Add column info to Parser

This commit is contained in:
백현웅 2022-02-15 00:28:29 +09:00
parent 847375027a
commit e3d683c28f
2 changed files with 37 additions and 48 deletions

View file

@ -9,8 +9,9 @@ let error_to_string e =
| Lex.Invalid_character (col, c) -> | Lex.Invalid_character (col, c) ->
sprintf "invalid character %c at col %d" c col sprintf "invalid character %c at col %d" c col
| Lex.Expected (col, c) -> sprintf "expected %c at col %d" c col | Lex.Expected (col, c) -> sprintf "expected %c at col %d" c col
| Parser.Expected t -> sprintf "expected %s" t | Parser.Expected (col, t) -> sprintf "expected %s at col %d" t col
| Parser.Unexpected_token t -> sprintf "unexpected token \"%s\"" t | Parser.Unexpected_token (col, t) ->
sprintf "unexpected token \"%s\" at col %d" t col
| Type.Invalid t -> sprintf "invalid type %s" (Type.to_string t) | Type.Invalid t -> sprintf "invalid type %s" (Type.to_string t)
| Eval.Unbound v -> sprintf "unbound value %s" v | Eval.Unbound v -> sprintf "unbound value %s" v
| Eval.Too_many_arguments -> "applied too many arguments" | Eval.Too_many_arguments -> "applied too many arguments"

View file

@ -2,15 +2,15 @@ open Ast
module S = Set.Make(String) module S = Set.Make(String)
exception Expected of string exception Expected of int * string
exception Unexpected_token of string exception Unexpected_token of int * string
exception End_of_tokens exception End_of_tokens
let expected t = let expected col t =
raise @@ Expected t raise @@ Expected (col, t)
let unexpected_token t = let unexpected_token col t =
raise @@ Unexpected_token (Token.to_string t) raise @@ Unexpected_token (col, Token.to_string t)
(* precedence table. (* precedence table.
* my first thought was using some sort of partially-ordered graph for * my first thought was using some sort of partially-ordered graph for
@ -89,43 +89,34 @@ let is_keyword = function
let any seq = let any seq =
match seq () with match seq () with
| Seq.Nil -> raise End_of_tokens | Seq.Nil -> raise End_of_tokens
| Seq.Cons (x, seq) -> x, seq | Seq.Cons ((col, x), seq) -> col, x, seq
let token tok seq = let token tok seq =
match seq () with let col, x, seq = any seq in
| Seq.Nil -> expected @@ Token.to_string tok if x = tok then x, seq
| Seq.Cons (x, seq) -> else expected col @@ Token.to_string tok
if x = tok then x, seq
else expected @@ Token.to_string tok
let any_ident seq = let any_ident seq =
match seq () with let col, x, seq = any seq in
| Seq.Nil -> expected "ident" match x with
| Seq.Cons (x, seq) -> begin match x with | Token.Ident id -> id, seq
| Token.Ident id -> id, seq | _ -> expected col "ident"
| _ -> unexpected_token x
end
let idents set seq = let idents set seq =
match seq () with let col, x, seq = any seq in
| Seq.Nil -> match x with
| Token.Ident id when S.mem id set -> id, seq
| _ ->
let msg = "ident " ^ (S.elements set |> String.concat " or ") in let msg = "ident " ^ (S.elements set |> String.concat " or ") in
expected msg expected col 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 = let ident str seq =
idents (S.singleton str) seq idents (S.singleton str) seq
let operator seq = let operator seq =
match seq () with let col, x, seq = any seq in
| Seq.Nil -> expected "operator" try token_to_op x, seq with
| Seq.Cons (x, seq) -> | _ -> expected col "operator"
try token_to_op x, seq with
| _ -> expected "operator"
(* parser combinators *) (* parser combinators *)
@ -261,12 +252,10 @@ and extern_value seq =
(* unary := - value *) (* unary := - value *)
and unary seq = and unary seq =
let op, seq = let op, seq =
match seq () with let col, x, seq = any seq in
| Seq.Nil -> raise End_of_tokens if x = Minus
| Seq.Cons (x, seq) -> then Negate, seq
if x = Minus else expected col "minus (-)"
then Negate, seq
else expected "minus"
in in
let v, seq = value seq in let v, seq = value seq in
Ast.unary op v, seq Ast.unary op v, seq
@ -275,7 +264,7 @@ and unary seq =
and value seq = and value seq =
match seq () with match seq () with
| Seq.Nil -> raise End_of_tokens | Seq.Nil -> raise End_of_tokens
| Seq.Cons (x, seq) -> begin match x with | Seq.Cons ((col, x), seq) -> begin match x with
| Ident id when is_keyword id -> failwith "value" | Ident id when is_keyword id -> failwith "value"
| Ident "true" -> Nbool true, seq | Ident "true" -> Nbool true, seq
| Ident "false" -> Nbool false, seq | Ident "false" -> Nbool false, seq
@ -284,20 +273,20 @@ and value seq =
| Float x -> Nfloat x, seq | Float x -> Nfloat x, seq
| String x -> Nstring x, seq | String x -> Nstring x, seq
| Hash -> | Hash ->
let t, seq = any seq in let _, t, seq = any seq in
Nsymbol (Token.to_string t), seq Nsymbol (Token.to_string t), seq
| LParen -> | LParen ->
let e, seq = expr min_int seq in let e, seq = expr min_int seq in
let _, seq = token RParen seq in let _, seq = token RParen seq in
e, seq e, seq
| _ -> unexpected_token x | _ -> unexpected_token col x
end end
(* binop := binop op binop *) (* binop := binop op binop *)
and binop pre left seq = and binop pre left seq =
match seq () with match seq () with
| Seq.Nil -> left, Seq.empty | Seq.Nil -> left, Seq.empty
| Seq.Cons (x, seq) -> begin match x with | Seq.Cons ((col, x), seq) -> begin match x with
| op when token_is_operator op -> | op when token_is_operator op ->
let op = token_to_op op in let op = token_to_op op in
let op_pre = precedence_of op in let op_pre = precedence_of op in
@ -308,16 +297,15 @@ and binop pre left seq =
let right, seq = expr op_pre seq in let right, seq = expr op_pre seq in
binop pre (Ast.binop left op right) seq binop pre (Ast.binop left op right) seq
else else
left, Seq.cons x seq left, Seq.cons (col, x) seq
| RParen -> left, Seq.cons x seq | RParen -> left, Seq.cons (col, x) seq
| Ident id when is_keyword id -> left, Seq.cons x seq | Ident id when is_keyword id -> left, Seq.cons (col, x) seq
| _ -> unexpected_token x | _ -> unexpected_token col x
end end
(* parse tokens *) (* parse tokens *)
let parse ts = let parse ts =
let ts = Seq.map snd ts in
let ast, rest = decl ts in let ast, rest = decl ts in
if rest () <> Seq.Nil then failwith "Parser.parse"; if rest () <> Seq.Nil then failwith "Parser.parse";
ast ast