Change get/set precedence/associativity to external function
This commit is contained in:
parent
34eeff4a01
commit
8c40e99241
4 changed files with 43 additions and 62 deletions
16
ast.ml
16
ast.ml
|
@ -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
57
eval.ml
|
@ -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 *)
|
||||||
|
|
2
main.ml
2
main.ml
|
@ -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)
|
||||||
|
|
30
parser.ml
30
parser.ml
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue