ce/parser.ml

273 lines
6.1 KiB
OCaml
Raw Normal View History

2022-01-10 01:31:47 +09:00
open Ast
2022-01-11 01:05:29 +09:00
module S = Set.Make(String)
2022-01-10 01:31:47 +09:00
exception Expected of string
exception Unexpected_token of string
2022-01-19 02:10:34 +09:00
exception End_of_tokens
2022-01-10 01:31:47 +09:00
let expected t =
2022-01-18 16:52:33 +09:00
raise @@ Expected t
2022-01-10 01:31:47 +09:00
let unexpected_token t =
raise @@ Unexpected_token (Token.to_string t)
2022-01-10 23:11:13 +09:00
(* precedence table.
* my first thought was using some sort of partially-ordered graph for
* precedency, but infering precedence relation from the graph is hard
* and the graph can be made to have loops, I just used plain table. *)
2022-01-10 01:31:47 +09:00
let precedence = [
2022-01-11 01:05:29 +09:00
Add, 10;
Sub, 10;
Mul, 20;
Div, 20;
Mod, 30;
Exp, 30;
2022-01-10 01:31:47 +09:00
] |> List.to_seq |> Hashtbl.of_seq
let precedence_of op =
2022-01-11 01:05:29 +09:00
Hashtbl.find precedence op
2022-01-10 01:31:47 +09:00
2022-01-19 15:28:41 +09:00
type associativity =
| Left_to_right
| Right_to_left
2022-01-20 23:36:53 +09:00
let assoc_of_string = function
| "left" -> Left_to_right
| "right" -> Right_to_left
| _ -> invalid_arg "assoc_of_string"
let assoc_to_string = function
| Left_to_right -> "left"
| Right_to_left -> "right"
2022-01-19 15:28:41 +09:00
let oper_assoc = [
Exp, Right_to_left;
] |> List.to_seq |> Hashtbl.of_seq
let op_is_right_to_left op =
let a =
Hashtbl.find_opt oper_assoc op
|> Option.value ~default: Left_to_right
in
a = Right_to_left
2022-01-10 23:11:13 +09:00
2022-01-18 15:36:09 +09:00
let operators = [
Token.Plus, Add;
Minus, Sub;
Asterisk, Mul;
Slash, Div;
Carret, Exp;
Percent, Mod;
] |> List.to_seq |> Hashtbl.of_seq
let token_to_op tok =
try Hashtbl.find operators tok
with _ -> failwith "Parser.token_to_op"
2022-01-10 01:31:47 +09:00
2022-01-19 02:10:34 +09:00
let token_is_operator tok =
Hashtbl.mem operators tok
2022-01-13 00:31:26 +09:00
(* common parsers *)
2022-02-08 00:26:03 +09:00
let any seq =
match seq () with
| Seq.Nil -> raise End_of_tokens
| Seq.Cons (x, seq) -> x, seq
2022-01-20 23:36:53 +09:00
let token tok seq =
match seq () with
| Seq.Nil -> expected @@ Token.to_string tok
| Seq.Cons (x, seq) ->
if x = tok then x, seq
else expected @@ Token.to_string tok
2022-01-21 00:17:01 +09:00
let any_ident seq =
match seq () with
| Seq.Nil -> expected "ident"
| Seq.Cons (x, seq) -> begin match x with
| Token.Ident id -> id, seq
| _ -> unexpected_token x
end
2022-01-13 00:31:26 +09:00
let idents set seq =
match seq () with
| Seq.Nil ->
let msg = "ident " ^ (S.elements set |> String.concat " or ") in
expected msg
| Seq.Cons (x, seq) -> begin
match x with
| Token.Ident id when S.mem id set -> id, seq
| _ -> unexpected_token x
end
let ident str seq =
idents (S.singleton str) seq
let operator seq =
match seq () with
| Seq.Nil -> expected "operator"
| Seq.Cons (x, seq) ->
try token_to_op x, seq with
| _ -> expected "operator"
(* parser combinators *)
2022-01-20 23:36:53 +09:00
let oneof fs seq =
let rec aux = function
| [] -> assert false
| [f] -> f seq
| f::fs -> (try f seq with _ -> aux fs)
in
aux fs
2022-01-13 00:31:26 +09:00
2022-01-29 20:01:48 +09:00
let either f g = fun seq ->
try f seq with _ -> g seq
2022-01-20 23:36:53 +09:00
let (@>) f g = fun seq ->
2022-01-13 00:31:26 +09:00
let a, seq = f seq in
g a seq
2022-01-29 20:01:48 +09:00
let more f seq =
let rec aux xs seq =
try
let x, seq = f seq in
aux (x::xs) seq
with
| _ -> xs, seq
in
let xs, seq = aux [] seq in
List.rev xs, seq
2022-01-20 23:36:53 +09:00
(* expr := level
* | assoc
* | let
2022-01-29 20:01:48 +09:00
* | apply
2022-01-20 01:35:48 +09:00
* | value binop_right
*)
2022-01-20 23:36:53 +09:00
let rec expr pre seq =
seq |> oneof [
level;
assoc;
2022-01-21 00:17:01 +09:00
let_value;
2022-02-01 21:38:00 +09:00
lambda;
extern_value;
apply;
2022-02-01 21:38:00 +09:00
(either unary value) @> binop pre;
2022-01-20 23:36:53 +09:00
]
(* level := "level" {"get" | "set"} [op] *)
and level seq =
let _, seq = ident "level" seq in
2022-01-20 01:35:48 +09:00
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"
2022-01-20 23:36:53 +09:00
(* 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"
2022-01-21 00:17:01 +09:00
(* let_value := "let" ident "=" expr *)
and let_value seq =
let _, seq = ident "let" seq in
let id, seq = any_ident seq in
let _, seq = token Token.Equal seq in
let e, seq = expr min_int seq in
Let (id, e), seq
2022-02-01 21:38:00 +09:00
(* lambda := "fun" [ident]+ "->" expr *)
and lambda seq =
let _, seq = ident "fun" seq in
let v0, seq = any_ident seq in
let vars, seq = more any_ident seq in
let _, seq = token Right_arrow seq in
let e, seq = expr min_int seq in
Nfunction (v0::vars, e), seq
2022-02-01 21:38:00 +09:00
(* apply := value [value]+ *)
2022-01-29 20:01:48 +09:00
and apply seq =
2022-02-01 21:38:00 +09:00
let v, seq = value seq in
let a0, seq = value seq in
2022-01-29 20:01:48 +09:00
let args, seq = more value seq in
2022-02-01 21:38:00 +09:00
Apply (v, a0::args), seq
(* extern_value := external ident *)
and extern_value seq =
let _, seq = ident "external" seq in
let id, seq = any_ident seq in
Nexternal id, seq
2022-01-29 20:01:48 +09:00
2022-01-23 01:20:34 +09:00
(* unary := - value *)
and unary seq =
let op, seq =
match seq () with
| Seq.Nil -> raise End_of_tokens
| Seq.Cons (x, seq) ->
if x = Minus
2022-01-28 00:56:24 +09:00
then Negate, seq
2022-01-23 01:20:34 +09:00
else expected "minus"
in
let v, seq = value seq in
Ast.unary op v, seq
2022-01-20 23:36:53 +09:00
(* value := int | float | ( expr ) *)
2022-01-20 01:35:48 +09:00
and value seq =
match seq () with
| Seq.Nil -> raise End_of_tokens
| Seq.Cons (x, seq) -> begin match x with
2022-02-01 02:06:18 +09:00
| Token.Ident id -> Var id, seq
| Int x -> Nint x, seq
| Float x -> Nfloat x, seq
| String x -> Nstring x, seq
2022-02-08 00:26:03 +09:00
| Hash ->
let t, seq = any seq in
Nsymbol (Token.to_string t), seq
2022-01-20 23:36:53 +09:00
| LParen ->
let e, seq = expr min_int seq in
let _, seq = token RParen seq in
e, seq
2022-01-20 01:35:48 +09:00
| _ -> unexpected_token x
end
(* binop := binop op binop *)
and binop pre left seq =
match seq () with
| Seq.Nil -> left, Seq.empty
| Seq.Cons (x, seq) -> begin match x with
| op when token_is_operator op ->
let op = token_to_op op in
2022-01-20 23:36:53 +09:00
let op_pre = precedence_of op in
2022-01-20 01:35:48 +09:00
(* op has to be calculated first *)
2022-01-20 23:36:53 +09:00
if op_pre > pre
|| (op_is_right_to_left op && op_pre = pre)
then
let right, seq = expr op_pre seq in
2022-01-20 01:35:48 +09:00
binop pre (Ast.binop left op right) seq
else
left, Seq.cons x seq
2022-01-20 23:36:53 +09:00
| Token.RParen -> left, Seq.cons x seq
2022-01-20 01:35:48 +09:00
| _ -> unexpected_token x
end
2022-01-13 00:31:26 +09:00
(* parse tokens *)
2022-01-10 23:11:13 +09:00
let parse ts =
2022-01-20 23:36:53 +09:00
let ast, rest = expr min_int ts in
2022-01-10 01:31:47 +09:00
if rest () <> Seq.Nil then failwith "Parser.parse";
ast