use std::cmp::min;
use std::vec::Vec;
use crate::ast::BinOpKind::*;
use crate::ast::BuilderKind::*;
use crate::ast::ExprKind::*;
use crate::ast::IterKind::*;
use crate::ast::LiteralKind::*;
use crate::ast::Type::*;
use crate::ast::UnaryOpKind::*;
use crate::ast::*;
use crate::error::*;
use crate::util::colors::*;
use super::program::*;
use super::tokenizer::Token::*;
use super::tokenizer::*;
use std::error::Error;
#[cfg(test)]
use crate::tests::{print_expr_without_indent, print_typed_expr_without_indent};
macro_rules! check_parse_error {
($parser:expr, $res:expr) => {{
if $res.is_ok() && !$parser.is_done() {
return compile_err!(
"Unexpected token {} at {}",
$parser.peek(),
$parser.error_context()
);
} else if $res.is_err() {
return compile_err!(
"{} (at {})",
$res.unwrap_err().description(),
$parser.error_context()
);
} else {
$res
}
}};
}
pub fn parse_program(input: &str) -> WeldResult<Program> {
let tokens = tokenize(input)?;
let mut parser = Parser::new(&tokens);
let res = parser.program();
check_parse_error!(parser, res)
}
pub fn parse_macros(input: &str) -> WeldResult<Vec<Macro>> {
let tokens = tokenize(input)?;
let mut parser = Parser::new(&tokens);
let res = parser.macros();
check_parse_error!(parser, res)
}
pub fn parse_type_aliases(input: &str) -> WeldResult<Vec<TypeAlias>> {
let tokens = tokenize(input)?;
let mut parser = Parser::new(&tokens);
let res = parser.type_aliases();
check_parse_error!(parser, res)
}
pub fn parse_expr(input: &str) -> WeldResult<Expr> {
let tokens = tokenize(input)?;
let mut parser = Parser::new(&tokens);
let res = parser.expr().map(|b| *b);
check_parse_error!(parser, res)
}
pub fn parse_type(input: &str) -> WeldResult<Type> {
let tokens = tokenize(input)?;
let mut parser = Parser::new(&tokens);
let res = parser.type_();
check_parse_error!(parser, res)
}
struct Parser<'t> {
tokens: &'t [Token],
position: usize,
}
impl<'t> Parser<'t> {
fn new(tokens: &[Token]) -> Parser<'_> {
Parser {
tokens,
position: 0,
}
}
fn peek(&self) -> &'t Token {
&self.tokens[self.position]
}
fn error_context(&self) -> String {
let length = 10;
let mut string = String::from("");
let context_length = if self.position >= length {
string.push_str("...");
length
} else {
self.position
};
for i in (self.position - context_length)
..min(self.position + context_length, self.tokens.len() - 1)
{
let token_str = format!("{}", &self.tokens[i]);
if i == self.position {
string.push_str(format_color(Color::BoldRed, token_str.as_str()).as_str());
} else {
string.push_str(&token_str);
}
if i != self.position - 1
&& self.tokens[i + 1].requires_space()
&& self.tokens[i].requires_space()
{
string.push_str(" ");
}
}
if self.position != self.tokens.len() {
string.push_str("...");
}
string
}
fn next(&mut self) -> &'t Token {
let token = &self.tokens[self.position];
self.position += 1;
token
}
fn consume(&mut self, expected: Token) -> WeldResult<()> {
if *self.next() != expected {
compile_err!("Expected '{}'", expected)
} else {
Ok(())
}
}
fn is_done(&self) -> bool {
self.position == self.tokens.len() || *self.peek() == TEndOfInput
}
fn program(&mut self) -> WeldResult<Program> {
let type_aliases = self.type_aliases()?;
let macros = self.macros()?;
let body = self.expr()?;
Ok(Program {
macros,
type_aliases,
body: *body,
})
}
fn macros(&mut self) -> WeldResult<Vec<Macro>> {
let mut res: Vec<Macro> = Vec::new();
while *self.peek() == TMacro {
res.push(self.macro_()?);
}
Ok(res)
}
fn macro_(&mut self) -> WeldResult<Macro> {
self.consume(TMacro)?;
let name = self.symbol()?;
let mut params: Vec<Symbol> = Vec::new();
self.consume(TOpenParen)?;
while *self.peek() != TCloseParen {
params.push(self.symbol()?);
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TCloseParen {
return compile_err!("Expected ',' or ')'");
}
}
self.consume(TCloseParen)?;
self.consume(TEqual)?;
let body = self.expr()?;
self.consume(TSemicolon)?;
Ok(Macro {
name,
parameters: params,
body: *body,
})
}
fn type_aliases(&mut self) -> WeldResult<Vec<TypeAlias>> {
let mut res: Vec<TypeAlias> = Vec::new();
while *self.peek() == TType {
res.push(self.type_alias_()?);
}
Ok(res)
}
fn type_alias_(&mut self) -> WeldResult<TypeAlias> {
self.consume(TType)?;
let name = self.symbol()?;
self.consume(TEqual)?;
let ty = self.type_()?;
self.consume(TSemicolon)?;
Ok(TypeAlias {
name: name.to_string(),
ty,
})
}
fn expr(&mut self) -> WeldResult<Box<Expr>> {
if *self.peek() == TLet {
self.let_expr()
} else if *self.peek() == TBar || *self.peek() == TLogicalOr {
self.lambda_expr()
} else {
self.operator_expr()
}
}
fn let_expr(&mut self) -> WeldResult<Box<Expr>> {
self.consume(TLet)?;
let name = self.symbol()?;
let ty = self.optional_type()?;
self.consume(TEqual)?;
let mut value = self.operator_expr()?;
if ty != Unknown {
value.ty = ty;
}
self.consume(TSemicolon)?;
let body = self.expr()?;
let expr = expr_box(Let { name, value, body }, Annotations::new());
Ok(expr)
}
fn lambda_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut params: Vec<Parameter> = Vec::new();
let token = self.next();
if *token == TBar {
while *self.peek() != TBar {
let name = self.symbol()?;
let ty = self.optional_type()?;
params.push(Parameter { name, ty });
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TBar {
return compile_err!("Expected ',' or '|'");
}
}
self.consume(TBar)?;
} else if *token != TLogicalOr {
return compile_err!("Expected '|' or '||'");
}
let body = self.expr()?;
Ok(expr_box(Lambda { params, body }, Annotations::new()))
}
fn operator_expr(&mut self) -> WeldResult<Box<Expr>> {
self.logical_or_expr()
}
fn logical_or_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.logical_and_expr()?;
while *self.peek() == TLogicalOr {
self.consume(TLogicalOr)?;
let right = self.logical_and_expr()?;
res = expr_box(
BinOp {
kind: LogicalOr,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn logical_and_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.bitwise_or_expr()?;
while *self.peek() == TLogicalAnd {
self.consume(TLogicalAnd)?;
let right = self.bitwise_or_expr()?;
res = expr_box(
BinOp {
kind: LogicalAnd,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn bitwise_or_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.xor_expr()?;
while *self.peek() == TBar {
self.consume(TBar)?;
let right = self.xor_expr()?;
res = expr_box(
BinOp {
kind: BitwiseOr,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn xor_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.bitwise_and_expr()?;
while *self.peek() == TXor {
self.consume(TXor)?;
let right = self.bitwise_and_expr()?;
res = expr_box(
BinOp {
kind: Xor,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn bitwise_and_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.equality_expr()?;
while *self.peek() == TBitwiseAnd {
self.consume(TBitwiseAnd)?;
let right = self.equality_expr()?;
res = expr_box(
BinOp {
kind: BitwiseAnd,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn equality_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.comparison_expr()?;
if *self.peek() == TEqualEqual || *self.peek() == TNotEqual {
let token = self.next();
let right = self.comparison_expr()?;
if *token == TEqualEqual {
res = expr_box(
BinOp {
kind: Equal,
left: res,
right,
},
Annotations::new(),
)
} else {
res = expr_box(
BinOp {
kind: NotEqual,
left: res,
right,
},
Annotations::new(),
)
}
}
Ok(res)
}
fn comparison_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.sum_expr()?;
if *self.peek() == TLessThan
|| *self.peek() == TLessThanOrEqual
|| *self.peek() == TGreaterThan
|| *self.peek() == TGreaterThanOrEqual
{
let op = match *self.next() {
TLessThan => LessThan,
TGreaterThan => GreaterThan,
TLessThanOrEqual => LessThanOrEqual,
_ => GreaterThanOrEqual,
};
let right = self.sum_expr()?;
res = expr_box(
BinOp {
kind: op,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn sum_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.product_expr()?;
while *self.peek() == TPlus || *self.peek() == TMinus {
let token = self.next();
let right = self.product_expr()?;
if *token == TPlus {
res = expr_box(
BinOp {
kind: Add,
left: res,
right,
},
Annotations::new(),
)
} else {
res = expr_box(
BinOp {
kind: Subtract,
left: res,
right,
},
Annotations::new(),
)
}
}
Ok(res)
}
fn product_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut res = self.ascribe_expr()?;
while *self.peek() == TTimes || *self.peek() == TDivide || *self.peek() == TModulo {
let op = match *self.next() {
TTimes => Multiply,
TDivide => Divide,
_ => Modulo,
};
let right = self.ascribe_expr()?;
res = expr_box(
BinOp {
kind: op,
left: res,
right,
},
Annotations::new(),
)
}
Ok(res)
}
fn ascribe_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut expr = self.apply_expr()?;
if *self.peek() == TColon {
expr.ty = self.optional_type()?;
}
Ok(expr)
}
fn apply_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut expr = self.leaf_expr()?;
while *self.peek() == TDot || *self.peek() == TOpenParen {
if *self.next() == TDot {
match *self.next() {
TIdent(ref value) => {
if value.starts_with('$') {
match u32::from_str_radix(&value[1..], 10) {
Ok(index) => {
expr = expr_box(GetField { expr, index }, Annotations::new())
}
_ => {
return compile_err!(
"Expected field index but got '{}'",
value
);
}
}
}
}
ref other => return compile_err!("Expected field index but got '{}'", other),
}
} else {
let mut params: Vec<Expr> = Vec::new();
while *self.peek() != TCloseParen {
let param = self.expr()?;
params.push(*param);
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TCloseParen {
return compile_err!("Expected ',' or ')'");
}
}
self.consume(TCloseParen)?;
expr = expr_box(Apply { func: expr, params }, Annotations::new())
}
}
Ok(expr)
}
fn parse_iter(&mut self) -> WeldResult<Iter> {
let iter: Token = self.peek().clone();
match iter {
TScalarIter | TSimdIter | TFringeIter | TNdIter => {
self.consume(iter.clone())?;
self.consume(TOpenParen)?;
let data = self.expr()?;
let (mut start, mut end, mut stride, mut shape, mut strides) =
(None, None, None, None, None);
if *self.peek() == TComma {
self.consume(TComma)?;
start = Some(self.expr()?);
self.consume(TComma)?;
end = Some(self.expr()?);
self.consume(TComma)?;
stride = Some(self.expr()?);
}
if iter == TNdIter && *self.peek() == TComma {
self.consume(TComma)?;
shape = Some(self.expr()?);
self.consume(TComma)?;
strides = Some(self.expr()?);
}
let iter = Iter {
data,
start,
end,
stride,
kind: match iter {
TSimdIter => SimdIter,
TFringeIter => FringeIter,
TNdIter => NdIter,
_ => ScalarIter,
},
shape,
strides,
};
self.consume(TCloseParen)?;
Ok(iter)
}
TRangeIter => {
self.consume(iter)?;
self.consume(TOpenParen)?;
let start = self.expr()?;
self.consume(TComma)?;
let end = self.expr()?;
self.consume(TComma)?;
let stride = self.expr()?;
let mut dummy_data = expr_box(MakeVector { elems: vec![] }, Annotations::new());
dummy_data.as_mut().ty = Vector(Box::new(Scalar(ScalarKind::I64)));
let iter = Iter {
data: dummy_data,
start: Some(start),
end: Some(end),
stride: Some(stride),
kind: RangeIter,
shape: None,
strides: None,
};
self.consume(TCloseParen)?;
Ok(iter)
}
_ => {
let data = self.expr()?;
let iter = Iter {
data,
start: None,
end: None,
stride: None,
kind: match iter {
TSimdIter => SimdIter,
TFringeIter => FringeIter,
TNdIter => NdIter,
TRangeIter => RangeIter,
_ => ScalarIter,
},
shape: None,
strides: None,
};
Ok(iter)
}
}
}
fn parse_cast(&mut self, kind: ScalarKind) -> WeldResult<Box<Expr>> {
if *self.next() != TOpenParen {
return compile_err!("Expected '('");
}
let child_expr = self.expr()?;
if *self.next() != TCloseParen {
return compile_err!("Expected ')'");
}
let cast_expr = expr_box(Cast { kind, child_expr }, Annotations::new());
Ok(cast_expr)
}
fn parse_annotations(&mut self, annotations: &mut Annotations) -> WeldResult<()> {
if *self.peek() == TAtMark {
self.consume(TAtMark)?;
self.consume(TOpenParen)?;
while *self.peek() != TCloseParen {
let key = self.symbol()?;
self.consume(TColon)?;
let value = match *self.peek() {
TI32Literal(ref v) => v.to_string(),
TI64Literal(ref v) => v.to_string(),
TF32Literal(ref v) => v.to_string(),
TF64Literal(ref v) => v.to_string(),
TI16Literal(ref v) => v.to_string(),
TI8Literal(ref v) => v.to_string(),
TBoolLiteral(ref v) => v.to_string(),
TStringLiteral(ref v) => v.clone(),
TIdent(ref v) => v.clone(),
_ => {
return compile_err!(
"Annotation value must be a literal or identifier/string"
);
}
};
let token = self.peek().clone();
self.consume(token)?;
annotations.set(key.to_string(), value);
if *self.peek() == TComma {
self.consume(TComma)?;
} else if *self.peek() != TCloseParen {
return compile_err!("Expected ',' or ')'");
}
}
self.consume(TCloseParen)?;
}
Ok(())
}
fn unary_op_kind_for_token(&self, token: Token) -> WeldResult<UnaryOpKind> {
let kind = match token {
TExp => Exp,
TLog => Log,
TSqrt => Sqrt,
TErf => Erf,
TSin => Sin,
TCos => Cos,
TTan => Tan,
TASin => ASin,
TACos => ACos,
TATan => ATan,
TSinh => Sinh,
TCosh => Cosh,
TTanh => Tanh,
_ => {
return compile_err!("Invalid token for UnaryOp");
}
};
Ok(kind)
}
fn unary_leaf_expr(&mut self, token: Token) -> WeldResult<Box<Expr>> {
self.consume(TOpenParen)?;
let value = self.expr()?;
self.consume(TCloseParen)?;
let kind = self.unary_op_kind_for_token(token)?;
Ok(expr_box(UnaryOp { kind, value }, Annotations::new()))
}
fn leaf_expr(&mut self) -> WeldResult<Box<Expr>> {
let mut annotations = Annotations::new();
self.parse_annotations(&mut annotations)?;
match *self.next() {
TI16Literal(v) => Ok(expr_box(Literal(I16Literal(v)), Annotations::new())),
TI8Literal(v) => Ok(expr_box(Literal(I8Literal(v)), Annotations::new())),
TI32Literal(v) => Ok(expr_box(Literal(I32Literal(v)), Annotations::new())),
TI64Literal(v) => Ok(expr_box(Literal(I64Literal(v)), Annotations::new())),
TF32Literal(v) => Ok(expr_box(
Literal(F32Literal(v.to_bits())),
Annotations::new(),
)),
TF64Literal(v) => Ok(expr_box(
Literal(F64Literal(v.to_bits())),
Annotations::new(),
)),
TBoolLiteral(v) => Ok(expr_box(Literal(BoolLiteral(v)), Annotations::new())),
TStringLiteral(ref v) => Ok(expr_box(
Literal(StringLiteral(v.clone())),
Annotations::new(),
)),
TI8 => Ok(self.parse_cast(ScalarKind::I8)?),
TI16 => Ok(self.parse_cast(ScalarKind::I16)?),
TI32 => Ok(self.parse_cast(ScalarKind::I32)?),
TI64 => Ok(self.parse_cast(ScalarKind::I64)?),
TU8 => Ok(self.parse_cast(ScalarKind::U8)?),
TU16 => Ok(self.parse_cast(ScalarKind::U16)?),
TU32 => Ok(self.parse_cast(ScalarKind::U32)?),
TU64 => Ok(self.parse_cast(ScalarKind::U64)?),
TF32 => Ok(self.parse_cast(ScalarKind::F32)?),
TF64 => Ok(self.parse_cast(ScalarKind::F64)?),
TBool => Ok(self.parse_cast(ScalarKind::Bool)?),
TToVec => {
self.consume(TOpenParen)?;
let child_expr = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(ToVec { child_expr }, Annotations::new()))
}
TIdent(ref name) => Ok(expr_box(
Ident(Symbol::new(name.as_str(), 0)),
Annotations::new(),
)),
TOpenParen => {
let expr = self.expr()?;
if *self.next() != TCloseParen {
return compile_err!("Expected ')' after {:?}", expr);
}
Ok(expr)
}
TOpenBracket => {
let mut exprs: Vec<Expr> = Vec::new();
while *self.peek() != TCloseBracket {
let expr = self.expr()?;
exprs.push(*expr);
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TCloseBracket {
return compile_err!("Expected ',' or ']'");
}
}
self.consume(TCloseBracket)?;
Ok(expr_box(MakeVector { elems: exprs }, Annotations::new()))
}
TOpenBrace => {
let mut exprs: Vec<Expr> = Vec::new();
while *self.peek() != TCloseBrace {
let expr = self.expr()?;
exprs.push(*expr);
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TCloseBrace {
return compile_err!("Expected ',' or '}}'");
}
}
self.consume(TCloseBrace)?;
Ok(expr_box(MakeStruct { elems: exprs }, Annotations::new()))
}
TIf => {
self.consume(TOpenParen)?;
let cond = self.expr()?;
self.consume(TComma)?;
let on_true = self.expr()?;
self.consume(TComma)?;
let on_false = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(
If {
cond,
on_true,
on_false,
},
annotations,
))
}
TIterate => {
self.consume(TOpenParen)?;
let initial = self.expr()?;
self.consume(TComma)?;
let update_func = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(
Iterate {
initial,
update_func,
},
Annotations::new(),
))
}
TSelect => {
self.consume(TOpenParen)?;
let cond = self.expr()?;
self.consume(TComma)?;
let on_true = self.expr()?;
self.consume(TComma)?;
let on_false = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(
Select {
cond,
on_true,
on_false,
},
Annotations::new(),
))
}
TBroadcast => {
self.consume(TOpenParen)?;
let expr = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Broadcast(expr), Annotations::new()))
}
TSerialize => {
self.consume(TOpenParen)?;
let expr = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Serialize(expr), Annotations::new()))
}
TDeserialize => {
self.consume(TOpenBracket)?;
let value_ty = self.type_()?;
self.consume(TCloseBracket)?;
self.consume(TOpenParen)?;
let value = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(
Deserialize {
value_ty: Box::new(value_ty),
value,
},
annotations,
))
}
TCUDF => {
let mut args = vec![];
self.consume(TOpenBracket)?;
let sym_name = self.symbol()?;
self.consume(TComma)?;
let return_ty = self.type_()?;
self.consume(TCloseBracket)?;
self.consume(TOpenParen)?;
while *self.peek() != TCloseParen {
let arg = self.expr()?;
args.push(*arg);
if *self.peek() == TComma {
self.consume(TComma)?;
}
}
self.consume(TCloseParen)?;
Ok(expr_box(
CUDF {
sym_name: sym_name.name(),
return_ty: Box::new(return_ty),
args,
},
annotations,
))
}
TZip => {
self.consume(TOpenParen)?;
let mut vectors = vec![];
while *self.peek() != TCloseParen {
let vector = self.expr()?;
vectors.push(*vector);
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TCloseParen {
return compile_err!("Expected ',' or ')'");
}
}
self.consume(TCloseParen)?;
if vectors.len() < 2 {
return compile_err!("Expected two or more arguments in Zip");
}
Ok(expr_box(Zip { vectors }, Annotations::new()))
}
TFor => {
self.consume(TOpenParen)?;
let mut iters = vec![];
if *self.peek() == TZip {
self.consume(TZip)?;
self.consume(TOpenParen)?;
iters.push(self.parse_iter()?);
while *self.peek() == TComma {
self.consume(TComma)?;
iters.push(self.parse_iter()?);
}
self.consume(TCloseParen)?;
} else {
iters.push(self.parse_iter()?);
}
self.consume(TComma)?;
let builder = self.expr()?;
self.consume(TComma)?;
let body = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(
For {
iters,
builder,
func: body,
},
annotations,
))
}
TLen => {
self.consume(TOpenParen)?;
let data = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Length { data }, Annotations::new()))
}
TLookup => {
self.consume(TOpenParen)?;
let data = self.expr()?;
self.consume(TComma)?;
let index = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Lookup { data, index }, Annotations::new()))
}
TOptLookup => {
self.consume(TOpenParen)?;
let data = self.expr()?;
self.consume(TComma)?;
let index = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(OptLookup { data, index }, Annotations::new()))
}
TKeyExists => {
self.consume(TOpenParen)?;
let data = self.expr()?;
self.consume(TComma)?;
let key = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(KeyExists { data, key }, Annotations::new()))
}
TSlice => {
self.consume(TOpenParen)?;
let data = self.expr()?;
self.consume(TComma)?;
let index = self.expr()?;
self.consume(TComma)?;
let size = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Slice { data, index, size }, Annotations::new()))
}
TSort => {
self.consume(TOpenParen)?;
let data = self.expr()?;
self.consume(TComma)?;
let cmpfunc = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Sort { data, cmpfunc }, Annotations::new()))
}
TExp => self.unary_leaf_expr(TExp),
TLog => self.unary_leaf_expr(TLog),
TErf => self.unary_leaf_expr(TErf),
TSqrt => self.unary_leaf_expr(TSqrt),
TSin => self.unary_leaf_expr(TSin),
TCos => self.unary_leaf_expr(TCos),
TTan => self.unary_leaf_expr(TTan),
TASin => self.unary_leaf_expr(TASin),
TACos => self.unary_leaf_expr(TACos),
TATan => self.unary_leaf_expr(TATan),
TSinh => self.unary_leaf_expr(TSinh),
TCosh => self.unary_leaf_expr(TCosh),
TTanh => self.unary_leaf_expr(TTanh),
TMerge => {
self.consume(TOpenParen)?;
let builder = self.expr()?;
self.consume(TComma)?;
let value = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Merge { builder, value }, Annotations::new()))
}
TResult => {
self.consume(TOpenParen)?;
let value = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Res { builder: value }, Annotations::new()))
}
TAppender => {
let mut elem_type = Unknown;
if *self.peek() == TOpenBracket {
self.consume(TOpenBracket)?;
elem_type = self.type_()?;
self.consume(TCloseBracket)?;
}
let arg = if *self.peek() == TOpenParen {
self.consume(TOpenParen)?;
let arg = self.expr()?;
self.consume(TCloseParen)?;
Some(arg)
} else {
None
};
let mut expr = expr_box(NewBuilder(arg), Annotations::new());
expr.ty = Builder(Appender(Box::new(elem_type)), annotations);
Ok(expr)
}
TMerger => {
let elem_type: Type;
self.consume(TOpenBracket)?;
elem_type = self.type_()?;
self.consume(TComma)?;
let bin_op = self.commutative_binop_()?;
self.consume(TCloseBracket)?;
let mut value = None;
if *self.peek() == TOpenParen {
self.consume(TOpenParen)?;
value = Some(self.expr()?);
self.consume(TCloseParen)?;
}
let mut expr = expr_box(NewBuilder(value), Annotations::new());
expr.ty = Builder(Merger(Box::new(elem_type), bin_op), annotations);
Ok(expr)
}
TDictMerger => {
let key_type: Type;
let value_type: Type;
self.consume(TOpenBracket)?;
key_type = self.type_()?;
self.consume(TComma)?;
value_type = self.type_()?;
self.consume(TComma)?;
let bin_op = self.commutative_binop_()?;
self.consume(TCloseBracket)?;
let arg = if *self.peek() == TOpenParen {
self.consume(TOpenParen)?;
let arg = self.expr()?;
self.consume(TCloseParen)?;
Some(arg)
} else {
None
};
let mut expr = expr_box(NewBuilder(arg), Annotations::new());
expr.ty = Builder(
DictMerger(Box::new(key_type), Box::new(value_type), bin_op),
annotations,
);
Ok(expr)
}
TGroupMerger => {
let key_type: Type;
let value_type: Type;
self.consume(TOpenBracket)?;
key_type = self.type_()?;
self.consume(TComma)?;
value_type = self.type_()?;
self.consume(TCloseBracket)?;
let mut expr = expr_box(NewBuilder(None), Annotations::new());
expr.ty = Builder(
GroupMerger(Box::new(key_type), Box::new(value_type)),
annotations,
);
Ok(expr)
}
TVecMerger => {
let elem_type: Type;
self.consume(TOpenBracket)?;
elem_type = self.type_()?;
self.consume(TComma)?;
let bin_op = self.commutative_binop_()?;
self.consume(TCloseBracket)?;
self.consume(TOpenParen)?;
let expr = self.expr()?;
self.consume(TCloseParen)?;
let mut expr = expr_box(NewBuilder(Some(expr)), Annotations::new());
expr.ty = Builder(VecMerger(Box::new(elem_type), bin_op), annotations);
Ok(expr)
}
TMinus => Ok(expr_box(Negate(self.leaf_expr()?), Annotations::new())),
TBang => Ok(expr_box(Not(self.leaf_expr()?), Annotations::new())),
TAssert => {
self.consume(TOpenParen)?;
let cond = self.expr()?;
self.consume(TCloseParen)?;
Ok(expr_box(Assert(cond), Annotations::new()))
}
TMin => {
self.consume(TOpenParen)?;
let left = self.expr()?;
self.consume(TComma)?;
let right = self.expr()?;
self.consume(TCloseParen)?;
let res = expr_box(
BinOp {
kind: Min,
left,
right,
},
Annotations::new(),
);
Ok(res)
}
TMax => {
self.consume(TOpenParen)?;
let left = self.expr()?;
self.consume(TComma)?;
let right = self.expr()?;
self.consume(TCloseParen)?;
let res = expr_box(
BinOp {
kind: Max,
left,
right,
},
Annotations::new(),
);
Ok(res)
}
TPow => {
self.consume(TOpenParen)?;
let left = self.expr()?;
self.consume(TComma)?;
let right = self.expr()?;
self.consume(TCloseParen)?;
let res = expr_box(
BinOp {
kind: Pow,
left,
right,
},
Annotations::new(),
);
Ok(res)
}
ref other => compile_err!("Expected expression but got '{}'", other),
}
}
fn symbol(&mut self) -> WeldResult<Symbol> {
match *self.next() {
TIdent(ref name) => Ok(Symbol::new(name.as_str(), 0)),
ref other => compile_err!("Expected identifier but got {}", other.to_string()),
}
}
fn optional_type(&mut self) -> WeldResult<Type> {
if *self.peek() == TColon {
self.consume(TColon)?;
self.type_()
} else {
Ok(Unknown)
}
}
fn commutative_binop_(&mut self) -> WeldResult<BinOpKind> {
match *self.peek() {
TPlus => {
self.consume(TPlus)?;
Ok(Add)
}
TTimes => {
self.consume(TTimes)?;
Ok(Multiply)
}
TMax => {
self.consume(TMax)?;
Ok(Max)
}
TMin => {
self.consume(TMin)?;
Ok(Min)
}
ref t => compile_err!("expected commutative binary op in but got '{}'", t),
}
}
fn type_(&mut self) -> WeldResult<Type> {
let mut annotations = Annotations::new();
self.parse_annotations(&mut annotations)?;
if !self.peek().signals_type() {
let name = self.symbol()?.to_string();
return Ok(Alias(name, Box::new(Unknown)));
}
match *self.next() {
TI8 => Ok(Scalar(ScalarKind::I8)),
TI16 => Ok(Scalar(ScalarKind::I16)),
TI32 => Ok(Scalar(ScalarKind::I32)),
TI64 => Ok(Scalar(ScalarKind::I64)),
TU8 => Ok(Scalar(ScalarKind::U8)),
TU16 => Ok(Scalar(ScalarKind::U16)),
TU32 => Ok(Scalar(ScalarKind::U32)),
TU64 => Ok(Scalar(ScalarKind::U64)),
TF32 => Ok(Scalar(ScalarKind::F32)),
TF64 => Ok(Scalar(ScalarKind::F64)),
TBool => Ok(Scalar(ScalarKind::Bool)),
TVec => {
self.consume(TOpenBracket)?;
let elem_type = self.type_()?;
self.consume(TCloseBracket)?;
Ok(Vector(Box::new(elem_type)))
}
TSimd => {
self.consume(TOpenBracket)?;
let elem_type = self.type_()?;
self.consume(TCloseBracket)?;
if let Scalar(ref kind) = elem_type {
Ok(Simd(*kind))
} else {
compile_err!("Expected Scalar type in simd")
}
}
TAppender => {
self.consume(TOpenBracket)?;
let elem_type = self.type_()?;
self.consume(TCloseBracket)?;
Ok(Builder(Appender(Box::new(elem_type)), annotations))
}
TMerger => {
let elem_type: Type;
self.consume(TOpenBracket)?;
elem_type = self.type_()?;
self.consume(TComma)?;
let binop = self.commutative_binop_()?;
self.consume(TCloseBracket)?;
Ok(Builder(Merger(Box::new(elem_type), binop), annotations))
}
TDict => {
let key_type: Type;
let value_type: Type;
self.consume(TOpenBracket)?;
key_type = self.type_()?;
self.consume(TComma)?;
value_type = self.type_()?;
self.consume(TCloseBracket)?;
Ok(Dict(Box::new(key_type), Box::new(value_type)))
}
TDictMerger => {
let key_type: Type;
let value_type: Type;
self.consume(TOpenBracket)?;
key_type = self.type_()?;
self.consume(TComma)?;
value_type = self.type_()?;
self.consume(TComma)?;
let binop = self.commutative_binop_()?;
self.consume(TCloseBracket)?;
Ok(Builder(
DictMerger(Box::new(key_type), Box::new(value_type), binop),
annotations,
))
}
TGroupMerger => {
self.consume(TOpenBracket)?;
let key_type = self.type_()?;
self.consume(TComma)?;
let value_type = self.type_()?;
self.consume(TCloseBracket)?;
let group_merger = GroupMerger(Box::new(key_type), Box::new(value_type));
Ok(Builder(group_merger, annotations))
}
TVecMerger => {
let elem_type: Type;
self.consume(TOpenBracket)?;
elem_type = self.type_()?;
self.consume(TComma)?;
let binop = self.commutative_binop_()?;
self.consume(TCloseBracket)?;
Ok(Builder(VecMerger(Box::new(elem_type), binop), annotations))
}
TOpenBrace => {
let mut types: Vec<Type> = Vec::new();
while *self.peek() != TCloseBrace {
let ty = self.type_()?;
types.push(ty);
if *self.peek() == TComma {
self.next();
} else if *self.peek() != TCloseBrace {
return compile_err!("Expected ',' or '}}'");
}
}
self.consume(TCloseBrace)?;
Ok(Struct(types))
}
TQuestion => Ok(Unknown),
ref other => compile_err!("Expected type but got '{}'", other),
}
}
}
#[test]
fn basic_parsing() {
let e = parse_expr("10 - 2 - 3 + 1").unwrap();
assert_eq!(print_expr_without_indent(&e), "(((10-2)-3)+1)");
let e = parse_expr("10 * 2 - 4 - 3 / 1").unwrap();
assert_eq!(print_expr_without_indent(&e), "(((10*2)-4)-(3/1))");
let e = parse_expr("i32(10 + 3 + 2)").unwrap();
assert_eq!(print_expr_without_indent(&e), "(i32(((10+3)+2)))");
let e = parse_expr("10 + 64 + i32(10.0)").unwrap();
assert_eq!(print_expr_without_indent(&e), "((10+64)+(i32(10.0)))");
let e = parse_expr("10 + 64 + f32(bool(19))").unwrap();
assert_eq!(print_expr_without_indent(&e), "((10+64)+(f32((bool(19)))))");
let e = parse_expr("1L:i64 + i64(1)").unwrap();
assert_eq!(print_expr_without_indent(&e), "(1L+(i64(1)))");
let e = parse_expr("i64(1L:i64)").unwrap();
assert_eq!(print_expr_without_indent(&e), "(i64(1L))");
let e = parse_expr("[1, 2+3, 2]").unwrap();
assert_eq!(print_expr_without_indent(&e), "[1,(2+3),2]");
let e = parse_expr("let a = 3+2; let b = (let c=a; c); b").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"(let a=((3+2));(let b=((let c=(a);c));b))"
);
let e = parse_expr("let a: vec[i32] = [2, 3]; a").unwrap();
assert_eq!(print_expr_without_indent(&e), "(let a=([2,3]);a)");
let e = parse_expr("|a, b:i32| a+b").unwrap();
assert_eq!(print_typed_expr_without_indent(&e), "|a:?,b:i32|(a:?+b:?)");
let e = parse_expr("|| a||b").unwrap();
assert_eq!(print_expr_without_indent(&e), "||(a||b)");
let e = parse_expr("a.$0.$1").unwrap();
assert_eq!(print_expr_without_indent(&e), "a.$0.$1");
let e = parse_expr("a(0,1).$0").unwrap();
assert_eq!(print_expr_without_indent(&e), "(a)(0,1).$0");
let e = parse_expr("a.$0(0,1).$1()").unwrap();
assert_eq!(print_expr_without_indent(&e), "((a.$0)(0,1).$1)()");
let e = parse_expr("a>b==c").unwrap();
assert_eq!(print_expr_without_indent(&e), "((a>b)==c)");
assert!(parse_expr("a>b>c").is_err());
assert!(parse_expr("a==b==c").is_err());
let e = parse_expr("appender[?]").unwrap();
assert_eq!(print_expr_without_indent(&e), "appender[?]");
let e = parse_expr("appender[i32]").unwrap();
assert_eq!(print_expr_without_indent(&e), "appender[i32]");
let e = parse_expr("appender[i32](1000L)").unwrap();
assert_eq!(print_expr_without_indent(&e), "appender[i32](1000L)");
let e = parse_expr("@(impl:local) dictmerger[i32,i32,+]").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"@(impl:local)dictmerger[i32,i32,+]"
);
let e = parse_expr("@(impl:local, num_keys:12l) dictmerger[i32,i32,+]").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"@(impl:local,num_keys:12)dictmerger[i32,i32,+]"
);
let e = parse_expr("a: i32 + b").unwrap();
assert_eq!(print_typed_expr_without_indent(&e), "(a:i32+b:?)");
let e = parse_expr("|a:i8| a").unwrap();
assert_eq!(print_typed_expr_without_indent(&e), "|a:i8|a:?");
assert!(parse_expr("10 * * 2").is_err());
let p = parse_program("macro a(x) = x+x; macro b() = 5; a(b)").unwrap();
assert_eq!(p.macros.len(), 2);
assert_eq!(print_expr_without_indent(&p.body), "(a)(b)");
assert_eq!(print_expr_without_indent(&p.macros[0].body), "(x+x)");
assert_eq!(print_expr_without_indent(&p.macros[1].body), "5");
let t = &parse_type("{i32, vec[vec[?]], ?}").unwrap().to_string();
assert_eq!(t, "{i32,vec[vec[?]],?}");
let t = &parse_type("{}").unwrap().to_string();
assert_eq!(t, "{}");
}
#[test]
fn operator_precedence() {
let e = parse_expr("a - b - c - d").unwrap();
assert_eq!(print_expr_without_indent(&e), "(((a-b)-c)-d)");
let e = parse_expr("a || b && c | d ^ e & f == g > h + i * j").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"(a||(b&&(c|(d^(e&(f==(g>(h+(i*j)))))))))"
);
let e = parse_expr("a * b + c > d == e & f ^ g | h && i || j").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"(((((((((a*b)+c)>d)==e)&f)^g)|h)&&i)||j)"
);
let e = parse_expr("a / b - c <= d != e & f ^ g | h && i || j").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"(((((((((a/b)-c)<=d)!=e)&f)^g)|h)&&i)||j)"
);
let e = parse_expr("a % b - c >= d != e & f ^ g | h && i || j").unwrap();
assert_eq!(
print_expr_without_indent(&e),
"(((((((((a%b)-c)>=d)!=e)&f)^g)|h)&&i)||j)"
);
}
#[test]
fn read_to_end_of_input() {
assert!(parse_expr("a + b").is_ok());
assert!(parse_expr("a + b macro").is_err());
assert!(parse_type("vec[i32]").is_ok());
assert!(parse_expr("vec[i32] 1").is_err());
assert!(parse_program("macro a() = b; a() + b").is_ok());
assert!(parse_program("macro a() = b; a() + b;").is_err());
}
#[test]
fn parse_and_print_literal_expressions() {
let tests = vec![
("23", "23"),
("0b111", "7"),
("0xff", "255"),
("23L", "23L"),
("7L", "7L"),
("0xffL", "255L"),
("23.0", "23.0"),
("23.5", "23.5"),
("23e5", "2300000.0"),
("23.5e5", "2350000.0"),
("23.0f", "23.0F"),
("23.5f", "23.5F"),
("23e5f", "2300000.0F"),
("23.5e5f", "2350000.0F"),
("true", "true"),
("false", "false"),
];
for test in tests {
let e = parse_expr(test.0).unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), test.1);
}
assert!(parse_expr("999999999999999").is_err()); assert!(parse_expr("999999999999999L").is_ok());
assert!(parse_expr("999999999999999999999999999999L").is_err()); }
#[test]
fn parse_and_print_simple_expressions() {
let e = parse_expr("23 + 32").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "(23+32)");
let e = parse_expr("2 - 3 - 4").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "((2-3)-4)");
let e = parse_expr("2 - (3 - 4)").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "(2-(3-4))");
let e = parse_expr("a").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "a");
let e = parse_expr("let a = 2; a").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "(let a=(2);a)");
let e = parse_expr("let a = 2.0; a").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "(let a=(2.0);a)");
let e = parse_expr("[1, 2, 3]").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "[1,2,3]");
let e = parse_expr("[1.0, 2.0, 3.0]").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "[1.0,2.0,3.0]");
let e = parse_expr("|a, b| a + b").unwrap();
assert_eq!(print_expr_without_indent(&e).as_str(), "|a:?,b:?|(a+b)");
let e = parse_expr("for(d, appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(d,appender[?],|e|(e+1))"
);
}
#[test]
fn parse_and_print_for_expressions() {
let e = parse_expr("for(d, appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(d,appender[?],|e|(e+1))"
);
let e = parse_expr("for(iter(d), appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(d,appender[?],|e|(e+1))"
);
let e = parse_expr("for(iter(d,0L,4L,1L), appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(iter(d,0L,4L,1L),appender[?],|e|(e+1))"
);
let e = parse_expr("for(zip(d), appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(d,appender[?],|e|(e+1))"
);
let e = parse_expr("for(zip(d,e), appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(zip(d,e),appender[?],|e|(e+1))"
);
let e = parse_expr("for(zip(a,b,iter(c,0L,4L,1L),iter(d)), appender, |e| e+1)").unwrap();
assert_eq!(
print_expr_without_indent(&e).as_str(),
"for(zip(a,b,iter(c,0L,4L,1L),d),appender[?],|e|(e+1))"
);
}