implemented calls

This commit is contained in:
Moritz Gmeiner 2024-08-27 20:32:05 +02:00
commit be931b7214
6 changed files with 115 additions and 55 deletions

View file

@ -10,14 +10,14 @@ type state = { tokens : token list ref; is_in_loop : bool }
type stmt_result = (stmt_node, parser_error) result
type expr_result = (expr_node, parser_error) result
let make_state tokens = { tokens; is_in_loop = false }
let with_is_in_loop (f : state -> 'a) (state : state) : 'a =
let new_state = { state with is_in_loop = true } in
let result = f new_state in
(* state.tokens <- new_state.tokens; *)
result
let make_state tokens = { tokens; is_in_loop = false }
let is_at_end state =
assert (not (List.is_empty !(state.tokens)));
(List.hd !(state.tokens)).token_type = Eof
@ -40,7 +40,7 @@ let advance_if state tt =
else false
let consume state tt =
if advance_if state tt then Ok state
if advance_if state tt then Ok ()
else
let pos = cur_pos state in
let tt' = peek_tt state in
@ -111,6 +111,27 @@ let rec grouping (state : state) : expr_result =
Error { pos; msg })
else primary state
and call (state : state) : expr_result =
let* expr = grouping state in
let pos = cur_pos state in
if advance_if state LeftParen then
let* args =
if peek_tt state = RightParen then Ok []
else
let* first_arg = expression state in
let* exprs_tokens = collect_chain state [| Comma |] expression in
let other_args = List.map fst exprs_tokens in
let args = first_arg :: other_args in
Ok args
in
if List.length args >= 255 then
let msg = "Can't call with more than 255 arguments" in
ParserError.make pos msg |> Result.error
else
let* () = consume state RightParen in
make_call pos expr args |> Result.ok
else Ok expr
and neg_not (state : state) : expr_result =
if matches state [| Bang; Minus |] then
let token = next state in
@ -124,7 +145,7 @@ and neg_not (state : state) : expr_result =
in
let expr = make_unary pos op expr in
Ok expr
else grouping state
else call state
and mul_or_div (state : state) : expr_result =
let* expr = neg_not state in
@ -232,7 +253,7 @@ and expression (state : state) : expr_result = assignment state
let rec block (state : state) : stmt_result =
let pos = cur_pos state in
let* _ = consume state LeftBrace in
let* () = consume state LeftBrace in
let rec collect_stmts state =
if is_at_end state then
let msg = "Unterminated block" in
@ -246,15 +267,15 @@ let rec block (state : state) : stmt_result =
Ok (stmt :: tail)
in
let* stmts = collect_stmts state in
let* _ = consume state RightBrace in
let* () = consume state RightBrace in
make_block pos stmts |> Result.ok
and if_then_else (state : state) : stmt_result =
let pos = cur_pos state in
let* _ = consume state If in
let* _ = consume state LeftParen in
let* () = consume state If in
let* () = consume state LeftParen in
let* cond = expression state in
let* _ = consume state RightParen in
let* () = consume state RightParen in
let* then_ = statement state in
let* (else_ : stmt_node option) =
if advance_if state Else then statement state |> Result.map Option.some else Ok None
@ -263,17 +284,17 @@ and if_then_else (state : state) : stmt_result =
and while_loop (state : state) : stmt_result =
let pos = cur_pos state in
let* _ = consume state While in
let* _ = consume state LeftParen in
let* () = consume state While in
let* () = consume state LeftParen in
let* cond = expression state in
let* _ = consume state RightParen in
let* () = consume state RightParen in
let* body = with_is_in_loop statement state in
make_while pos cond body |> Result.ok
and for_loop (state : state) : stmt_result =
let pos = cur_pos state in
let* _ = consume state For in
let* _ = consume state LeftParen in
let* () = consume state For in
let* () = consume state LeftParen in
let* init =
match peek_tt state with
| Semicolon ->
@ -288,20 +309,20 @@ and for_loop (state : state) : stmt_result =
| _ -> expression state |> Result.map Option.some
in
(* expression has no final semicolon, so we need to consume it *)
let* _ = consume state Semicolon in
let* () = consume state Semicolon in
let* update =
match peek_tt state with
| RightParen -> Ok None
| _ -> expression state |> Result.map Option.some
in
let* _ = consume state RightParen in
let* () = consume state RightParen in
let* body = with_is_in_loop statement state in
make_for pos init cond update body |> Result.ok
and expr_stmt (state : state) : stmt_result =
let pos = cur_pos state in
let* expr = expression state in
let* _ = consume state Semicolon in
let* () = consume state Semicolon in
let stmt = make_expr_stmt pos expr in
Ok stmt
@ -311,7 +332,7 @@ and statement (state : state) : stmt_result =
| Break ->
if state.is_in_loop then (
advance state;
let* _ = consume state Semicolon in
let* () = consume state Semicolon in
make_break pos |> Result.ok)
else
let msg = "Can use break only in loops" in
@ -319,7 +340,7 @@ and statement (state : state) : stmt_result =
| Continue ->
if state.is_in_loop then (
advance state;
let* _ = consume state Semicolon in
let* () = consume state Semicolon in
make_continue pos |> Result.ok)
else
let msg = "Can use continue only in loops" in
@ -327,7 +348,7 @@ and statement (state : state) : stmt_result =
| Print ->
advance state;
let* expr = expression state in
let* _ = consume state Semicolon in
let* () = consume state Semicolon in
let stmt = make_print pos expr in
Ok stmt
| LeftBrace -> block state
@ -344,13 +365,13 @@ and var_declaration (state : state) : stmt_result =
let* init =
if Equal = peek_tt state then
(* found =, parsing initialiser *)
let* _ = consume state Equal in
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
let* () = consume state Semicolon in
make_var_decl pos name init |> Result.ok
and declaration (state : state) : stmt_result =