use std::str::FromStr;
use super::*;
grammar;
pub Module: Module = {
<imports:Import*> <items:Item*> => Module {
imports,
items,
},
<AnonymousItem> => Module {
imports: Default::default(),
items: vec![<>],
}
}
Import: Import = {
imp <path:Path> => Import {
path
}
};
Path: String = {
<start:@L> (identifier "::")+ identifier <end:@R> => input[start..end].to_string(),
};
Item: Item = {
<NativeItem> => Item::Native(<>),
<ExternalItem> => Item::External(<>),
}
ExternalItems: Vec<ExternalItem> = {
ext "{" <items:ExternalItem*> "}" => <>,
}
ExternalItem: ExternalItem = {
pub_ ext fn_ <field:Identifier> "(" <parameters:ParameterNameTypes> ")" "->" <ret:TypeExpr> ";" => {
let (parameter_names, parameter_typs) : (Vec<_>, Vec<_>)= if parameters.is_empty() {
(vec!["_".to_string()],vec![TypeExpr::Unit])
} else {
parameters.into_iter().unzip()
};
ExternalItem {
symbol: Symbol {
module: "".to_string(),
field,
},
typ: FunctionType {
parameter_names,
parameter_typs,
ret: Box::new(ret),
},
}
},
};
NativeItem: NativeItem = {
pub_ fn_ <name:Identifier> "(" <parameters:ParameterNameTypes> ")" "->" <ret:TypeExpr> "{" <body:Expr> "}" => {
let (names, types) : (Vec<_>, Vec<_>)= if parameters.is_empty() {
(vec!["_".to_string()],vec![TypeExpr::Unit])
} else {
parameters.into_iter().unzip()
};
NativeItem {
symbol: Symbol {
module: "".to_string(),
field: name,
},
function: Function {
parameters: names.clone(),
body: Box::new(body),
},
typ: FunctionType {
parameter_names: names,
parameter_typs: types,
ret: Box::new(ret),
},
}
},
};
AnonymousItem: Item = {
//TODO make this unparse correctly
<body:Expr> => Item::Native(NativeItem {
symbol: Symbol{ module:"".to_string(), field: "main".to_string() },
function: Function {
parameters: vec!["_".to_string()],
body: Box::new(body),
},
typ: FunctionType {
parameter_names: vec!["_".to_string()],
parameter_typs: vec![TypeExpr::Unit],
ret: Box::new(TypeExpr::Var("_".to_string())),
},
}),
};
pub Expr: Expr = {
let_ <pattern:Pattern> "=" <init:Expr> ";" <body:Expr> => Expr::Let{
pattern,
init: Box::new(init),
body: Box::new(body),
},
fn_ "(" <parameters:ParameterNames> ")" "=>" <body:Expr> => Expr::Function (Function {
parameters,
body: Box::new(body),
}),
ForwardExpr,
};
ForwardExpr = {
<parameter:ForwardExpr> ">>" <call:ApplicationExpr> => Expr::Forward{
parameter: Box::new(parameter),
call: Box::new(call),
},
ArithExpr,
};
// Left associative binary operator rule
BinaryTier<Op,NextTier>: Expr = {
<left:BinaryTier<Op,NextTier>> <op:Op> <right:NextTier> => Expr::Binary {
left: Box::new(left),
op,
right: Box::new(right),
},
NextTier,
};
ArithExpr = BinaryTier<ArithOp, FactorExpr>;
FactorExpr = BinaryTier<FactorOp, ConcatExpr>;
ConcatExpr = BinaryTier<ConcatOp, ApplicationExpr>;
ArithOp: BinaryOperator = {
"+" => BinaryOperator::Addition,
"-" => BinaryOperator::Subtraction,
};
FactorOp: BinaryOperator = {
"*" => BinaryOperator::Multiplication,
"/" => BinaryOperator::Division,
};
ConcatOp: BinaryOperator = {
".." => BinaryOperator::Concat,
};
ApplicationExpr = {
<function:ApplicationExpr> "(" <parameters:Exprs> ")" => Expr::Application {
function: Box::new(function),
parameters,
},
Term,
};
Field = {
<Identifier> ":" <Expr>,
};
Fields = Comma<Field>;
Exprs = Comma<Expr>;
Term: Expr = {
Int,
Float,
ItemExpr,
Variable,
StringLiteral,
Variant,
Match,
<record:Term> "." <label:Identifier> => Expr::RecordSelect {
record: Box::new(record),
label,
},
//"[" <Exprs> "]" => Expr::List(List{values:<>}),
"{" <Fields> "}" => Expr::Record{fields:<>},
"(" <Expr> ")" => Expr::Parenthesized(Box::new(<>)),
};
Int: Expr = {
number => Expr::Integer(i64::from_str(<>).unwrap())
};
Float: Expr = {
decimal_number => Expr::Float(f64::from_str(<>).unwrap())
};
ItemExpr: Expr = {
<path:Path> => {
let (module, field) = path.rsplit_once("::").unwrap();
Expr::Item(Symbol{
module: module.to_string(),
field: field.to_string(),
})
}
};
Variable: Expr = {
Identifier => Expr::Variable(<>)
};
Identifier: String = {
identifier => <>.to_string(),
};
StringLiteral: Expr = {
string => Expr::String(<>[1..<>.len()-1].to_string()),
};
Variant: Expr = {
<lbl:Label> "(" <expr:Expr> ")" => Expr::Variant(lbl, Box::new(expr)),
};
Match: Expr = {
match_ <expr:Expr> "{" <cases:Comma<MatchCase>> "}" => Expr::Match(Box::new(expr), cases),
};
MatchCase = {
<Pattern> "=>" <Expr>,
};
Pattern: Pattern ={
<ident:Identifier> => Pattern::Identifier(ident),
<lbl:Label> "(" <p:Pattern> ")" => Pattern::Variant(lbl, Box::new(p)),
};
Label: String = {
label => <>.to_string(),
};
Delimited<T,D>: Vec<T> = {
<mut v:(<T> D)*> <e:T?> => match e {
None => v,
Some(e) => {
v.push(e);
v
}
}
};
Comma<T> = Delimited<T, ",">;
ParameterNames = Comma<Identifier>;
ParameterNameTypes = Comma<ParameterWithType>;
ParameterWithType: (String,TypeExpr) = {
<name:Identifier> ":" <type_expr:TypeExpr> => (
name,
type_expr,
),
};
TypeExpr: TypeExpr = {
// TODO Remove these keywords for named types
"unit" => TypeExpr::Unit,
"i64" => TypeExpr::Int,
"f64" => TypeExpr::Float,
"string" => TypeExpr::String,
"DataFrame" => TypeExpr::DataFrame,
"'" <identifier> => TypeExpr::Var(<>.to_string()),
"{" <ProdType> "}" => TypeExpr::Prod(Row{ fields: <> }),
"[" <SumType> "]" => TypeExpr::Sum(Row{ fields: <> }),
<name:Identifier> "=" <typ:TypeExpr> => TypeExpr::Nominal(name, Box::new(typ)),
};
ProdType = Comma<FielType>;
FielType = {
<Identifier> ":" <TypeExpr>,
};
SumType = Delimited<VariantType, "|">;
VariantType: (String, TypeExpr) = {
<lbl:label> <typ:TypeExpr> => (lbl.to_string(), typ)
};
String: String = {
string => <>.to_string()
}
match {
"extern" => ext,
"pub" => pub_,
"import" => imp,
"fn" => fn_,
"let" => let_,
"match" => match_,
r"[0-9]+" => number,
r"[0-9]+\.[0-9]+" => decimal_number,
_
} else {
r"`[a-zA-Z0-9_]+" => label,
} else {
r"[a-zA-Z0-9_]+" => identifier,
} else {
r#""[^"]*""# => string,
}