mirror of
https://github.com/MorizzG/MLox.git
synced 2025-12-06 04:22:41 +00:00
global and local variables with scope
also reworked arg parsing, now has --debug flag
This commit is contained in:
parent
222de81a19
commit
77e57cd8c2
8 changed files with 341 additions and 95 deletions
127
lib/parser.ml
127
lib/parser.ml
|
|
@ -10,11 +10,11 @@ type stmt_result = (stmt_node, parser_error) result
|
|||
type expr_result = (expr_node, parser_error) result
|
||||
type state = { tokens : token list }
|
||||
|
||||
let is_at_end state = (List.hd !state.tokens).token_type == Eof
|
||||
let is_at_end state = (List.hd !state.tokens).token_type = Eof
|
||||
let advance state = state := { tokens = List.tl !state.tokens }
|
||||
|
||||
let next state =
|
||||
assert (not ((List.hd !state.tokens).token_type == Eof));
|
||||
assert (not ((List.hd !state.tokens).token_type = Eof));
|
||||
let token = List.hd !state.tokens in
|
||||
advance state;
|
||||
token
|
||||
|
|
@ -24,7 +24,7 @@ let peek_tt (state : state ref) : token_type = (peek state).token_type
|
|||
let cur_pos state = (peek state).pos
|
||||
|
||||
let advance_if state tt =
|
||||
if peek_tt state == tt then (
|
||||
if peek_tt state = tt then (
|
||||
advance state;
|
||||
true)
|
||||
else false
|
||||
|
|
@ -32,13 +32,23 @@ let advance_if state tt =
|
|||
let consume state tt =
|
||||
if advance_if state tt then Ok ()
|
||||
else
|
||||
Error
|
||||
(ParserError.make (cur_pos state)
|
||||
(Printf.sprintf "Expected %s, but got %s" (show_token_type tt)
|
||||
(show_token_type (peek_tt state))))
|
||||
let pos = cur_pos state in
|
||||
let tt' = peek_tt state in
|
||||
let msg = Printf.sprintf "Expected %s, but got %s" (show_token_type tt) (show_token_type tt') in
|
||||
Error (ParserError.make pos msg)
|
||||
|
||||
let consume_identifier state =
|
||||
match peek_tt state with
|
||||
| Identifier name ->
|
||||
advance state;
|
||||
Ok name
|
||||
| tt ->
|
||||
let pos = cur_pos state in
|
||||
let msg = Printf.sprintf "Expected iedntifier, but got %s" (show_token_type tt) in
|
||||
Error (ParserError.make pos msg)
|
||||
|
||||
let matches state tts =
|
||||
let f = ( == ) (peek_tt state) in
|
||||
let f = ( = ) (peek_tt state) in
|
||||
Array.fold_left (fun acc tt -> acc || f tt) false tts
|
||||
|
||||
let collect_chain (state : state ref) (tts : token_type array)
|
||||
|
|
@ -71,9 +81,12 @@ let primary (state : state ref) : expr_result =
|
|||
| Nil ->
|
||||
advance state;
|
||||
Ok (make_nil pos)
|
||||
| Identifier name ->
|
||||
advance state;
|
||||
Ok (make_variable pos name)
|
||||
| tt ->
|
||||
let msg = Printf.sprintf "Unexpected %s, expected valid expression" (show_token_type tt) in
|
||||
let pos = (peek state).pos in
|
||||
advance state;
|
||||
let msg = Printf.sprintf "Expected valid expression, got %s instead" (show_token_type tt) in
|
||||
Error { msg; pos }
|
||||
|
||||
let rec grouping (state : state ref) : expr_result =
|
||||
|
|
@ -171,9 +184,40 @@ and equality (state : state ref) : expr_result =
|
|||
let expr = Array.fold_left f expr exprs_tokens in
|
||||
Ok expr
|
||||
|
||||
and expression (state : state ref) : expr_result = equality state
|
||||
and assignment (state : state ref) : expr_result =
|
||||
let* expr = equality state in
|
||||
if Equal = peek_tt state then
|
||||
let pos = (next state).pos in
|
||||
let* rhs = assignment state in
|
||||
match expr.expr with
|
||||
| Variable name -> Ok (make_assignment pos name rhs)
|
||||
| _ ->
|
||||
let msg = "Invalid assignment target" in
|
||||
Error (ParserError.make pos msg)
|
||||
else Ok expr
|
||||
|
||||
let statement (state : state ref) : stmt_result =
|
||||
and expression (state : state ref) : expr_result = assignment state
|
||||
|
||||
let rec block (state : state ref) : stmt_result =
|
||||
let pos = cur_pos state in
|
||||
let* _ = consume state LeftBrace in
|
||||
let rec collect_stmts state =
|
||||
if is_at_end state then
|
||||
let msg = "Unterminated block" in
|
||||
Error (ParserError.make pos msg)
|
||||
else
|
||||
match peek_tt state with
|
||||
| RightBrace -> Ok []
|
||||
| _ ->
|
||||
let* stmt = declaration state in
|
||||
let* tail = collect_stmts state in
|
||||
Ok (stmt :: tail)
|
||||
in
|
||||
let* stmts = collect_stmts state in
|
||||
let* _ = consume state RightBrace in
|
||||
Ok (make_block pos stmts)
|
||||
|
||||
and statement (state : state ref) : stmt_result =
|
||||
let pos = cur_pos state in
|
||||
match peek_tt state with
|
||||
| Print ->
|
||||
|
|
@ -182,12 +226,32 @@ let statement (state : state ref) : stmt_result =
|
|||
let* _ = consume state Semicolon in
|
||||
let stmt = make_print pos expr in
|
||||
Ok stmt
|
||||
| tt ->
|
||||
advance state;
|
||||
let msg =
|
||||
Printf.sprintf "Statement stating with %s not yet implemented" (show_token_type tt)
|
||||
in
|
||||
Error (ParserError.make pos msg)
|
||||
| LeftBrace -> block state
|
||||
| _ ->
|
||||
let* expr = expression state in
|
||||
let* _ = consume state Semicolon in
|
||||
let stmt = make_expr_stmt pos expr in
|
||||
Ok stmt
|
||||
|
||||
and var_declaration (state : state ref) : stmt_result =
|
||||
let pos = cur_pos state in
|
||||
(* consume var token *)
|
||||
assert ((next state).token_type = Var);
|
||||
let* name = consume_identifier state in
|
||||
let* init =
|
||||
if Equal = peek_tt state then
|
||||
(* found =, parsing initialiser *)
|
||||
let* _ = consume state Equal in
|
||||
let* init = expression state in
|
||||
Ok (Some init)
|
||||
else (* no initialiser, default to nil *)
|
||||
Ok None
|
||||
in
|
||||
let* _ = consume state Semicolon in
|
||||
Ok (make_var_decl pos name init)
|
||||
|
||||
and declaration (state : state ref) : stmt_result =
|
||||
match peek_tt state with Var -> var_declaration state | _ -> statement state
|
||||
|
||||
let rec synchronise (state : state ref) =
|
||||
match peek_tt state with
|
||||
|
|
@ -198,19 +262,20 @@ let rec synchronise (state : state ref) =
|
|||
synchronise state
|
||||
|
||||
let rec parse_impl (state : state ref) : parse_result =
|
||||
let result = statement state in
|
||||
match result with
|
||||
| Ok stmt when peek_tt state == Eof -> Ok [ stmt ]
|
||||
| Ok stmt ->
|
||||
print_endline (show_stmt stmt.stmt);
|
||||
let* stmts = parse_impl state in
|
||||
Ok (stmt :: stmts)
|
||||
| Error e -> (
|
||||
synchronise state;
|
||||
if peek_tt state == Eof then Error [ e ]
|
||||
else
|
||||
let tail_result = parse_impl state in
|
||||
match tail_result with Ok _ -> Error [ e ] | Error es -> Error (e :: es))
|
||||
if peek_tt state = Eof then Ok []
|
||||
else
|
||||
let result = declaration state in
|
||||
match result with
|
||||
| Ok stmt ->
|
||||
let* stmts = parse_impl state in
|
||||
Ok (stmt :: stmts)
|
||||
| Error e -> (
|
||||
print_endline e.msg;
|
||||
synchronise state;
|
||||
if peek_tt state = Eof then Error [ e ]
|
||||
else
|
||||
let tail_result = parse_impl state in
|
||||
match tail_result with Ok _ -> Error [ e ] | Error es -> Error (e :: es))
|
||||
|
||||
let parse (tokens : token list) : parse_result =
|
||||
(* filter out all the comment tokens *)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue