mirror of
https://github.com/MorizzG/MLox.git
synced 2025-12-06 04:22:41 +00:00
implemented calls
This commit is contained in:
parent
8d445cc9e4
commit
be931b7214
6 changed files with 115 additions and 55 deletions
|
|
@ -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 =
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue