fixed two bugs

calls are now parsed recursively, i.e. multiple in a row
is_in_fun is now false by default
This commit is contained in:
Moritz Gmeiner 2024-08-28 22:41:00 +02:00
commit 4496875ba3

View file

@ -10,7 +10,7 @@ type state = { tokens : token list ref; is_in_loop : bool; is_in_fun : bool }
type stmt_result = (stmt_node, parser_error) result type stmt_result = (stmt_node, parser_error) result
type expr_result = (expr_node, parser_error) result type expr_result = (expr_node, parser_error) result
let make_state tokens = { tokens; is_in_loop = false; is_in_fun = true } let make_state tokens = { tokens; is_in_loop = false; is_in_fun = false }
let with_is_in_loop (f : state -> 'a) (state : state) : 'a = let with_is_in_loop (f : state -> 'a) (state : state) : 'a =
let new_state = { state with is_in_loop = true } in let new_state = { state with is_in_loop = true } in
@ -120,23 +120,27 @@ let rec grouping (state : state) : expr_result =
and call (state : state) : expr_result = and call (state : state) : expr_result =
let* expr = grouping state in let* expr = grouping state in
let pos = cur_pos state in let pos = cur_pos state in
if advance_if state LeftParen then let rec parse_calls_rec expr =
let* args = if advance_if state LeftParen then
if peek_tt state = RightParen then Ok [] let* args =
if peek_tt state = RightParen then Ok []
else
let* first_arg = expression state in
let* exprs_tokens = collect_chain [| Comma |] expression state 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 else
let* first_arg = expression state in let* () = consume state RightParen in
let* exprs_tokens = collect_chain [| Comma |] expression state in let expr = make_call pos expr args in
let other_args = List.map fst exprs_tokens in parse_calls_rec expr
let args = first_arg :: other_args in else Ok expr
Ok args in
in parse_calls_rec expr
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 = and neg_not (state : state) : expr_result =
if matches state [| Bang; Minus |] then if matches state [| Bang; Minus |] then
@ -336,21 +340,35 @@ and statement (state : state) : stmt_result =
let pos = cur_pos state in let pos = cur_pos state in
match peek_tt state with match peek_tt state with
| Break -> | Break ->
if state.is_in_loop then ( if not state.is_in_loop then (
advance state;
let msg = "Can use break only in loops" in
ParserError.make pos msg |> Result.error)
else (
advance state; advance state;
let* () = consume state Semicolon in let* () = consume state Semicolon in
make_break pos |> Result.ok) make_break pos |> Result.ok)
else
let msg = "Can use break only in loops" in
ParserError.make pos msg |> Result.error
| Continue -> | Continue ->
if state.is_in_loop then ( if not state.is_in_loop then (
advance state;
let msg = "Can use continue only in loops" in
ParserError.make pos msg |> Result.error)
else (
advance state; advance state;
let* () = consume state Semicolon in let* () = consume state Semicolon in
make_continue pos |> Result.ok) make_continue pos |> Result.ok)
else | Return ->
let msg = "Can use continue only in loops" in if not state.is_in_fun then (
ParserError.make pos msg |> Result.error advance state;
let msg = "Can use return only in functions" in
ParserError.make pos msg |> Result.error)
else (
advance state;
let* expr =
if peek_tt state = Semicolon then make_nil pos |> Result.ok else expression state
in
let* () = consume state Semicolon in
make_return pos expr |> Result.ok)
| Print -> | Print ->
advance state; advance state;
let* expr = expression state in let* expr = expression state in
@ -412,7 +430,7 @@ and declaration (state : state) : stmt_result =
let rec synchronise (state : state) = let rec synchronise (state : state) =
match peek_tt state with match peek_tt state with
| Semicolon -> advance state | Semicolon -> advance state
| Class | Fun | Var | For | If | While | Print | Return | Eof -> () | Break | Class | Continue | Fun | Var | For | If | While | Print | Return | Eof -> ()
| _ -> | _ ->
advance state; advance state;
synchronise state synchronise state