global and local variables with scope

also reworked arg parsing, now has --debug flag
This commit is contained in:
Moritz Gmeiner 2024-08-26 01:58:03 +02:00
commit 77e57cd8c2
8 changed files with 341 additions and 95 deletions

View file

@ -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 *)