Change get/set precedence/associativity to external function

This commit is contained in:
백현웅 2022-02-20 03:35:11 +09:00
parent 34eeff4a01
commit 8c40e99241
4 changed files with 43 additions and 62 deletions

16
ast.ml
View file

@ -15,11 +15,6 @@ type t =
| Binop of t * operator * t | Binop of t * operator * t
| If of t * t * t (* cond then else *) | If of t * t * t (* cond then else *)
| Apply of t * t list (* function application *) | Apply of t * t list (* function application *)
(* these will be seperated into external functions. *)
| Set_binop_pre of operator * t
| Get_binop_pre of operator
| Set_binop_aso of operator * string
| Get_binop_aso of operator
and operator = and operator =
| Add | Sub | Mul | Div (* arithmetics *) | Add | Sub | Mul | Div (* arithmetics *)
@ -89,16 +84,5 @@ let print ast =
pr "(if"; f co; f th; f el; pr ")" pr "(if"; f co; f th; f el; pr ")"
| Apply (f, args) -> | Apply (f, args) ->
pr "("; aux f; List.iter (fun a -> pr " "; aux a) args; pr ")" pr "("; aux f; List.iter (fun a -> pr " "; aux a) args; pr ")"
| Set_binop_pre (op, pre) ->
pr "(set_pre %s " (op_to_string op);
aux pre;
pr ")"
| Get_binop_pre op ->
pr "(get_pre %s)" (op_to_string op)
| Set_binop_aso (op, aso) ->
pr "(set_assoc %s %s)" (op_to_string op) aso
| Get_binop_aso op ->
pr "(get_pre %s)" (op_to_string op)
in in
aux ast; pr "\n" aux ast; pr "\n"

57
eval.ml
View file

@ -168,6 +168,42 @@ module External = struct
| [v] -> raise @@ Type.Invalid (Value.typeof v) | [v] -> raise @@ Type.Invalid (Value.typeof v)
| _ -> invalid_arg "External.floatfun" | _ -> invalid_arg "External.floatfun"
let symbol_to_op op =
op
|> String.to_seqi
|> Lex.find_token
|> Option.get
|> fst
|> Parser.token_to_op
let set_op_pre = function
| [Symbol op; Int l] ->
let op = symbol_to_op op in
Hashtbl.replace Parser.precedence op l;
Nop
| _ -> failwith "set_op_pre"
let get_op_pre = function
| [Symbol op] ->
let op = symbol_to_op op in
Int (Hashtbl.find Parser.precedence op)
| _ -> failwith "get_op_pre"
let set_op_assoc = function
| [Symbol op; String a] ->
let op = symbol_to_op op in
Hashtbl.replace Parser.oper_assoc op @@ Parser.assoc_of_string a;
Nop
| _ -> failwith "set_op_assoc"
let get_op_assoc = function
| [Symbol op] ->
let op = symbol_to_op op in
Hashtbl.find_opt Parser.oper_assoc op
|> Option.value ~default: Parser.Left_to_right
|> (fun a -> String (Parser.assoc_to_string a))
| _ -> failwith "get_op_assoc"
let apply f args = let apply f args =
let f = match f with let f = match f with
| "sin" -> floatfun Float.sin | "sin" -> floatfun Float.sin
@ -175,6 +211,10 @@ module External = struct
| "tan" -> floatfun Float.tan | "tan" -> floatfun Float.tan
| "deg" -> floatfun deg | "deg" -> floatfun deg
| "rad" -> floatfun rad | "rad" -> floatfun rad
| "set_op_pre" -> set_op_pre
| "get_op_pre" -> get_op_pre
| "set_op_assoc" -> set_op_assoc
| "get_op_assoc" -> get_op_assoc
| _ -> raise @@ Invalid f | _ -> raise @@ Invalid f
in in
f args f args
@ -250,23 +290,6 @@ let rec eval env ast =
end end
| Apply (v, args) -> apply v args env | Apply (v, args) -> apply v args env
| Set_binop_pre (op, l) ->
let l =
match aux l with
| Int n -> n
| v -> raise @@ Type.Invalid (Value.typeof v)
in
Hashtbl.replace Parser.precedence op l;
Nop
| Get_binop_pre op ->
Int (Hashtbl.find Parser.precedence op)
| Set_binop_aso (op, a) ->
Hashtbl.replace Parser.oper_assoc op @@ Parser.assoc_of_string a;
Nop
| Get_binop_aso op ->
(match Hashtbl.find_opt Parser.oper_assoc op with
| None -> String "left"
| Some a -> String (Parser.assoc_to_string a))
| _ -> failwith "Eval.eval" | _ -> failwith "Eval.eval"
(* apply args to result of expr *) (* apply args to result of expr *)

View file

@ -27,6 +27,8 @@ let print_error e =
let stdlib = [ let stdlib = [
"sin"; "cos"; "tan"; "sin"; "cos"; "tan";
"deg"; "rad"; "deg"; "rad";
"get_op_pre"; "set_op_pre";
"get_op_assoc"; "set_op_assoc";
] ]
|> List.to_seq |> List.to_seq
|> Seq.map (fun v -> v, External v) |> Seq.map (fun v -> v, External v)

View file

@ -191,11 +191,9 @@ and expr pre seq =
seq |> oneof [ seq |> oneof [
ifexpr; ifexpr;
let_value; let_value;
oneof [apply; unary; value] @> binop pre;
level;
assoc;
lambda; lambda;
extern_value; extern_value;
oneof [apply; unary; value] @> binop pre;
(* TODO: place error routine here *) (* TODO: place error routine here *)
] ]
@ -209,32 +207,6 @@ and let_value seq =
let f, seq = mustbe (expr min_int) seq in let f, seq = mustbe (expr min_int) seq in
Letin (id, e, f), seq Letin (id, e, f), seq
(* level := "level" {"get" | "set"} [op] *)
and level seq =
let _, seq = ident "level" seq in
let id, seq = idents (S.of_list ["get"; "set"]) seq in
let op, seq = operator seq in
if id = "get" then
Get_binop_pre op, seq
else if id = "set" then
let v, seq = value seq in
Set_binop_pre (op, v), seq
else
failwith "Parser.level"
(* assoc := "assoc" {"get" | "set"} [op] *)
and assoc seq =
let _, seq = ident "assoc" seq in
let id, seq = idents (S.of_list ["get"; "set"]) seq in
let op, seq = operator seq in
if id = "get" then
Get_binop_aso op, seq
else if id = "set" then
let a, seq = idents (S.of_list ["left"; "right"]) seq in
Set_binop_aso (op, a), seq
else
failwith "Parser.assoc"
(* lambda := "fun" [ident]+ "->" expr *) (* lambda := "fun" [ident]+ "->" expr *)
and lambda seq = and lambda seq =
let _, seq = ident "fun" seq in let _, seq = ident "fun" seq in