From 57d1cc73dd4bc49914f9e6dc09191ac4ac730c84 Mon Sep 17 00:00:00 2001 From: monoid Date: Wed, 29 Jan 2025 18:07:47 +0900 Subject: [PATCH] feat: impl function call --- bin/main.ml | 1 + lib/eval.ml | 14 ++++++++++++-- lib/parser.ml | 24 +++++++++++++++++++----- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/bin/main.ml b/bin/main.ml index 3576804..c15293e 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -1,4 +1,5 @@ open Calc;; + let main () = let input = Sys.argv.(1) in diff --git a/lib/eval.ml b/lib/eval.ml index 92a1c6d..8f1f7cb 100644 --- a/lib/eval.ml +++ b/lib/eval.ml @@ -11,7 +11,7 @@ and scope = { bindings: value_type VariableBindingMap.t; } and function_type = { - name: string; + argname: string; body: Parser.expr_tree; scope: scope; } @@ -28,6 +28,8 @@ let rec eval_expr (scope: scope) (expr: Parser.expr_tree): value_type = eval_bin_op_expr scope op left_expr right_expr | Parser.MonoOpExpr (_op, _expr) -> failwith "Not implemented" + | Parser.CallExpr (Parser.Call (func_expr, arg_expr)) -> + eval_call_expr scope func_expr arg_expr | Parser.Identifier(name) -> let rec find_binding scope = match scope with @@ -38,6 +40,14 @@ let rec eval_expr (scope: scope) (expr: Parser.expr_tree): value_type = | None -> find_binding s.parent in find_binding (Some scope) | Parser.Number(n) -> Int n +and eval_call_expr scope func_expr arg_expr = + let func = eval_expr scope func_expr in + let arg = eval_expr scope arg_expr in + (match func with + | Fun f -> + let new_scope = { parent = Some f.scope; bindings = VariableBindingMap.add f.argname arg f.scope.bindings } in + eval_expr new_scope f.body + | _ -> failwith "Type error") and eval_if_expr scope cond_expr then_expr else_expr = let cond = eval_expr scope cond_expr in (match cond with @@ -48,7 +58,7 @@ and eval_let_expr scope name value_expr in_expr = let new_scope = { scope with bindings = VariableBindingMap.add name value scope.bindings } in eval_expr new_scope in_expr and eval_fun_expr scope name body_expr = - Fun { name = name; body = body_expr; scope = scope } + Fun { argname = name; body = body_expr; scope = scope } and eval_bin_op_expr scope op left_expr right_expr = let left = eval_expr scope left_expr in let right = eval_expr scope right_expr in diff --git a/lib/parser.ml b/lib/parser.ml index 7219fac..a55d181 100644 --- a/lib/parser.ml +++ b/lib/parser.ml @@ -71,8 +71,9 @@ BNF: let_expr ::= let identifier = expr in expr fun_expr ::= fun identifier -> expr if_expr ::= if expr then expr else expr - level0 ::= (expr) | identifier | number - level1 ::= level0 | level1 + level0 | level1 - level0 + factor ::= (expr) | identifier | number + call_expr ::= factor | factor factor + level1 ::= call_expr | level1 + call_expr | level1 - call_expr level2 ::= level2 * level1 | level2 / level1 | level2 % level1 | level1 level3 ::= level2 ^ level3 | level2 expr ::= let_expr | fun_expr | if_expr | level3 @@ -81,10 +82,12 @@ BNF: type let_expr_tree = Let of string * expr_tree * expr_tree and fun_expr_tree = Fun of string * expr_tree and if_expr_tree = If of expr_tree * expr_tree * expr_tree +and call_expr_tree = Call of expr_tree * expr_tree and expr_tree = | LetExpr of let_expr_tree | FunExpr of fun_expr_tree | IfExpr of if_expr_tree + | CallExpr of call_expr_tree | BinOpExpr of Lexer.op_type * expr_tree * expr_tree | MonoOpExpr of Lexer.op_type * expr_tree | Identifier of string @@ -96,6 +99,7 @@ let expr2str (e: expr_tree): string = | LetExpr (Let (id, e1, e2)) -> Printf.sprintf "let %s = %s in\n %s" id (aux e1) (aux e2) | FunExpr (Fun (id, e)) -> Printf.sprintf "fun %s -> %s" id (aux e) | IfExpr (If (e1, e2, e3)) -> Printf.sprintf "if %s then %s else %s" (aux e1) (aux e2) (aux e3) + | CallExpr (Call (e1, e2)) -> Printf.sprintf "%s %s" (aux e1) (aux e2) | BinOpExpr (op, e1, e2) -> Printf.sprintf "%s %s %s" (aux e1) (Lexer.op2str op) (aux e2) | MonoOpExpr (op, e) -> Printf.sprintf "%s %s" (Lexer.op2str op) (aux e) | Identifier id -> id @@ -132,7 +136,7 @@ and parse_if_expr (): if_expr_tree parser = let* _ = match_token (Lexer.Keyword Lexer.Else) in let* e3 = expr() in return (If (e1, e2, e3)) -and parse_level0 (): expr_tree parser = +and parse_factor (): expr_tree parser = let* tt = peek_token in match tt.token_type with | Lexer.Identifier x -> @@ -147,14 +151,24 @@ and parse_level0 (): expr_tree parser = let* _ = match_token Lexer.RParen in return e | _ -> stop +and parse_call_expr (): expr_tree parser = + let* e1 = parse_factor() in + let rec aux e1 = + let* c = peek_token in + match c.token_type with + | Lexer.Identifier _ | Lexer.Digit _ | Lexer.LParen -> + let* e2 = parse_factor() in + aux (CallExpr (Call (e1, e2))) + | _ -> return e1 in + aux e1 and parse_level1 (): expr_tree parser = - let* e1 = parse_level0() in + let* e1 = parse_call_expr() in let rec aux e1 = let* c = peek_token in match c.token_type with | Lexer.Op op when op = Lexer.Add || op = Lexer.Sub -> let* _ = next_token in - let* e2 = parse_level0() in + let* e2 = parse_call_expr() in aux (BinOpExpr (op, e1, e2)) | _ -> return e1 in aux e1