Tigerインタプリタで組み込み関数を呼び出せるようにしたい
https://gyazo.com/1a3bc5fd8828827adbbc253309636016
組み込み関数を呼べるようにして、組み込み関数 print を実装した。
print 関数はユニットを返したいけどまだ未実装なので 0 を返してる。
code:diff
diff --git a/bin/main.ml b/bin/main.ml
index 631e1e0..4659dea 100644
--- a/bin/main.ml
+++ b/bin/main.ml
@@ -2,7 +2,18 @@
let () =
let buff = Lexing.from_channel stdin in
let expr = Tiger.Parser.program Tiger.Lexer.token buff in
- let result, _ = Tiger.Eval.f expr [] in
- print_string "#=> ";
+ let result, _ = Tiger.Eval.f expr [
+ (* 組み込み関数 print(s: string) *)
+ ("print", Tiger.Eval.BuiltInFunction(
+ fun args _ ->
+ match args with
+ print_string s;
+ (* NOTE: 本当は unit を返したいけどまだ未実装なので 0 を返してる *)
+ Tiger.Eval.IntVal(0)
+ | _ -> failwith "invalid arguments"
+ ))
+ ] in
+ print_string "\n#=> ";
Tiger.Eval.print_val result;
print_newline ()
diff --git a/lib/eval.ml b/lib/eval.ml
index 1aa1f6e..b4af632 100644
--- a/lib/eval.ml
+++ b/lib/eval.ml
@@ -1,6 +1,10 @@
type id = string
and table = (id * val_t) list
-and val_t = IntVal of int | StringVal of string | FunctionDec of id list * Syntax.t
+and val_t =
+ IntVal of int
+ | StringVal of string
+ | FunctionDec of id list * Syntax.t
+ | BuiltInFunction of (val_t list -> table -> val_t)
let rec f expr env: val_t * table =
match expr with
@@ -27,6 +31,17 @@ let rec f expr env: val_t * table =
in
let new_env = get_args args env field_names in
f body new_env
+ | BuiltInFunction builtin_func ->
+ (let rec eval_args args env =
+ match args with
+ | [] -> ([], env)
+ | arg::args ->
+ let v, env = f arg env in
+ let vs, env = eval_args args env in
+ (v::vs, env)
+ in
+ let args, env = eval_args args env in
+ (builtin_func args env, env))
| _ -> failwith "type error")
| Syntax.OpExp (e1, op, e2) ->
match op with
@@ -79,5 +94,6 @@ and string_of_val v =
IntVal n -> string_of_int n
| StringVal s -> s
| FunctionDec _ -> "<fun>"
+ | BuiltInFunction _ -> "<builtin>"
and print_val v = print_string (string_of_val v)
diff --git a/test/tiger_test.expected b/test/tiger_test.expected
index 9c6d8c4..aac8ff3 100644
--- a/test/tiger_test.expected
+++ b/test/tiger_test.expected
@@ -25,3 +25,6 @@ result: 30
result: 99
result: 5678
result: 100
+result: 20
+result: 4649
+Hello World!!
diff --git a/test/tiger_test.ml b/test/tiger_test.ml
index 8800e2b..3ada260 100644
--- a/test/tiger_test.ml
+++ b/test/tiger_test.ml
@@ -5,7 +5,18 @@ let eval_with_env src env =
result
let eval src =
- eval_with_env src []
+ eval_with_env src [
+ (* 組み込み関数 print(s: string) *)
+ ("print", Tiger.Eval.BuiltInFunction(
+ fun args _ ->
+ match args with
+ print_string s;
+ (* NOTE: 本当は unit を返したいけどまだ未実装なので 0 を返してる *)
+ Tiger.Eval.IntVal(0)
+ | _ -> failwith "invalid arguments"
+ ))
+ ]
(* 整数リテラル *)
let () =
@@ -211,3 +222,58 @@ let () =
print_string "result: ";
Tiger.Eval.print_val (eval src);
print_newline ()
+
+(* 組み込み関数 double の呼び出し *)
+let () =
+ let src = {|
+ let
+ in
+ double(10)
+ end
+ |}
+ in
+ print_string "result: ";
+ let env = [
+ ("double", Tiger.Eval.BuiltInFunction (
+ fun args (_:Tiger.Eval.table) ->
+ match args with
+ | _ -> failwith "invalid arguments"
+ ));
+ ] in
+ Tiger.Eval.print_val (eval_with_env src env);
+ print_newline ()
+
+(* 組み込み関数 foo の呼び出し *)
+let () =
+ let src = {|
+ let
+ in
+ foo(4, 6, 4, 9)
+ end
+ |}
+ in
+ print_string "result: ";
+ let env = [
+ (* (args0 * 1000) + (args1 * 100) + (args2 * 10) + args3 *) + ("foo", Tiger.Eval.BuiltInFunction (
+ fun args (_:Tiger.Eval.table) ->
+ match args with
+ Tiger.Eval.IntVal(a * 1000 + b * 100 + c * 10 + d)
+ | _ -> failwith "invalid arguments"
+ ));
+ ] in
+ Tiger.Eval.print_val (eval_with_env src env);
+ print_newline ()
+
+(* 組み込み関数 print(s: string) の呼び出し *)
+let () =
+ let src = {|
+ let in
+ print("Hello World!!")
+ end
+ |}
+ in
+ ignore(eval src);
+ print_newline ()