parent
32f8f7c29a
commit
305e95846d
@ -1,92 +0,0 @@
|
||||
use std::iter::Peekable;
|
||||
use std::ops::{Deref, RangeInclusive};
|
||||
use std::usize;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
use super::ParseError;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Token {
|
||||
LeftParen,
|
||||
RightParen,
|
||||
Symbol(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Sexpr {
|
||||
Symbol(String),
|
||||
List(Vec<Sexpr>),
|
||||
}
|
||||
|
||||
impl Sexpr {
|
||||
pub fn symbol(self) -> Option<String> {
|
||||
match self {
|
||||
Sexpr::Symbol(item) => Some(item),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list(self) -> Option<Vec<Sexpr>> {
|
||||
match self {
|
||||
Sexpr::List(item) => Some(item),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn tokenize(input: &str) -> Vec<Token> {
|
||||
let mut tokens = Vec::new();
|
||||
// let mut chars = input.chars().peekable();
|
||||
let mut chars = input.chars().peekable();
|
||||
while let Some(c) = chars.next() {
|
||||
match c {
|
||||
'(' => tokens.push(Token::LeftParen),
|
||||
')' => tokens.push(Token::RightParen),
|
||||
_ if c.is_whitespace() => (),
|
||||
_ => {
|
||||
let mut symbol = c.to_string();
|
||||
while let Some(c) = chars.peek() {
|
||||
if c.is_whitespace() || *c == '(' || *c == ')' {
|
||||
break;
|
||||
}
|
||||
symbol.push(*c);
|
||||
chars.next();
|
||||
}
|
||||
tokens.push(Token::Symbol(symbol));
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
fn parse_expr(tokens: &mut Peekable<IntoIter<Token>>) -> Result<Sexpr, ParseError> {
|
||||
match tokens.next() {
|
||||
Some(Token::LeftParen) => {
|
||||
let mut list = Vec::new();
|
||||
while !matches!(tokens.peek(), Some(Token::RightParen,)) {
|
||||
list.push(parse_expr(tokens)?);
|
||||
}
|
||||
let Some(Token::RightParen) = tokens.next() else {
|
||||
unreachable!()
|
||||
};
|
||||
Ok(Sexpr::List(list))
|
||||
}
|
||||
Some(Token::RightParen) => Err(ParseError::UnexpectedParenClose),
|
||||
Some(Token::Symbol(s)) => Ok(Sexpr::Symbol(s)),
|
||||
None => Err(ParseError::UnexpectedEof),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse(tokens: Vec<Token>) -> Result<Sexpr, ParseError> {
|
||||
let mut tokens = tokens.into_iter().peekable();
|
||||
let ast = parse_expr(&mut tokens)?;
|
||||
if tokens.peek().is_some() {
|
||||
return Err(ParseError::TrailingTokens);
|
||||
};
|
||||
Ok(ast)
|
||||
}
|
||||
|
||||
pub fn parse_string(src: &str) -> Result<Sexpr, ParseError> {
|
||||
let tokens = tokenize(src);
|
||||
parse(tokens)
|
||||
}
|
@ -1,96 +1,254 @@
|
||||
use crate::{
|
||||
PrimitiveType, Type,
|
||||
parse::{
|
||||
Ast, Constant,
|
||||
sexpr::{Sexpr, parse_string},
|
||||
tokenize::{self, Lexer},
|
||||
},
|
||||
types::{PrimitiveType, TaggedType, Type, TypeTag},
|
||||
};
|
||||
|
||||
use super::{parse, parse_type};
|
||||
use super::parser;
|
||||
|
||||
#[test]
|
||||
fn parse_to_sexpr() {
|
||||
let input = "((\\x:Nat.x) (5))";
|
||||
let parsed = parse_string(input).unwrap();
|
||||
assert_eq!(
|
||||
parsed,
|
||||
Sexpr::List(vec![
|
||||
Sexpr::List(vec![Sexpr::Symbol("\\x:Nat.x".to_string())]),
|
||||
Sexpr::List(vec![Sexpr::Symbol("5".to_string())])
|
||||
])
|
||||
);
|
||||
}
|
||||
fn parse_constant() {
|
||||
let parser = parser::AstParser::new();
|
||||
let ast = parser.parse(Lexer::new("5")).unwrap();
|
||||
assert_eq!(ast, Ast::Constant(Constant::Nat(5)));
|
||||
|
||||
#[test]
|
||||
fn parse_prim_type() {
|
||||
let input = Sexpr::Symbol("Nat".to_string());
|
||||
let parsed = parse_type(&input).unwrap();
|
||||
assert_eq!(parsed, Type::Primitive(PrimitiveType::Nat))
|
||||
let ast = parser.parse(Lexer::new("3.14")).unwrap();
|
||||
assert_eq!(ast, Ast::Constant(Constant::Float(3.14)));
|
||||
|
||||
let ast = parser.parse(Lexer::new("true")).unwrap();
|
||||
assert_eq!(ast, Ast::Constant(Constant::Bool(true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_simpl_arr_type() {
|
||||
let input = Sexpr::List(vec![
|
||||
Sexpr::Symbol("Nat".to_string()),
|
||||
Sexpr::Symbol("->".to_string()),
|
||||
Sexpr::Symbol("Nat".to_string()),
|
||||
]);
|
||||
let parsed = parse_type(&input).unwrap();
|
||||
assert_eq!(parsed, Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat))
|
||||
fn parse_variable() {
|
||||
let parser = parser::AstParser::new();
|
||||
let ast = parser.parse(Lexer::new("x")).unwrap();
|
||||
assert_eq!(ast, Ast::Variable("x".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_apply_arr_type() {
|
||||
let input = Sexpr::List(vec![
|
||||
Sexpr::List(vec![
|
||||
Sexpr::Symbol("Nat".to_string()),
|
||||
Sexpr::Symbol("->".to_string()),
|
||||
Sexpr::Symbol("Nat".to_string()),
|
||||
]),
|
||||
Sexpr::Symbol("->".to_string()),
|
||||
Sexpr::Symbol("Nat".to_string()),
|
||||
Sexpr::Symbol("->".to_string()),
|
||||
Sexpr::Symbol("Nat".to_string()),
|
||||
]);
|
||||
let parsed = parse_type(&input).unwrap();
|
||||
fn parse_type() {
|
||||
let parser = parser::TaggedTypeParser::new();
|
||||
let ast = parser.parse(Lexer::new("Num a => a -> a -> a")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Num,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Concrete(Type::arrow(
|
||||
"a",
|
||||
Type::arrow("a", "a")
|
||||
)))
|
||||
)
|
||||
);
|
||||
|
||||
let ast = parser
|
||||
.parse(Lexer::new("Any a => (a -> a) -> a -> a"))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
parsed,
|
||||
Type::arrow(
|
||||
Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat),
|
||||
Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat)
|
||||
ast,
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Concrete(Type::arrow(
|
||||
Type::arrow("a", "a"),
|
||||
Type::arrow("a", "a")
|
||||
)))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
let ast = parser
|
||||
.parse(Lexer::new("Any a => Any b => (a -> b) -> a -> b"))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"b".to_string(),
|
||||
Box::new(TaggedType::Concrete(Type::arrow(
|
||||
Type::arrow("a", "b"),
|
||||
Type::arrow("a", "b")
|
||||
)))
|
||||
))
|
||||
)
|
||||
);
|
||||
|
||||
let ast = parser.parse(Lexer::new("Nat -> Nat")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
TaggedType::Concrete(Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_abstraction() {
|
||||
let input = "(\\ (x (Nat -> Nat)) (x 5))";
|
||||
let parsed = parse(input).unwrap();
|
||||
let parser = parser::AstParser::new();
|
||||
let ast = parser.parse(Lexer::new(r"\x:Nat.x")).unwrap();
|
||||
assert_eq!(
|
||||
parsed,
|
||||
ast,
|
||||
Ast::Abstraction(
|
||||
"x".to_string(),
|
||||
Type::arrow(PrimitiveType::Nat, PrimitiveType::Nat),
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("x".to_string())),
|
||||
Box::new(Ast::Constant(Constant::Nat(5)))
|
||||
Type::Primitive(PrimitiveType::Nat).into(),
|
||||
Box::new(Ast::Variable("x".to_string()))
|
||||
)
|
||||
);
|
||||
|
||||
let ast = parser.parse(Lexer::new(r"\x:Nat.\y:Nat.x")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Abstraction(
|
||||
"x".to_string(),
|
||||
Type::Primitive(PrimitiveType::Nat).into(),
|
||||
Box::new(Ast::Abstraction(
|
||||
"y".to_string(),
|
||||
Type::Primitive(PrimitiveType::Nat).into(),
|
||||
Box::new(Ast::Variable("x".to_string()))
|
||||
))
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
let ast = parser
|
||||
.parse(Lexer::new(r"\x:Any a => a.\y:Any b => b.x"))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Abstraction(
|
||||
"x".to_string(),
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Concrete("a".into()))
|
||||
),
|
||||
Box::new(Ast::Abstraction(
|
||||
"y".to_string(),
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"b".to_string(),
|
||||
Box::new(TaggedType::Concrete("b".into()))
|
||||
),
|
||||
Box::new(Ast::Variable("x".to_string()))
|
||||
))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_application() {
|
||||
let input = "((add 5) 6)";
|
||||
let parsed = parse(input).unwrap();
|
||||
let parser = parser::AstParser::new();
|
||||
let ast = parser.parse(Lexer::new(r"(\x:Nat.x) 5")).unwrap();
|
||||
assert_eq!(
|
||||
parsed,
|
||||
ast,
|
||||
Ast::Application(
|
||||
Box::new(Ast::Abstraction(
|
||||
"x".to_string(),
|
||||
Type::Primitive(PrimitiveType::Nat).into(),
|
||||
Box::new(Ast::Variable("x".to_string()))
|
||||
)),
|
||||
Box::new(Ast::Constant(Constant::Nat(5)))
|
||||
)
|
||||
);
|
||||
|
||||
let ast = parser.parse(Lexer::new(r"add 1")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Application(
|
||||
Box::new(Ast::Variable("add".to_string())),
|
||||
Box::new(Ast::Constant(Constant::Nat(1)))
|
||||
),
|
||||
);
|
||||
|
||||
let ast = parser.parse(Lexer::new(r"(add 1) 2")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Application(
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("add".to_string())),
|
||||
Box::new(Ast::Constant(Constant::Nat(1)))
|
||||
)),
|
||||
Box::new(Ast::Constant(Constant::Nat(2)))
|
||||
),
|
||||
);
|
||||
|
||||
let ast = parser.parse(Lexer::new(r"add 1 2")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Application(
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("add".to_string())),
|
||||
Box::new(Ast::Constant(Constant::Nat(1)))
|
||||
)),
|
||||
Box::new(Ast::Constant(Constant::Nat(2)))
|
||||
),
|
||||
);
|
||||
|
||||
let ast = parser.parse(Lexer::new(r"add 1 (x y)")).unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Application(
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("add".to_string())),
|
||||
Box::new(Ast::Constant(Constant::Nat(5)))
|
||||
Box::new(Ast::Constant(Constant::Nat(1)))
|
||||
)),
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("x".to_string())),
|
||||
Box::new(Ast::Variable("y".to_string())),
|
||||
)),
|
||||
Box::new(Ast::Constant(Constant::Nat(6)))
|
||||
),
|
||||
);
|
||||
|
||||
let ast = parser
|
||||
.parse(Lexer::new(
|
||||
r"(\x:Any a => a -> a.\y:Num a => a. add 1 (x y)) (\x:Any a => a.x) 2",
|
||||
))
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
ast,
|
||||
Ast::Application(
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Abstraction(
|
||||
"x".to_string(),
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Concrete(Type::arrow("a", "a")))
|
||||
),
|
||||
Box::new(Ast::Abstraction(
|
||||
"y".to_string(),
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Num,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Concrete("a".into()))
|
||||
),
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("add".to_string())),
|
||||
Box::new(Ast::Constant(Constant::Nat(1)))
|
||||
)),
|
||||
Box::new(Ast::Application(
|
||||
Box::new(Ast::Variable("x".to_string())),
|
||||
Box::new(Ast::Variable("y".to_string())),
|
||||
))
|
||||
))
|
||||
)),
|
||||
)),
|
||||
Box::new(Ast::Abstraction(
|
||||
"x".to_string(),
|
||||
TaggedType::Tagged(
|
||||
TypeTag::Any,
|
||||
"a".to_string(),
|
||||
Box::new(TaggedType::Concrete("a".into()))
|
||||
),
|
||||
Box::new(Ast::Variable("x".to_string()))
|
||||
))
|
||||
)),
|
||||
Box::new(Ast::Constant(Constant::Nat(2)))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// (\x:Any a => a -> a.\y:Num a => a. + 1 (x y)) (\x:Any a => a.x) 2
|
||||
|
@ -0,0 +1,141 @@
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
num::{ParseFloatError, ParseIntError},
|
||||
str::ParseBoolError,
|
||||
};
|
||||
|
||||
use logos::{Logos, SpannedIter};
|
||||
|
||||
use super::ParseError;
|
||||
|
||||
impl From<ParseIntError> for ParseError {
|
||||
fn from(err: ParseIntError) -> Self {
|
||||
Self::InvalidInteger(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseFloatError> for ParseError {
|
||||
fn from(err: ParseFloatError) -> Self {
|
||||
Self::InvalidFloat(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParseBoolError> for ParseError {
|
||||
fn from(err: ParseBoolError) -> Self {
|
||||
Self::InvalidBool(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Logos, Debug, Clone)]
|
||||
#[logos(skip r"[ \t\n\r\f]+", error = ParseError)]
|
||||
pub enum Token {
|
||||
// #[regex(r#""([^\"\\]|\\.)*""#, |lex| {let slice = lex.slice(); slice[1..slice.len() - 1].to_string()})]
|
||||
// String(String),
|
||||
#[regex(r#"\d+"#, |lex| lex.slice().parse::<usize>())]
|
||||
Nat(usize),
|
||||
#[regex(r#"-?\d+\.\d+"#, |lex| lex.slice().parse::<f64>())]
|
||||
Float(f64),
|
||||
#[regex(r#"(true|false)"#, |lex| lex.slice().parse::<bool>())]
|
||||
Bool(bool),
|
||||
|
||||
#[regex(r#"[_a-zA-Z][_a-zA-Z0-9]*'*"#, |lex| lex.slice().to_string())]
|
||||
Ident(String),
|
||||
|
||||
#[token(r"\")]
|
||||
Lambda,
|
||||
#[token("=>")]
|
||||
FatArrow,
|
||||
#[token("->")]
|
||||
ThinArrow,
|
||||
#[token(":")]
|
||||
Colon,
|
||||
#[token(".")]
|
||||
Period,
|
||||
|
||||
#[token("=")]
|
||||
Equals,
|
||||
#[token("<>")]
|
||||
NotEquals,
|
||||
#[token("+")]
|
||||
Plus,
|
||||
#[token("-")]
|
||||
Minus,
|
||||
#[token("*")]
|
||||
Star,
|
||||
#[token("/")]
|
||||
Slash,
|
||||
#[token("^")]
|
||||
Hat,
|
||||
#[token("<")]
|
||||
Less,
|
||||
#[token(">")]
|
||||
Greater,
|
||||
#[token("<=")]
|
||||
LessEq,
|
||||
#[token(">=")]
|
||||
GreaterEq,
|
||||
#[token(r"/\")]
|
||||
Conjunction,
|
||||
#[token(r"\/")]
|
||||
Disjunction,
|
||||
|
||||
#[token("(")]
|
||||
ParenOpen,
|
||||
#[token(")")]
|
||||
ParenClose,
|
||||
}
|
||||
|
||||
pub type Spanned<Tok, Loc, Error> = Result<(Loc, Tok, Loc), Error>;
|
||||
|
||||
pub struct Lexer<'input> {
|
||||
// instead of an iterator over characters, we have a token iterator
|
||||
token_stream: SpannedIter<'input, Token>,
|
||||
}
|
||||
impl<'input> Lexer<'input> {
|
||||
pub fn new(input: &'input str) -> Self {
|
||||
// the Token::lexer() method is provided by the Logos trait
|
||||
Self {
|
||||
token_stream: Token::lexer(input).spanned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'input> Iterator for Lexer<'input> {
|
||||
type Item = Spanned<Token, usize, ParseError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.token_stream
|
||||
.next()
|
||||
.map(|(token, span)| Ok((span.start, token?, span.end)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Token {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Token::Lambda => write!(f, r"\"),
|
||||
Token::FatArrow => write!(f, "=>"),
|
||||
Token::ThinArrow => write!(f, "->"),
|
||||
Token::Colon => write!(f, ":"),
|
||||
Token::Period => write!(f, "."),
|
||||
Token::Equals => write!(f, "="),
|
||||
Token::NotEquals => write!(f, "<>"),
|
||||
Token::Plus => write!(f, "+"),
|
||||
Token::Minus => write!(f, "-"),
|
||||
Token::Star => write!(f, "*"),
|
||||
Token::Slash => write!(f, "/"),
|
||||
Token::Hat => write!(f, "^"),
|
||||
Token::Less => write!(f, "<"),
|
||||
Token::Greater => write!(f, ">"),
|
||||
Token::LessEq => write!(f, "<="),
|
||||
Token::GreaterEq => write!(f, ">="),
|
||||
Token::Conjunction => write!(f, r"/\"),
|
||||
Token::Disjunction => write!(f, r"\/"),
|
||||
Token::ParenOpen => write!(f, "("),
|
||||
Token::ParenClose => write!(f, ")"),
|
||||
Token::Nat(n) => write!(f, "{n}"),
|
||||
Token::Float(n) => write!(f, "{n}"),
|
||||
Token::Bool(b) => write!(f, "{b}"),
|
||||
Token::Ident(i) => write!(f, "{i}"),
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
use crate::{
|
||||
parse::{Ast, Constant, tokenize as lexer, ParseError as PError},
|
||||
types::{TaggedType, TypeTag, Type, PrimitiveType},
|
||||
};
|
||||
use lalrpop_util::ParseError;
|
||||
|
||||
grammar;
|
||||
|
||||
extern {
|
||||
type Location = usize;
|
||||
type Error = PError;
|
||||
|
||||
enum lexer::Token {
|
||||
Nat => lexer::Token::Nat(<usize>),
|
||||
Float => lexer::Token::Float(<f64>),
|
||||
Bool => lexer::Token::Bool(<bool>),
|
||||
|
||||
Ident => lexer::Token::Ident(<String>),
|
||||
|
||||
r"\" => lexer::Token::Lambda,
|
||||
"=>" => lexer::Token::FatArrow,
|
||||
"->" => lexer::Token::ThinArrow,
|
||||
":" => lexer::Token::Colon,
|
||||
"." => lexer::Token::Period,
|
||||
|
||||
"=" => lexer::Token::Equals,
|
||||
"<>" => lexer::Token::NotEquals,
|
||||
"+" => lexer::Token::Plus,
|
||||
"-" => lexer::Token::Minus,
|
||||
"*" => lexer::Token::Star,
|
||||
"/" => lexer::Token::Slash,
|
||||
"^" => lexer::Token::Hat,
|
||||
"<" => lexer::Token::Less,
|
||||
">" => lexer::Token::Greater,
|
||||
"<=" => lexer::Token::LessEq,
|
||||
">=" => lexer::Token::GreaterEq,
|
||||
r"/\" => lexer::Token::Conjunction,
|
||||
r"\/" => lexer::Token::Disjunction,
|
||||
|
||||
"(" => lexer::Token::ParenOpen,
|
||||
")" => lexer::Token::ParenClose,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub Ast: Ast = {
|
||||
Term => <>,
|
||||
r"\" <x:Ident> ":" <t:TaggedType> "." <ast:Ast> => Ast::Abstraction(x, t, Box::new(ast)),
|
||||
};
|
||||
|
||||
|
||||
Term: Ast = {
|
||||
#[precedence(level="0")]
|
||||
Ident => Ast::Variable(<>),
|
||||
#[precedence(level="0")]
|
||||
Constant => Ast::Constant(<>),
|
||||
#[precedence(level="1")]
|
||||
"(" <Ast> ")" => <>,
|
||||
#[precedence(level="2")] #[assoc(side = "left")]
|
||||
<lhs:Term> <rhs:Term> => Ast::Application(Box::new(lhs), Box::new(rhs)),
|
||||
};
|
||||
|
||||
Constant: Constant = {
|
||||
Nat => Constant::Nat(<>),
|
||||
Float => Constant::Float(<>),
|
||||
Bool => Constant::Bool(<>),
|
||||
};
|
||||
|
||||
pub TaggedType: TaggedType = {
|
||||
<t:TypeTag> <i:Ident> "=>" <tt:TaggedType> => TaggedType::Tagged(t, i, Box::new(tt)),
|
||||
<t:Type> => TaggedType::Concrete(t),
|
||||
};
|
||||
|
||||
TypeTag: TypeTag = Ident =>? TypeTag::try_from(<>).map_err(|e| ParseError::User{ error: e });
|
||||
|
||||
Type: Type = { BasicType, ArrowType };
|
||||
|
||||
BasicType: Type = Ident => Type::from_name(<>);
|
||||
|
||||
ArrowType: Type = {
|
||||
#[precedence(level="0")]
|
||||
"(" <l:Type> ")" "->" <r:Type> => Type::Arrow(Box::new(l), Box::new(r)),
|
||||
#[precedence(level="1")] #[assoc(side = "right")]
|
||||
<l:BasicType> "->" <r:Type> => Type::Arrow(Box::new(l), Box::new(r)),
|
||||
};
|
||||
|
Loading…
Reference in new issue