use ast;
use parser;
use std::str::FromStr;
#[LALR]
grammar;
extern {
type Location = usize;
type Error = parser::Error;
}
#[inline]
Comma0<A>: Vec<A> = {
<v:(<A> ",")*> <e: A?> => {
let mut v = v;
v.extend(e);
v
},
}
#[inline]
Comma1<A>: Vec<A> = {
<v:(<A> ",")+> <e: A?> => {
let mut v = v;
v.extend(e);
v
},
}
#[inline]
Semi0<A>: Vec<A> = {
<v:(<A> ";")*> <e: A> => {
let mut v = v;
v.push(e);
v
},
}
#[inline]
SemiRequired0<A>: Vec<A> = {
<(<A> ";")*> => <>,
}
pub Module: ast::Module<parser::Context> = {
<lo:@L> <ds:SemiRequired0<(Comment? <Definition>)>> <hi:@R> =>
ast::Module { context: parser::Context::new(ast::Kind::Module, lo, hi), variables: ds },
}
Comment: () = {
r"/\*(\*[^/]|[^*])*\*/"=> ()
}
Definition: ast::Variable<parser::Context> = {
<lo:@L> <n:Identifier> "=" <i:Expression> <hi:@R> =>
ast::Variable { context: parser::Context::new(ast::Kind::Variable, lo, hi), name: n, initializer: i },
}
pub Expression = { <ExpressionBiOpOr> }
// Left-to-right evaluation
ExpressionBiOpOr: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpOr, BiOperatorOr, ExpressionBiOpXor> => ast::Expression::BiOp(<>),
ExpressionBiOpXor => <>,
}
// Left-to-right evaluation
ExpressionBiOpXor: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpXor, BiOperatorXor, ExpressionBiOpAnd> => ast::Expression::BiOp(<>),
ExpressionBiOpAnd => <>,
}
// Left-to-right evaluation
ExpressionBiOpAnd: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpAnd, BiOperatorAnd, ExpressionBiOpCmp> => ast::Expression::BiOp(<>),
ExpressionBiOpCmp => <>,
}
// No associativity; require parenthesis
ExpressionBiOpCmp: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpBOr, BiOperatorCmp, ExpressionBiOpBOr> => ast::Expression::BiOp(<>),
ExpressionBiOpBOr => <>,
}
// Left-to-right evaluation
ExpressionBiOpBOr: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpBOr, BiOperatorBOr, ExpressionBiOpBXor> => ast::Expression::BiOp(<>),
ExpressionBiOpBXor => <>,
}
// Left-to-right evaluation
ExpressionBiOpBXor: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpBXor, BiOperatorBXor, ExpressionBiOpBAnd> => ast::Expression::BiOp(<>),
ExpressionBiOpBAnd => <>,
}
// Left-to-right evaluation
ExpressionBiOpBAnd: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpBAnd, BiOperatorBAnd, ExpressionBiOpShift> => ast::Expression::BiOp(<>),
ExpressionBiOpShift => <>,
}
// Left-to-right evaluation
ExpressionBiOpShift: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpShift, BiOperatorShift, ExpressionBiOpSum> => ast::Expression::BiOp(<>),
ExpressionBiOpSum => <>,
}
// Left-to-right evaluation
ExpressionBiOpSum: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpSum, BiOperatorSum, ExpressionBiOpFactor> => ast::Expression::BiOp(<>),
ExpressionBiOpFactor => <>,
}
// Left-to-right evaluation
ExpressionBiOpFactor: ast::Expression<parser::Context> = {
BiOp<ExpressionBiOpFactor, BiOperatorFactor, ExpressionUnOp> => ast::Expression::BiOp(<>),
ExpressionUnOp => <>,
}
ExpressionUnOp: ast::Expression<parser::Context> = {
UnOp => ast::Expression::UnOp(<>),
ExpressionProjection => <>,
}
ExpressionProjection: ast::Expression<parser::Context> = {
Select => ast::Expression::Select(<>),
Apply => ast::Expression::Apply(<>),
ExpressionAtom => <>,
}
ExpressionAtom: ast::Expression<parser::Context> = {
Identifier => ast::Expression::Identifier(<>),
NumberLiteral => ast::Expression::NumberLiteral(<>),
StringLiteral => ast::Expression::StringLiteral(<>),
Tuple => ast::Expression::Tuple(<>),
Record => ast::Expression::Record(<>),
Lambda => ast::Expression::Lambda(<>),
"(" <Expression> ")" => <>,
}
UnOperator: ast::UnOperator = {
"!" => ast::UnOperator::Not,
"~!" => ast::UnOperator::BNot,
"#^0" => ast::UnOperator::Cl0,
"#^1" => ast::UnOperator::Cl1,
"#^-" => ast::UnOperator::Cls,
"#$0" => ast::UnOperator::Ct0,
"#$1" => ast::UnOperator::Ct1,
"#0" => ast::UnOperator::C0,
"#1" => ast::UnOperator::C1,
"^/" => ast::UnOperator::Sqrt,
}
UnOp: ast::UnOp<parser::Context> = {
<lo:@L> <operator:UnOperator> <operand:ExpressionUnOp> <hi:@R> =>
ast::UnOp { context: parser::Context::new(ast::Kind::UnOp, lo, hi), operator, operand: Box::new(operand) },
}
#[inline]
BiOp<L, O, R>: ast::BiOp<parser::Context> = {
<lo:@L> <lhs:L> <operator:O> <rhs:R> <hi:@R> =>
ast::BiOp { context: parser::Context::new(ast::Kind::BiOp, lo, hi), lhs: Box::new(lhs), operator, rhs: Box::new(rhs) },
}
BiOperatorFactor: ast::BiOperator = {
"*" => ast::BiOperator::Mul,
"/" => ast::BiOperator::Div,
"%" => ast::BiOperator::Rem,
}
BiOperatorSum: ast::BiOperator = {
"+" => ast::BiOperator::Add,
"-" => ast::BiOperator::Sub,
}
BiOperatorShift: ast::BiOperator = {
">->" => ast::BiOperator::RotL,
"<-<" => ast::BiOperator::RotR,
">>" => ast::BiOperator::ShL,
"<<" => ast::BiOperator::ShR,
}
BiOperatorBAnd: ast::BiOperator = {
"~&" => ast::BiOperator::BAnd,
"~&!" => ast::BiOperator::BAndNot,
}
BiOperatorBOr: ast::BiOperator = {
"~|" => ast::BiOperator::BOr,
"~|!" => ast::BiOperator::BOrNot,
}
BiOperatorBXor: ast::BiOperator = {
"~^" => ast::BiOperator::BXor,
"~^!" => ast::BiOperator::BXorNot,
}
BiOperatorAnd: ast::BiOperator = {
"&" => ast::BiOperator::And,
"&!" => ast::BiOperator::AndNot,
}
BiOperatorOr: ast::BiOperator = {
"|" => ast::BiOperator::Or,
"|!" => ast::BiOperator::OrNot,
}
BiOperatorXor: ast::BiOperator = {
"^" => ast::BiOperator::Xor,
"^!" => ast::BiOperator::XorNot,
}
BiOperatorCmp: ast::BiOperator = {
"==" => ast::BiOperator::Eq,
"!=" => ast::BiOperator::Ne,
"<" => ast::BiOperator::Lt,
">=" => ast::BiOperator::Ge,
">" => ast::BiOperator::Gt,
"<=" => ast::BiOperator::Le,
"<=>" => ast::BiOperator::Cmp,
}
Identifier: ast::Identifier<parser::Context> = {
<lo:@L> <id:r"\p{XID_Start}\p{XID_Continue}*"> <hi:@R> =>
ast::Identifier { context: parser::Context::new(ast::Kind::Identifier, lo, hi), value: id.into() },
}
Tuple: ast::Tuple<parser::Context> = {
<lo:@L> "(" ")" <hi:@R> =>
ast::Tuple { context: parser::Context::new(ast::Kind::Tuple, lo, hi), fields: vec![] },
<lo:@L> "(" <fs:Comma1<Expression>> ")" <hi:@R> =>
ast::Tuple { context: parser::Context::new(ast::Kind::Tuple, lo, hi), fields: fs },
}
Record: ast::Record<parser::Context> = {
<lo:@L> "{" <fs:Comma0<Field>> "}" <hi:@R> =>
ast::Record { context: parser::Context::new(ast::Kind::Record, lo, hi), fields: fs },
}
Field: (ast::Identifier<parser::Context>, ast::Expression<parser::Context>) = {
<Identifier> ":" <Expression> => (<>),
}
NumberLiteral: ast::NumberLiteral<parser::Context> = {
<lo:@L> <v:r"-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?(?:u8|u16|u32|u64|i8|i16|i32|i64|f32|f64)"> <hi:@R> =>
ast::NumberLiteral {
context: parser::Context::new(ast::Kind::NumberLiteral, lo, hi),
value: if v.ends_with("u8") {
ast::NumberValue::U8(u8::from_str(&v[..v.len() - 2]).unwrap())
} else if v.ends_with("u16") {
ast::NumberValue::U16(u16::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("u32") {
ast::NumberValue::U32(u32::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("u64") {
ast::NumberValue::U64(u64::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("i8") {
ast::NumberValue::I8(i8::from_str(&v[..v.len() - 2]).unwrap())
} else if v.ends_with("i16") {
ast::NumberValue::I16(i16::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("i32") {
ast::NumberValue::I32(i32::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("i64") {
ast::NumberValue::I64(i64::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("f32") {
ast::NumberValue::F32(f32::from_str(&v[..v.len() - 3]).unwrap())
} else if v.ends_with("f64") {
ast::NumberValue::F64(f64::from_str(&v[..v.len() - 3]).unwrap())
} else {
unreachable!()
}
},
}
StringLiteral: ast::StringLiteral<parser::Context> = {
<lo:@L> <v:r#""(?:[^"\\]|\\(?:["\\/bfnrt]|u\{[a-fA-F0-9]{1,6}\}))*""#> <hi:@R> =>
ast::StringLiteral { context: parser::Context::new(ast::Kind::StringLiteral, lo, hi), value: parser::util::parse_escaped_string(v).into_owned() },
}
Lambda: ast::Lambda<parser::Context> = {
<lo:@L> "|" <params:Comma0<(Comment? <Parameter>)>> "|" <sig:Expression?> "{" <stmts:SemiRequired0<(Comment? <Statement>)>> <res:(Comment? <Expression>)> "}" <hi:@R> =>
ast::Lambda { context: parser::Context::new(ast::Kind::Lambda, lo, hi), parameters: params, signature: sig.map(Box::new), statements: stmts, result: Box::new(res) },
}
Statement: ast::Statement<parser::Context> = {
<Definition> => ast::Statement::Variable(<>),
<Expression> => ast::Statement::Expression(<>),
}
Select: ast::Select<parser::Context> = {
<lo:@L> <r:ExpressionProjection> "." <f:Identifier> <hi:@R> =>
ast::Select { context: parser::Context::new(ast::Kind::Select, lo, hi), record: Box::new(r), field: f },
}
Apply: ast::Apply<parser::Context> = {
<lo:@L> <e:ExpressionProjection> "(" <p:Comma0<Expression>> ")" <hi:@R> =>
ast::Apply { context: parser::Context::new(ast::Kind::Apply, lo, hi), function: Box::new(e), parameters: p },
}
Parameter: ast::Parameter<parser::Context> = {
<lo:@L> <name:Identifier> <signature:(":" <ExpressionAtom>)?> <hi:@R> =>
ast::Parameter { context: parser::Context::new(ast::Kind::Parameter, lo, hi), name, signature },
}