9 changed files with 419 additions and 34 deletions
@ -1,3 +1,4 @@ |
|||
(lang dune 3.0) |
|||
|
|||
(using menhir 2.1) |
|||
(using mdx 0.2) |
|||
|
@ -0,0 +1,35 @@ |
|||
let a = const 42 in |
|||
let b = const 28 in |
|||
|
|||
let set = |
|||
make_closures |
|||
| cl_f { x } env -> |
|||
let aa = project_var v_a from env in |
|||
let cond = x == aa in |
|||
if cond then |
|||
let res = project_var v_a from env in res |
|||
else |
|||
let g = move_within_closures env cl_g in |
|||
g x |
|||
end |
|||
| cl_g { x } env -> |
|||
let f = move_within_closures env cl_f in |
|||
let one = const 1 in |
|||
let x = x - one in |
|||
f x |
|||
with vars |
|||
| v_a -> a |
|||
end |
|||
in |
|||
|
|||
let f = |
|||
project_closure cl_f from set |
|||
in |
|||
|
|||
let g = |
|||
project_closure cl_g from set |
|||
in |
|||
|
|||
let arg = f b in |
|||
|
|||
print_int arg |
@ -0,0 +1,105 @@ |
|||
open Sedlexing |
|||
open Menhir_parser |
|||
|
|||
exception Error of Lexing.position * string |
|||
|
|||
let blank = [%sedlex.regexp? ' ' | '\t'] |
|||
|
|||
let newline = [%sedlex.regexp? '\r' | '\n' | "\r\n"] |
|||
|
|||
let any_blank = [%sedlex.regexp? blank | newline] |
|||
|
|||
let sign = [%sedlex.regexp? '+' | '-'] |
|||
|
|||
let digit = [%sedlex.regexp? '0' .. '9'] |
|||
|
|||
let hexdigit = [%sedlex.regexp? digit | 'a' .. 'f' | 'A' .. 'F'] |
|||
|
|||
let num = [%sedlex.regexp? digit, Star (Opt '_', digit)] |
|||
|
|||
let hexnum = [%sedlex.regexp? hexdigit, Star (Opt '_', hexdigit)] |
|||
|
|||
let nat = [%sedlex.regexp? num | "0x", hexnum] |
|||
|
|||
let int = [%sedlex.regexp? sign, nat] |
|||
|
|||
let num = [%sedlex.regexp? int | nat] |
|||
|
|||
let id_char = [%sedlex.regexp? 'a' .. 'z' | '_'] |
|||
|
|||
let id = [%sedlex.regexp? Plus id_char] |
|||
|
|||
let err buf msg = |
|||
let position = fst @@ lexing_positions buf in |
|||
let tok = Utf8.lexeme buf in |
|||
raise @@ Error (position, Printf.sprintf "%s %S" msg tok) |
|||
|
|||
let rec token buf = |
|||
match%sedlex buf with |
|||
| Plus any_blank -> token buf |
|||
| num -> NUM (Utf8.lexeme buf) |
|||
| "|" -> BAR |
|||
| "==" -> DOUBLE_EQUAL |
|||
| "=" -> EQUAL |
|||
| "-" -> HYPHEN |
|||
| "<-" -> LEFT_ARROW |
|||
| "{" -> LEFT_BRACKET |
|||
| "->" -> RIGHT_ARROW |
|||
| "}" -> RIGHT_BRACKET |
|||
| ";" -> SEMI_COLON |
|||
| "catch" -> CATCH |
|||
| "const" -> CONST |
|||
| "do" -> DO |
|||
| "if" -> IF |
|||
| "in" -> IN |
|||
| "int" -> INT |
|||
| "else" -> ELSE |
|||
| "end" -> END |
|||
| "from" -> FROM |
|||
| "get_field" -> GET_FIELD |
|||
| "let" -> LET |
|||
| "make_block" -> MAKE_BLOCK |
|||
| "make_closures" -> MAKE_CLOSURES |
|||
| "move_within_closures" -> MOVE_WITHIN_CLOSURES |
|||
| "print_int" -> PRINT_INT |
|||
| "project_closure" -> PROJECT_CLOSURE |
|||
| "project_var" -> PROJECT_VAR |
|||
| "raise" -> RAISE |
|||
| "switch" -> SWITCH |
|||
| "tag" -> TAG |
|||
| "then" -> THEN |
|||
| "try" -> TRY |
|||
| "vars" -> VARS |
|||
| "while" -> WHILE |
|||
| "with" -> WITH |
|||
| "(*" -> |
|||
comment buf; |
|||
token buf |
|||
(* other *) |
|||
| id -> |
|||
let id = Utf8.lexeme buf in |
|||
ID id |
|||
| eof -> EOF |
|||
| _ -> |
|||
let position = fst @@ lexing_positions buf in |
|||
let tok = Utf8.lexeme buf in |
|||
raise @@ Error (position, Printf.sprintf "unexpected character `%S`" tok) |
|||
|
|||
and comment buf = |
|||
match%sedlex buf with |
|||
| "*)" -> () |
|||
| "(*" -> |
|||
comment buf; |
|||
comment buf |
|||
| eof -> Format.ksprintf failwith "eof in comment" |
|||
| any -> comment buf |
|||
| _ -> assert false |
|||
|
|||
and single_comment buf = |
|||
match%sedlex buf with |
|||
| newline -> () |
|||
| eof -> Format.ksprintf failwith "eof in single line comment" |
|||
| any -> single_comment buf |
|||
| _ -> assert false |
|||
|
|||
let lexer buf = Sedlexing.with_tokenizer token buf |
@ -0,0 +1,22 @@ |
|||
let () = |
|||
if Array.length Sys.argv <> 2 then |
|||
Format.ksprintf failwith "usage: %s <file>" Sys.argv.(0) |
|||
|
|||
let filename = Sys.argv.(1) |
|||
|
|||
let () = |
|||
if not @@ Sys.file_exists filename then |
|||
Format.ksprintf failwith "file %s doesn't exist" filename |
|||
|
|||
open Wasocaml_core |
|||
|
|||
let ast = |
|||
match Parse.from_file ~filename with |
|||
| Error msg -> failwith msg |
|||
| Ok ast -> ast |
|||
|
|||
let env = Interpret.Env.empty |
|||
|
|||
let _env, value = Interpret.eval_term env ast |
|||
|
|||
let () = Interpret.Value.print value |
@ -0,0 +1,68 @@ |
|||
%token <String.t> NUM |
|||
%token <String.t> ID |
|||
%token BAR DOUBLE_EQUAL EOF EQUAL HYPHEN LEFT_ARROW LEFT_BRACKET RIGHT_ARROW RIGHT_BRACKET SEMI_COLON |
|||
%token CATCH CONST DO IF IN INT ELSE END FROM GET_FIELD LET MAKE_BLOCK MAKE_CLOSURES MOVE_WITHIN_CLOSURES PRINT_INT PROJECT_CLOSURE PROJECT_VAR RAISE SWITCH TAG THEN TRY VARS WHILE WITH |
|||
|
|||
%{ |
|||
open Flambda_core_ast |
|||
%} |
|||
|
|||
%start <Flambda_core_ast.term> file |
|||
|
|||
%% |
|||
|
|||
(* Helpers *) |
|||
|
|||
(* |
|||
let par(X) == |
|||
| LPAR; ~ = X; RPAR; <> |
|||
*) |
|||
|
|||
(* Types *) |
|||
|
|||
let id == |
|||
| ~ = ID; <> |
|||
|
|||
let num == |
|||
| n = NUM; { int_of_string n } |
|||
|
|||
let int_case == |
|||
| BAR; INT; ~ = num; RIGHT_ARROW; ~ = term; <> |
|||
|
|||
let tag_case == |
|||
| BAR; TAG; ~ = num; RIGHT_ARROW; ~ = term; <> |
|||
|
|||
let term := |
|||
| ~ = id; <Variable> |
|||
| LET; ~ = id; EQUAL; ~ = named; IN; ~ = term; <Let> |
|||
| i1 = id; LEFT_ARROW; i2 = id; <Mutate> |
|||
| i1 = id; i2 = id; <Apply> |
|||
| IF; ~ = id; THEN; t1 = term; ELSE; t2 = term; END; <If_then_else> |
|||
| SWITCH; ~ = id; WITH; ~ = list(int_case); ~ = list(tag_case); END; <Switch> |
|||
| RAISE; ~ = id; ~ = list(id); SEMI_COLON; <Raise> |
|||
| TRY; t1 = term; CATCH; ~ = id; ~ = list(id); RIGHT_ARROW; t2 = term; END; <Try_catch> |
|||
| WHILE; t1 = term; DO; t2 = term; END; <While> |
|||
|
|||
let named == |
|||
| CONST; ~ = num; <Const> |
|||
| PRINT_INT; ~ = id; <Print_int> |
|||
| i1 = id; HYPHEN; i2 = id; <Sub> |
|||
| i1 = id; DOUBLE_EQUAL; i2 = id; <Physical_eq> |
|||
| GET_FIELD; ~ = num; ~ = id; <Get_field> |
|||
| MAKE_BLOCK; ~ = num; ~ = list(id); <Make_block> |
|||
| MAKE_CLOSURES; |
|||
(* TODO: can this be empty ? *) |
|||
~ = list(closures); |
|||
WITH; VARS; ~ = list(vars); END; <Make_closures> |
|||
| PROJECT_CLOSURE; i1 = id; FROM; i2 = id; <Project_closure> |
|||
| PROJECT_VAR; i1 = id; FROM; i2 = id; <Project_var> |
|||
| MOVE_WITHIN_CLOSURES; i1 = id; i2 = id; <Move_within_closure> |
|||
|
|||
let closures == |
|||
| BAR; i1 = id; LEFT_BRACKET; i2 = id; RIGHT_BRACKET; i3 = id; RIGHT_ARROW; ~ = term; <> |
|||
|
|||
let vars == |
|||
| BAR; i1 = id; RIGHT_ARROW; i2 = id; <> |
|||
|
|||
let file := |
|||
| ~ = term; EOF; <> |
@ -0,0 +1,46 @@ |
|||
let from_lexbuf = |
|||
let parser = |
|||
MenhirLib.Convert.Simplified.traditional2revised Menhir_parser.file |
|||
in |
|||
fun buf -> |
|||
let provider () = |
|||
let tok = Lexer.token buf in |
|||
let start, stop = Sedlexing.lexing_positions buf in |
|||
(tok, start, stop) |
|||
in |
|||
try Ok (parser provider) with |
|||
| Menhir_parser.Error -> |
|||
let start, _stop = Sedlexing.lexing_positions buf in |
|||
Format.ksprintf failwith "File %s, line %i, character %i: parse error" |
|||
start.pos_fname start.pos_lnum |
|||
(start.pos_cnum - start.pos_bol) |
|||
| Lexer.Error (pos, msg) -> |
|||
let file_line = |
|||
let cpos = pos.pos_cnum - pos.pos_bol in |
|||
Printf.sprintf "File \"%s\", line %i, character %i:" pos.pos_fname |
|||
pos.pos_lnum cpos |
|||
in |
|||
let msg = Printf.sprintf "Error: Lexing error %s" msg in |
|||
Format.ksprintf failwith "%s\n%s\n" file_line msg |
|||
| Failure msg -> |
|||
let msg = Printf.sprintf "Error: Lexing error %s" msg in |
|||
Format.ksprintf failwith "%s\n" msg |
|||
|
|||
(** Parse a script from a string. *) |
|||
let from_string s = from_lexbuf (Sedlexing.Utf8.from_string s) |
|||
|
|||
(** Parse a script from a channel. *) |
|||
let from_channel c = from_lexbuf (Sedlexing.Utf8.from_channel c) |
|||
|
|||
(** Parse a script from a file. *) |
|||
let from_file ~filename = |
|||
let chan = open_in filename in |
|||
let result = |
|||
Fun.protect |
|||
~finally:(fun () -> close_in chan) |
|||
(fun () -> |
|||
let lb = Sedlexing.Utf8.from_channel chan in |
|||
Sedlexing.set_filename lb filename; |
|||
from_lexbuf lb ) |
|||
in |
|||
result |
Loading…
Reference in new issue