summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNanoTech2016-12-07 00:14:15 -0600
committerNanoTech2017-03-10 23:48:28 -0600
commit9bfe1f36502c701d33174293f71647e614e5797e (patch)
treef111f0b0b6d9c4489bed293790d7e44e85381c16
parente8da1dd3007a392e9594eca72177265f356cabeb (diff)
Parse Const, lists, and records
Also fix keyword parsing to always consume whole identifiers.
-rw-r--r--src/grammar.lalrpop57
-rw-r--r--src/grammar_util.rs8
-rw-r--r--src/lexer.rs100
-rw-r--r--src/parser.rs1
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());
}