diff options
author | NanoTech | 2016-12-07 00:14:15 -0600 |
---|---|---|
committer | NanoTech | 2017-03-10 23:48:28 -0600 |
commit | 9bfe1f36502c701d33174293f71647e614e5797e (patch) | |
tree | f111f0b0b6d9c4489bed293790d7e44e85381c16 /src | |
parent | e8da1dd3007a392e9594eca72177265f356cabeb (diff) |
Parse Const, lists, and records
Also fix keyword parsing to always consume
whole identifiers.
Diffstat (limited to 'src')
-rw-r--r-- | src/grammar.lalrpop | 57 | ||||
-rw-r--r-- | src/grammar_util.rs | 8 | ||||
-rw-r--r-- | src/lexer.rs | 100 | ||||
-rw-r--r-- | src/parser.rs | 1 |
4 files changed, 133 insertions, 33 deletions
diff --git a/src/grammar.lalrpop b/src/grammar.lalrpop index 8a4ad83..c2dc879 100644 --- a/src/grammar.lalrpop +++ b/src/grammar.lalrpop @@ -1,7 +1,11 @@ use core; use core::Expr::*; use grammar_util::*; -use lexer::{Builtin, Keyword, LexicalError, Tok}; +use lexer::*; + +use std::collections::HashMap; +use std::iter; +use std::iter::FromIterator; grammar; @@ -19,13 +23,20 @@ extern { Nat => Tok::Natural(<usize>), Bool => Tok::Bool(<bool>), Label => Tok::Identifier(<String>), + Const => Tok::Const(<core::Const>), Let => Tok::Keyword(Keyword::Let), In => Tok::Keyword(Keyword::In), If => Tok::Keyword(Keyword::If), Then => Tok::Keyword(Keyword::Then), Else => Tok::Keyword(Keyword::Else), + List => Tok::ListLike(ListLike::List), + Optional => Tok::ListLike(ListLike::Optional), Builtin => Tok::Builtin(<Builtin>), + "{" => Tok::BraceL, + "}" => Tok::BraceR, + "[" => Tok::BracketL, + "]" => Tok::BracketR, "(" => Tok::ParenL, ")" => Tok::ParenR, "&&" => Tok::BoolAnd, @@ -35,6 +46,7 @@ extern { "++" => Tok::Append, "*" => Tok::Times, "+" => Tok::Plus, + "," => Tok::Comma, "." => Tok::Dot, ":" => Tok::Ascription, "=" => Tok::Equals, @@ -52,9 +64,15 @@ ExprB: BoxExpr = { If <Expr> Then <ExprB> Else <ExprC> => bx(BoolIf(<>)), <ExprC> "->" <ExprB> => bx(Pi("_".to_owned(), <>)), Let <Label> <(":" <Expr>)?> "=" <Expr> In <ExprB> => bx(Let(<>)), + "[" <a:Elems> "]" ":" <b:ListLike> <c:ExprE> => bx(b(c, a)), ExprC, }; +ListLike: ExprListFn = { + List => ListLit, + Optional => OptionalLit, +}; + BoolOr: ExprOpFn = { "||" => BoolOr }; NaturalPlus: ExprOpFn = { "+" => NaturalPlus }; TextAppend: ExprOpFn = { "++" => TextAppend }; @@ -97,7 +115,44 @@ ExprF: BoxExpr = { Nat => bx(NaturalLit(<>)), Int => bx(IntegerLit(<>)), Label => bx(Var(core::Var(<>, 0))), // FIXME support var@n syntax + Const => bx(Const(<>)), + List => bx(List), + Optional => bx(Optional), Builtin => bx(builtin_expr(<>)), Bool => bx(BoolLit(<>)), + Record, + RecordLit, "(" <Expr> ")", }; + +SepBy<S, T>: iter::Chain<::std::vec::IntoIter<T>, ::std::option::IntoIter<T>> = { + <v:(<T> S)*> <last:T?> => v.into_iter().chain(last.into_iter()), +}; + +SepBy1<S, T>: iter::Chain<::std::vec::IntoIter<T>, iter::Once<T>> = { + <v:(<T> S)*> <last:T> => v.into_iter().chain(iter::once(last)), +}; + +Elems: Vec<ParsedExpr> = { + <v:SepBy<",", Expr>> => { + v.into_iter() + .map(|b| *b) + .collect::<Vec<_>>() + } +}; + +RecordLit: BoxExpr = { + "{" "=" "}" => bx(RecordLit(HashMap::new())), + "{" <FieldValues> "}" => bx(RecordLit(HashMap::from_iter(<>))), +}; + +Record: BoxExpr = { + "{" <FieldTypes> "}" => bx(Record(HashMap::from_iter(<>))), +}; + +FieldValues = SepBy1<",", Field<"=">>; +FieldTypes = SepBy<",", Field<":">>; + +Field<Sep>: (String, ParsedExpr) = { + <a:Label> Sep <b:Expr> => (a, *b), +}; diff --git a/src/grammar_util.rs b/src/grammar_util.rs index d73be94..4a14175 100644 --- a/src/grammar_util.rs +++ b/src/grammar_util.rs @@ -1,8 +1,10 @@ use core::Expr; use lexer::Builtin; -pub type BoxExpr = Box<Expr<(), ()>>; -pub type ExprOpFn = fn(BoxExpr, BoxExpr) -> Expr<(), ()>; +pub type ParsedExpr = Expr<(), ()>; +pub type BoxExpr = Box<ParsedExpr>; +pub type ExprOpFn = fn(BoxExpr, BoxExpr) -> ParsedExpr; +pub type ExprListFn = fn(BoxExpr, Vec<ParsedExpr>) -> ParsedExpr; pub fn bx<T>(x: T) -> Box<T> { Box::new(x) @@ -19,7 +21,6 @@ pub fn builtin_expr<S, A>(b: Builtin) -> Expr<S, A> { Builtin::Integer => Expr::Integer, Builtin::Double => Expr::Double, Builtin::Text => Expr::Text, - Builtin::List => Expr::List, Builtin::ListBuild => Expr::ListBuild, Builtin::ListFold => Expr::ListFold, Builtin::ListLength => Expr::ListLength, @@ -27,7 +28,6 @@ pub fn builtin_expr<S, A>(b: Builtin) -> Expr<S, A> { Builtin::ListLast => Expr::ListLast, Builtin::ListIndexed => Expr::ListIndexed, Builtin::ListReverse => Expr::ListReverse, - Builtin::Optional => Expr::Optional, Builtin::OptionalFold => Expr::OptionalFold, Builtin::Bool => Expr::Bool, } diff --git a/src/lexer.rs b/src/lexer.rs index b9ff9bd..5081bcb 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -2,6 +2,8 @@ use nom; use std::str::FromStr; +use core::Const; + #[derive(Debug, PartialEq, Eq)] pub enum Keyword { Let, @@ -12,6 +14,12 @@ pub enum Keyword { } #[derive(Debug, PartialEq, Eq)] +pub enum ListLike { + List, + Optional, +} + +#[derive(Debug, PartialEq, Eq)] pub enum Builtin { Natural, NaturalFold, @@ -22,7 +30,6 @@ pub enum Builtin { Integer, Double, Text, - List, ListBuild, ListFold, ListLength, @@ -30,7 +37,6 @@ pub enum Builtin { ListLast, ListIndexed, ListReverse, - Optional, OptionalFold, Bool, } @@ -40,11 +46,17 @@ pub enum Tok { Identifier(String), Keyword(Keyword), Builtin(Builtin), + ListLike(ListLike), + Const(Const), Bool(bool), Integer(isize), Natural(usize), // Symbols + BraceL, + BraceR, + BracketL, + BracketR, ParenL, ParenR, Arrow, @@ -58,6 +70,7 @@ pub enum Tok { Append, Times, Plus, + Comma, Dot, Ascription, Equals, @@ -128,39 +141,63 @@ named!(boolean<&str, bool>, alt!( value!(false, tag!("False")) )); +/// Parse an identifier, ensuring a whole identifier is parsed and not just a prefix. +macro_rules! ident_tag { + ($i:expr, $tag:expr) => { + match identifier($i) { + nom::IResult::Done(i, s) => { + if s == $tag { + nom::IResult::Done(i, s) + } else { + nom::IResult::Error(error_position!(nom::ErrorKind::Tag, $i)) + } + } + r => r, + } + } +} + named!(keyword<&str, Keyword>, alt!( - value!(Keyword::Let, tag!("let")) | - value!(Keyword::In, tag!("in")) | - value!(Keyword::If, tag!("if")) | - value!(Keyword::Then, tag!("then")) | - value!(Keyword::Else, tag!("else")) + value!(Keyword::Let, ident_tag!("let")) | + value!(Keyword::In, ident_tag!("in")) | + value!(Keyword::If, ident_tag!("if")) | + value!(Keyword::Then, ident_tag!("then")) | + value!(Keyword::Else, ident_tag!("else")) +)); + +named!(type_const<&str, Const>, alt!( + value!(Const::Type, ident_tag!("Type")) | + value!(Const::Kind, ident_tag!("Kind")) +)); + +named!(list_like<&str, ListLike>, alt!( + value!(ListLike::List, ident_tag!("List")) | + value!(ListLike::Optional, ident_tag!("Optional")) )); named!(builtin<&str, Builtin>, alt!( - value!(Builtin::NaturalFold, tag!("Natural/fold")) | - value!(Builtin::NaturalBuild, tag!("Natural/build")) | - value!(Builtin::NaturalIsZero, tag!("Natural/isZero")) | - value!(Builtin::NaturalEven, tag!("Natural/even")) | - value!(Builtin::NaturalOdd, tag!("Natural/odd")) | - value!(Builtin::Natural, tag!("Natural")) | - value!(Builtin::Integer, tag!("Integer")) | - value!(Builtin::Double, tag!("Double")) | - value!(Builtin::Text, tag!("Text")) | - value!(Builtin::ListBuild, tag!("List/build")) | - value!(Builtin::ListFold, tag!("List/fold")) | - value!(Builtin::ListLength, tag!("List/length")) | - value!(Builtin::ListHead, tag!("List/head")) | - value!(Builtin::ListLast, tag!("List/last")) | - value!(Builtin::ListIndexed, tag!("List/indexed")) | - value!(Builtin::ListReverse, tag!("List/reverse")) | - value!(Builtin::List, tag!("List")) | - value!(Builtin::OptionalFold, tag!("Optional/fold")) | - value!(Builtin::Optional, tag!("Optional")) | - value!(Builtin::Bool, tag!("Bool")) + value!(Builtin::NaturalFold, ident_tag!("Natural/fold")) | + value!(Builtin::NaturalBuild, ident_tag!("Natural/build")) | + value!(Builtin::NaturalIsZero, ident_tag!("Natural/isZero")) | + value!(Builtin::NaturalEven, ident_tag!("Natural/even")) | + value!(Builtin::NaturalOdd, ident_tag!("Natural/odd")) | + value!(Builtin::Natural, ident_tag!("Natural")) | + value!(Builtin::Integer, ident_tag!("Integer")) | + value!(Builtin::Double, ident_tag!("Double")) | + value!(Builtin::Text, ident_tag!("Text")) | + value!(Builtin::ListBuild, ident_tag!("List/build")) | + value!(Builtin::ListFold, ident_tag!("List/fold")) | + value!(Builtin::ListLength, ident_tag!("List/length")) | + value!(Builtin::ListHead, ident_tag!("List/head")) | + value!(Builtin::ListLast, ident_tag!("List/last")) | + value!(Builtin::ListIndexed, ident_tag!("List/indexed")) | + value!(Builtin::ListReverse, ident_tag!("List/reverse")) | + value!(Builtin::OptionalFold, ident_tag!("Optional/fold")) | + value!(Builtin::Bool, ident_tag!("Bool")) )); named!(token<&str, Tok>, alt!( - value!(Tok::Pi, tag!("forall")) | + value!(Tok::Pi, ident_tag!("forall")) | value!(Tok::Pi, tag!("∀")) | value!(Tok::Lambda, tag!("\\")) | value!(Tok::Lambda, tag!("λ")) | @@ -169,13 +206,19 @@ named!(token<&str, Tok>, alt!( value!(Tok::Arrow, tag!("->")) | value!(Tok::Arrow, tag!("→")) | + map!(type_const, Tok::Const) | map!(boolean, Tok::Bool) | map!(keyword, Tok::Keyword) | map!(builtin, Tok::Builtin) | + map!(list_like, Tok::ListLike) | map_opt!(natural, |s| usize::from_str(s).ok().map(|n| Tok::Natural(n))) | map!(integer, Tok::Integer) | map!(identifier, |s: &str| Tok::Identifier(s.to_owned())) | + value!(Tok::BraceL, tag!("{")) | + value!(Tok::BraceR, tag!("}")) | + value!(Tok::BracketL, tag!("[")) | + value!(Tok::BracketR, tag!("]")) | value!(Tok::ParenL, tag!("(")) | value!(Tok::ParenR, tag!(")")) | value!(Tok::BoolAnd, tag!("&&")) | @@ -185,6 +228,7 @@ named!(token<&str, Tok>, alt!( value!(Tok::Append, tag!("++")) | value!(Tok::Times, tag!("*")) | value!(Tok::Plus, tag!("+")) | + value!(Tok::Comma, tag!(",")) | value!(Tok::Dot, tag!(".")) | value!(Tok::Ascription, tag!(":")) | value!(Tok::Equals, tag!("=")) diff --git a/src/parser.rs b/src/parser.rs index 1ecf040..e3f3420 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -31,4 +31,5 @@ fn test_parse() { assert!(parse_expr("\\(b : Bool) -> b == False").is_ok()); println!("{:?}", parse_expr("foo.bar")); assert!(parse_expr("foo.bar").is_ok()); + assert!(parse_expr("[] : List Bool").is_ok()); } |