blob: dab48e045342135fe1908547c8f16a7778472f43 [file]
{
open Parser
open Operators
let convert_pos pos =
{ Source.file = pos.Lexing.pos_fname;
Source.line = pos.Lexing.pos_lnum;
Source.column = pos.Lexing.pos_cnum - pos.Lexing.pos_bol
}
let region lexbuf =
let left = convert_pos (Lexing.lexeme_start_p lexbuf) in
let right = convert_pos (Lexing.lexeme_end_p lexbuf) in
{Source.left = left; Source.right = right}
let error lexbuf msg = raise (Script.Syntax (region lexbuf, msg))
let error_nest start lexbuf msg =
lexbuf.Lexing.lex_start_p <- start;
error lexbuf msg
let string s =
let b = Buffer.create (String.length s) in
let i = ref 1 in
while !i < String.length s - 1 do
let c = if s.[!i] <> '\\' then s.[!i] else
match (incr i; s.[!i]) with
| 'n' -> '\n'
| 'r' -> '\r'
| 't' -> '\t'
| '\\' -> '\\'
| '\'' -> '\''
| '\"' -> '\"'
| 'u' ->
let j = !i + 2 in
i := String.index_from s j '}';
let n = int_of_string ("0x" ^ String.sub s j (!i - j)) in
let bs = Utf8.encode [n] in
Buffer.add_substring b bs 0 (String.length bs - 1);
bs.[String.length bs - 1]
| h ->
incr i;
Char.chr (int_of_string ("0x" ^ String.make 1 h ^ String.make 1 s.[!i]))
in Buffer.add_char b c;
incr i
done;
Buffer.contents b
let value_type = function
| "i32" -> Types.I32Type
| "i64" -> Types.I64Type
| "f32" -> Types.F32Type
| "f64" -> Types.F64Type
| _ -> assert false
let intop t i32 i64 =
match t with
| "i32" -> i32
| "i64" -> i64
| _ -> assert false
let floatop t f32 f64 =
match t with
| "f32" -> f32
| "f64" -> f64
| _ -> assert false
let numop t i32 i64 f32 f64 =
match t with
| "i32" -> i32
| "i64" -> i64
| "f32" -> f32
| "f64" -> f64
| _ -> assert false
let memsz sz m8 m16 m32 =
match sz with
| "8" -> m8
| "16" -> m16
| "32" -> m32
| _ -> assert false
let ext e s u =
match e with
| 's' -> s
| 'u' -> u
| _ -> assert false
let opt = Lib.Option.get
}
let sign = '+' | '-'
let digit = ['0'-'9']
let hexdigit = ['0'-'9''a'-'f''A'-'F']
let num = digit ('_'? digit)*
let hexnum = hexdigit ('_'? hexdigit)*
let letter = ['a'-'z''A'-'Z']
let symbol =
['+''-''*''/''\\''^''~''=''<''>''!''?''@''#''$''%''&''|'':''`''.''\'']
let space = [' ''\t''\n''\r']
let ascii = ['\x00'-'\x7f']
let ascii_no_nl = ['\x00'-'\x09''\x0b'-'\x7f']
let utf8cont = ['\x80'-'\xbf']
let utf8enc =
['\xc2'-'\xdf'] utf8cont
| ['\xe0'] ['\xa0'-'\xbf'] utf8cont
| ['\xed'] ['\x80'-'\x9f'] utf8cont
| ['\xe1'-'\xec''\xee'-'\xef'] utf8cont utf8cont
| ['\xf0'] ['\x90'-'\xbf'] utf8cont utf8cont
| ['\xf4'] ['\x80'-'\x8f'] utf8cont utf8cont
| ['\xf1'-'\xf3'] utf8cont utf8cont utf8cont
let utf8 = ascii | utf8enc
let utf8_no_nl = ascii_no_nl | utf8enc
let escape = ['n''r''t''\\''\'''\"']
let character =
[^'"''\\''\x00'-'\x1f''\x7f'-'\xff']
| utf8enc
| '\\'escape
| '\\'hexdigit hexdigit
| "\\u{" hexnum '}'
let nat = num | "0x" hexnum
let int = sign nat
let frac = num
let hexfrac = hexnum
let float =
sign? num '.' frac?
| sign? num ('.' frac?)? ('e' | 'E') sign? num
| sign? "0x" hexnum '.' hexfrac?
| sign? "0x" hexnum ('.' hexfrac?)? ('p' | 'P') sign? num
| sign? "inf"
| sign? "nan"
| sign? "nan:" "0x" hexnum
let string = '"' character* '"'
let name = '$' (letter | digit | '_' | symbol)+
let reserved = ([^'\"''('')'';'] # space)+ (* hack for table size *)
let ixx = "i" ("32" | "64")
let fxx = "f" ("32" | "64")
let nxx = ixx | fxx
let mixx = "i" ("8" | "16" | "32" | "64")
let mfxx = "f" ("32" | "64")
let sign = "s" | "u"
let mem_size = "8" | "16" | "32"
rule token = parse
| "(" { LPAR }
| ")" { RPAR }
| nat as s { NAT s }
| int as s { INT s }
| float as s { FLOAT s }
| string as s { STRING (string s) }
| '"'character*('\n'|eof) { error lexbuf "unclosed string literal" }
| '"'character*['\x00'-'\x09''\x0b'-'\x1f''\x7f']
{ error lexbuf "illegal control character in string literal" }
| '"'character*'\\'_
{ error_nest (Lexing.lexeme_end_p lexbuf) lexbuf "illegal escape" }
| (nxx as t) { VALUE_TYPE (value_type t) }
| (nxx as t)".const"
{ let open Source in
CONST (numop t
(fun s -> let n = I32.of_string s.it in
i32_const (n @@ s.at), Values.I32 n)
(fun s -> let n = I64.of_string s.it in
i64_const (n @@ s.at), Values.I64 n)
(fun s -> let n = F32.of_string s.it in
f32_const (n @@ s.at), Values.F32 n)
(fun s -> let n = F64.of_string s.it in
f64_const (n @@ s.at), Values.F64 n))
}
| "funcref" { FUNCREF }
| "mut" { MUT }
| "nop" { NOP }
| "unreachable" { UNREACHABLE }
| "drop" { DROP }
| "block" { BLOCK }
| "loop" { LOOP }
| "end" { END }
| "br" { BR }
| "br_if" { BR_IF }
| "br_table" { BR_TABLE }
| "return" { RETURN }
| "if" { IF }
| "then" { THEN }
| "else" { ELSE }
| "select" { SELECT }
| "call" { CALL }
| "call_indirect" { CALL_INDIRECT }
| "local.get" { LOCAL_GET }
| "local.set" { LOCAL_SET }
| "local.tee" { LOCAL_TEE }
| "global.get" { GLOBAL_GET }
| "global.set" { GLOBAL_SET }
| (nxx as t)".load"
{ LOAD (fun a o ->
numop t (i32_load (opt a 2)) (i64_load (opt a 3))
(f32_load (opt a 2)) (f64_load (opt a 3)) o) }
| (nxx as t)".store"
{ STORE (fun a o ->
numop t (i32_store (opt a 2)) (i64_store (opt a 3))
(f32_store (opt a 2)) (f64_store (opt a 3)) o) }
| (ixx as t)".load"(mem_size as sz)"_"(sign as s)
{ if t = "i32" && sz = "32" then error lexbuf "unknown operator";
LOAD (fun a o ->
intop t
(memsz sz
(ext s i32_load8_s i32_load8_u (opt a 0))
(ext s i32_load16_s i32_load16_u (opt a 1))
(fun _ -> unreachable) o)
(memsz sz
(ext s i64_load8_s i64_load8_u (opt a 0))
(ext s i64_load16_s i64_load16_u (opt a 1))
(ext s i64_load32_s i64_load32_u (opt a 2)) o)) }
| (ixx as t)".store"(mem_size as sz)
{ if t = "i32" && sz = "32" then error lexbuf "unknown operator";
STORE (fun a o ->
intop t
(memsz sz
(i32_store8 (opt a 0))
(i32_store16 (opt a 1))
(fun _ -> unreachable) o)
(memsz sz
(i64_store8 (opt a 0))
(i64_store16 (opt a 1))
(i64_store32 (opt a 2)) o)) }
| "offset="(nat as s) { OFFSET_EQ_NAT s }
| "align="(nat as s) { ALIGN_EQ_NAT s }
| (ixx as t)".clz" { UNARY (intop t i32_clz i64_clz) }
| (ixx as t)".ctz" { UNARY (intop t i32_ctz i64_ctz) }
| (ixx as t)".popcnt" { UNARY (intop t i32_popcnt i64_popcnt) }
| (fxx as t)".neg" { UNARY (floatop t f32_neg f64_neg) }
| (fxx as t)".abs" { UNARY (floatop t f32_abs f64_abs) }
| (fxx as t)".sqrt" { UNARY (floatop t f32_sqrt f64_sqrt) }
| (fxx as t)".ceil" { UNARY (floatop t f32_ceil f64_ceil) }
| (fxx as t)".floor" { UNARY (floatop t f32_floor f64_floor) }
| (fxx as t)".trunc" { UNARY (floatop t f32_trunc f64_trunc) }
| (fxx as t)".nearest" { UNARY (floatop t f32_nearest f64_nearest) }
| (ixx as t)".add" { BINARY (intop t i32_add i64_add) }
| (ixx as t)".sub" { BINARY (intop t i32_sub i64_sub) }
| (ixx as t)".mul" { BINARY (intop t i32_mul i64_mul) }
| (ixx as t)".div_s" { BINARY (intop t i32_div_s i64_div_s) }
| (ixx as t)".div_u" { BINARY (intop t i32_div_u i64_div_u) }
| (ixx as t)".rem_s" { BINARY (intop t i32_rem_s i64_rem_s) }
| (ixx as t)".rem_u" { BINARY (intop t i32_rem_u i64_rem_u) }
| (ixx as t)".and" { BINARY (intop t i32_and i64_and) }
| (ixx as t)".or" { BINARY (intop t i32_or i64_or) }
| (ixx as t)".xor" { BINARY (intop t i32_xor i64_xor) }
| (ixx as t)".shl" { BINARY (intop t i32_shl i64_shl) }
| (ixx as t)".shr_s" { BINARY (intop t i32_shr_s i64_shr_s) }
| (ixx as t)".shr_u" { BINARY (intop t i32_shr_u i64_shr_u) }
| (ixx as t)".rotl" { BINARY (intop t i32_rotl i64_rotl) }
| (ixx as t)".rotr" { BINARY (intop t i32_rotr i64_rotr) }
| (fxx as t)".add" { BINARY (floatop t f32_add f64_add) }
| (fxx as t)".sub" { BINARY (floatop t f32_sub f64_sub) }
| (fxx as t)".mul" { BINARY (floatop t f32_mul f64_mul) }
| (fxx as t)".div" { BINARY (floatop t f32_div f64_div) }
| (fxx as t)".min" { BINARY (floatop t f32_min f64_min) }
| (fxx as t)".max" { BINARY (floatop t f32_max f64_max) }
| (fxx as t)".copysign" { BINARY (floatop t f32_copysign f64_copysign) }
| (ixx as t)".eqz" { TEST (intop t i32_eqz i64_eqz) }
| (ixx as t)".eq" { COMPARE (intop t i32_eq i64_eq) }
| (ixx as t)".ne" { COMPARE (intop t i32_ne i64_ne) }
| (ixx as t)".lt_s" { COMPARE (intop t i32_lt_s i64_lt_s) }
| (ixx as t)".lt_u" { COMPARE (intop t i32_lt_u i64_lt_u) }
| (ixx as t)".le_s" { COMPARE (intop t i32_le_s i64_le_s) }
| (ixx as t)".le_u" { COMPARE (intop t i32_le_u i64_le_u) }
| (ixx as t)".gt_s" { COMPARE (intop t i32_gt_s i64_gt_s) }
| (ixx as t)".gt_u" { COMPARE (intop t i32_gt_u i64_gt_u) }
| (ixx as t)".ge_s" { COMPARE (intop t i32_ge_s i64_ge_s) }
| (ixx as t)".ge_u" { COMPARE (intop t i32_ge_u i64_ge_u) }
| (fxx as t)".eq" { COMPARE (floatop t f32_eq f64_eq) }
| (fxx as t)".ne" { COMPARE (floatop t f32_ne f64_ne) }
| (fxx as t)".lt" { COMPARE (floatop t f32_lt f64_lt) }
| (fxx as t)".le" { COMPARE (floatop t f32_le f64_le) }
| (fxx as t)".gt" { COMPARE (floatop t f32_gt f64_gt) }
| (fxx as t)".ge" { COMPARE (floatop t f32_ge f64_ge) }
| "i32.wrap_i64" { CONVERT i32_wrap_i64 }
| "i64.extend_i32_s" { CONVERT i64_extend_i32_s }
| "i64.extend_i32_u" { CONVERT i64_extend_i32_u }
| "f32.demote_f64" { CONVERT f32_demote_f64 }
| "f64.promote_f32" { CONVERT f64_promote_f32 }
| (ixx as t)".trunc_f32_s"
{ CONVERT (intop t i32_trunc_f32_s i64_trunc_f32_s) }
| (ixx as t)".trunc_f32_u"
{ CONVERT (intop t i32_trunc_f32_u i64_trunc_f32_u) }
| (ixx as t)".trunc_f64_s"
{ CONVERT (intop t i32_trunc_f64_s i64_trunc_f64_s) }
| (ixx as t)".trunc_f64_u"
{ CONVERT (intop t i32_trunc_f64_u i64_trunc_f64_u) }
| (fxx as t)".convert_i32_s"
{ CONVERT (floatop t f32_convert_i32_s f64_convert_i32_s) }
| (fxx as t)".convert_i32_u"
{ CONVERT (floatop t f32_convert_i32_u f64_convert_i32_u) }
| (fxx as t)".convert_i64_s"
{ CONVERT (floatop t f32_convert_i64_s f64_convert_i64_s) }
| (fxx as t)".convert_i64_u"
{ CONVERT (floatop t f32_convert_i64_u f64_convert_i64_u) }
| "f32.reinterpret_i32" { CONVERT f32_reinterpret_i32 }
| "f64.reinterpret_i64" { CONVERT f64_reinterpret_i64 }
| "i32.reinterpret_f32" { CONVERT i32_reinterpret_f32 }
| "i64.reinterpret_f64" { CONVERT i64_reinterpret_f64 }
| "memory.size" { MEMORY_SIZE }
| "memory.grow" { MEMORY_GROW }
| "type" { TYPE }
| "func" { FUNC }
| "start" { START }
| "param" { PARAM }
| "result" { RESULT }
| "local" { LOCAL }
| "global" { GLOBAL }
| "table" { TABLE }
| "memory" { MEMORY }
| "elem" { ELEM }
| "data" { DATA }
| "offset" { OFFSET }
| "import" { IMPORT }
| "export" { EXPORT }
| "module" { MODULE }
| "binary" { BIN }
| "quote" { QUOTE }
| "script" { SCRIPT }
| "register" { REGISTER }
| "invoke" { INVOKE }
| "get" { GET }
| "assert_malformed" { ASSERT_MALFORMED }
| "assert_invalid" { ASSERT_INVALID }
| "assert_unlinkable" { ASSERT_UNLINKABLE }
| "assert_return" { ASSERT_RETURN }
| "assert_return_canonical_nan" { ASSERT_RETURN_CANONICAL_NAN }
| "assert_return_arithmetic_nan" { ASSERT_RETURN_ARITHMETIC_NAN }
| "assert_trap" { ASSERT_TRAP }
| "assert_exhaustion" { ASSERT_EXHAUSTION }
| "input" { INPUT }
| "output" { OUTPUT }
| name as s { VAR s }
| ";;"utf8_no_nl*eof { EOF }
| ";;"utf8_no_nl*'\n' { Lexing.new_line lexbuf; token lexbuf }
| ";;"utf8_no_nl* { token lexbuf (* causes error on following position *) }
| "(;" { comment (Lexing.lexeme_start_p lexbuf) lexbuf; token lexbuf }
| space#'\n' { token lexbuf }
| '\n' { Lexing.new_line lexbuf; token lexbuf }
| eof { EOF }
| reserved { error lexbuf "unknown operator" }
| utf8 { error lexbuf "malformed operator" }
| _ { error lexbuf "malformed UTF-8 encoding" }
and comment start = parse
| ";)" { () }
| "(;" { comment (Lexing.lexeme_start_p lexbuf) lexbuf; comment start lexbuf }
| '\n' { Lexing.new_line lexbuf; comment start lexbuf }
| eof { error_nest start lexbuf "unclosed comment" }
| utf8 { comment start lexbuf }
| _ { error lexbuf "malformed UTF-8 encoding" }