added If, And, Or

This commit is contained in:
Moritz Gmeiner 2024-08-26 17:26:59 +02:00
commit dbcdbc216f
5 changed files with 120 additions and 58 deletions

View file

@ -35,7 +35,7 @@ let consume state tt =
let pos = cur_pos state in
let tt' = peek_tt state in
let msg = Printf.sprintf "Expected %s, but got %s" (show_token_type tt) (show_token_type tt') in
Error (ParserError.make pos msg)
ParserError.make pos msg |> Result.error
let consume_identifier state =
match peek_tt state with
@ -44,15 +44,15 @@ let consume_identifier state =
Ok name
| tt ->
let pos = cur_pos state in
let msg = Printf.sprintf "Expected iedntifier, but got %s" (show_token_type tt) in
Error (ParserError.make pos msg)
let msg = Printf.sprintf "Expected identifier, but got %s" (show_token_type tt) in
ParserError.make pos msg |> Result.error
let matches state tts =
let f = ( = ) (peek_tt state) in
Array.fold_left (fun acc tt -> acc || f tt) false tts
let collect_chain (state : state ref) (tts : token_type array)
(higher_prec : state ref -> expr_result) : ((expr_node * token) array, parser_error) result =
(higher_prec : state ref -> expr_result) : ((expr_node * token) list, parser_error) result =
let rec collect_chain_rec (acc : (expr_node * token) list) =
if (not (is_at_end state)) && matches state tts then
let token = next state in
@ -61,29 +61,29 @@ let collect_chain (state : state ref) (tts : token_type array)
collect_chain_rec acc
else Ok acc
in
collect_chain_rec [] |> Result.map (fun l -> Array.of_list (List.rev l))
collect_chain_rec [] |> Result.map (fun l -> List.rev l)
let primary (state : state ref) : expr_result =
let pos = cur_pos state in
match peek_tt state with
| Number x ->
advance state;
Ok (make_number pos x)
make_number pos x |> Result.ok
| String s ->
advance state;
Ok (make_string pos s)
make_string pos s |> Result.ok
| True ->
advance state;
Ok (make_bool pos true)
make_bool pos true |> Result.ok
| False ->
advance state;
Ok (make_bool pos false)
make_bool pos false |> Result.ok
| Nil ->
advance state;
Ok (make_nil pos)
make_nil pos |> Result.ok
| Identifier name ->
advance state;
Ok (make_variable pos name)
make_variable pos name |> Result.ok
| tt ->
advance state;
let msg = Printf.sprintf "Expected valid expression, got %s instead" (show_token_type tt) in
@ -129,7 +129,7 @@ and mul_or_div (state : state ref) : expr_result =
in
make_binary pos op acc expr
in
let expr = Array.fold_left f expr exprs_tokens in
let expr = List.fold_left f expr exprs_tokens in
Ok expr
and sum_or_diff (state : state ref) : expr_result =
@ -145,7 +145,7 @@ and sum_or_diff (state : state ref) : expr_result =
in
make_binary pos op acc expr
in
let expr = Array.fold_left f expr exprs_tokens in
let expr = List.fold_left f expr exprs_tokens in
Ok expr
and inequality (state : state ref) : expr_result =
@ -166,7 +166,7 @@ and inequality (state : state ref) : expr_result =
in
make_binary pos op acc expr
in
let expr = Array.fold_left f expr exprs_tokens in
let expr = List.fold_left f expr exprs_tokens in
Ok expr
and equality (state : state ref) : expr_result =
@ -181,19 +181,41 @@ and equality (state : state ref) : expr_result =
make_unary pos Not expr
| _ -> assert false (* should only be here if tt is == != *)
in
let expr = Array.fold_left f expr exprs_tokens in
let expr = List.fold_left f expr exprs_tokens in
Ok expr
and logical_and (state : state ref) : expr_result =
let* expr = equality state in
let* exprs_tokens = collect_chain state [| And |] equality in
let f acc (expr, (token : token)) =
let pos = token.pos in
assert (token.token_type = And);
make_logical pos And acc expr
in
let expr = List.fold_left f expr exprs_tokens in
Ok expr
and logical_or (state : state ref) : expr_result =
let* expr = logical_and state in
let* exprs_tokens = collect_chain state [| Or |] logical_and in
let f acc (expr, (token : token)) =
let pos = token.pos in
assert (token.token_type = Or);
make_logical pos Or acc expr
in
let expr = List.fold_left f expr exprs_tokens in
Ok expr
and assignment (state : state ref) : expr_result =
let* expr = equality state in
let* expr = logical_or state in
if Equal = peek_tt state then
let pos = (next state).pos in
let* rhs = assignment state in
match expr.expr with
| Variable name -> Ok (make_assignment pos name rhs)
| Variable name -> make_assignment pos name rhs |> Result.ok
| _ ->
let msg = "Invalid assignment target" in
Error (ParserError.make pos msg)
ParserError.make pos msg |> Result.error
else Ok expr
and expression (state : state ref) : expr_result = assignment state
@ -204,7 +226,7 @@ let rec block (state : state ref) : stmt_result =
let rec collect_stmts state =
if is_at_end state then
let msg = "Unterminated block" in
Error (ParserError.make pos msg)
ParserError.make pos msg |> Result.error
else
match peek_tt state with
| RightBrace -> Ok []
@ -215,7 +237,19 @@ let rec block (state : state ref) : stmt_result =
in
let* stmts = collect_stmts state in
let* _ = consume state RightBrace in
Ok (make_block pos stmts)
make_block pos stmts |> Result.ok
and if_then_else (state : state ref) : stmt_result =
let pos = cur_pos state in
let* _ = consume state If in
let* _ = consume state LeftParen in
let* cond = expression state 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
in
make_if pos cond then_ else_ |> Result.ok
and statement (state : state ref) : stmt_result =
let pos = cur_pos state in
@ -227,6 +261,7 @@ and statement (state : state ref) : stmt_result =
let stmt = make_print pos expr in
Ok stmt
| LeftBrace -> block state
| If -> if_then_else state
| _ ->
let* expr = expression state in
let* _ = consume state Semicolon in
@ -248,7 +283,7 @@ and var_declaration (state : state ref) : stmt_result =
Ok None
in
let* _ = consume state Semicolon in
Ok (make_var_decl pos name init)
make_var_decl pos name init |> Result.ok
and declaration (state : state ref) : stmt_result =
match peek_tt state with Var -> var_declaration state | _ -> statement state
@ -270,7 +305,6 @@ let rec parse_impl (state : state ref) : parse_result =
let* stmts = parse_impl state in
Ok (stmt :: stmts)
| Error e -> (
print_endline e.msg;
synchronise state;
if peek_tt state = Eof then Error [ e ]
else