diff --git a/lib/parser.ml b/lib/parser.ml index 51f6b64..993db83 100644 --- a/lib/parser.ml +++ b/lib/parser.ml @@ -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 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 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 = 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 [] + let rec parse_calls_rec expr = + 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 [| 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 - 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 - let* () = consume state RightParen in - make_call pos expr args |> Result.ok - else Ok expr + let* () = consume state RightParen in + let expr = make_call pos expr args in + parse_calls_rec expr + else Ok expr + in + parse_calls_rec expr and neg_not (state : state) : expr_result = if matches state [| Bang; Minus |] then @@ -336,21 +340,35 @@ and statement (state : state) : stmt_result = let pos = cur_pos state in match peek_tt state with | 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; let* () = consume state Semicolon in make_break pos |> Result.ok) - else - let msg = "Can use break only in loops" in - ParserError.make pos msg |> Result.error | 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; let* () = consume state Semicolon in make_continue pos |> Result.ok) - else - let msg = "Can use continue only in loops" in - ParserError.make pos msg |> Result.error + | Return -> + if not state.is_in_fun then ( + 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 -> advance state; let* expr = expression state in @@ -412,7 +430,7 @@ and declaration (state : state) : stmt_result = let rec synchronise (state : state) = match peek_tt state with | 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; synchronise state