mirror of
https://github.com/MorizzG/MLox.git
synced 2025-12-06 04:22:41 +00:00
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:
parent
e1a8717d21
commit
4496875ba3
1 changed files with 44 additions and 26 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue