use crate::types::*;
use lalrpop_util::ParseError;
use std::collections::VecDeque;
use std::io::Read;
use std::str::FromStr;
grammar;
match {
"+", "-", "*", "/", "%", "&", "^", "|", "<<", ">>", "!",
"==", "!=", "<", ">", "<=", ">=", "&&", "||",
"=", "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=",
"...", "$", ":",
"(", ")", "{", "}", "[", "]",
r"[a-zA-Z_.][a-zA-Z0-9_.]*" => identifier,
r#""([^"]|\.)*""# => string,
r"-?[0-9]+" => number,
";", ",",
"env", "use", "include", "def", "alias", "macro", "pool", "const",
"return", "yield", "typedef", "struct", "ptr",
"if", "else", "while", "do", "for", "repeat", "loop",
r"#asm[^#]*#end" => raw_assembly,
// Skip whitespace and comments
r"\s*" => { },
r"//[^\n\r]*[\n\r]*" => { }, // `// comment`
r"/\*([^*]|\*[^/])*\*/" => { }, // `/* comment */`
}
pub File = { <Root*> }
Root: Root = {
<start:@L> <environment:Iden> <name:Iden> <end:@L> "{" <contents:Statement*> "}" => {
Root::Function( name, Function { environment, contents, start, end } )
},
"env" <name:Iden> "{" <contents:Statement*> "}" => {
Root::Environment( name, Environment { contents } )
},
raw_assembly =>? {
let mut bytes = <>.bytes().collect::<VecDeque<u8>>();
bytes.pop_front();
bytes.pop_front();
bytes.pop_front();
bytes.pop_front();
bytes.pop_back();
bytes.pop_back();
bytes.pop_back();
bytes.pop_back();
let mut result = String::new();
bytes.read_to_string(&mut result)
.map_err(|err| ParseError::User {
error: "Invalid UTF8"
})?;
Ok(Root::Assembly(result))
},
"include" <path:String> ";" => Root::Include(path),
"typedef" <name:Iden> "=" <t:Iden> ";" => Root::Typedef { name, t },
"struct" <name:Iden> "{" <contents:Comma<StructMember>> "}" => Root::Struct { name, contents },
}
StructMember: StructMember = {
<name:Iden> ":" <t:Iden> => StructMember { name, t },
}
Statement: Statement = {
<start:@L> "def" <name:Iden> "(" <args:Comma<DefinitionParam>> ")" <end:@R> ";" => {
Statement { t: StatementType::Definition(name, Definition::Def(Def { args, bytecode: 0 })), start, end }
},
<start:@L> "alias" <name:Iden> "(" <args:Comma<DefinitionParam>> ")" "=" <target:Iden> "(" <target_args:Comma<AliasParam>> ")" <end:@R> ";" => {
Statement { t: StatementType::Definition(name, Definition::Alias(Alias { args, target, target_args })), start, end }
},
<start:@L> "macro" <name:Iden> "(" <args:Comma<DefinitionParam>> ")" "=" <target:Iden> <end:@R> ";" => {
Statement { t: StatementType::Definition(name, Definition::Macro(Macro { args, target })), start, end }
},
<start:@L> "use" <env:Iden> <end:@R> ";" => Statement { t: StatementType::Use(env), start, end },
<start:@L> "pool" "=" <expr:Expr> <end:@R> ";" => Statement { t: StatementType::Pool(expr), start, end },
<start:@L> <expr:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(expr), start, end },
<start:@L> <t:Iden> <i:Iden> <end:@R> ";" => Statement { t: StatementType::Declaration(t, i), start, end },
<start:@L> <t:Iden> "ptr" <i:Iden> <end:@R> ";" => Statement { t: StatementType::PointerDeclaration(t, i), start, end },
<start:@L> <t:Iden> <l:Iden> "=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::DeclareAssign(t, l, r), start, end },
<start:@L> <t:Iden> "ptr" <l:Iden> "=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::PointerDeclareAssign(t, l, r), start, end },
Assignment,
IfContainer,
<start:@L> "while" <cond:Expr> <end:@R> "{" <contents:Statement*> "}" => Statement { t: StatementType::While(cond, contents), start, end },
"do" "{" <contents:Statement*> "}" <start:@L> "while" <cond:Expr> <end:@R> ";" => Statement { t: StatementType::Do(cond, contents), start, end },
<start:@L> "for" <pro:Statement> <cond:Expr> ";" <epi:Statement> <end:@R> "{" <contents:Statement*> "}" => Statement { t: StatementType::For(Box::new(pro), cond, Box::new(epi), contents), start, end },
<start:@L> "repeat" <cond:Expr> <end:@R> "{" <contents:Statement*> "}" => Statement { t: StatementType::Repeat(cond, contents), start, end },
<start:@L> "loop" <end:@R> "{" <contents:Statement*> "}" => Statement { t: StatementType::Loop(contents), start, end },
<start:@L> "return" <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Call(String::from("ret"), vec![])), start, end },
<start:@L> "yield" <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Call(String::from("yld"), vec![])), start, end },
}
DefinitionParam: DefinitionParam = {
"return" <i:Iden> => DefinitionParam::Return(i),
"const" <i:Iden> => DefinitionParam::Const(i),
Iden => DefinitionParam::Type(<>),
}
AliasParam: AliasParam = {
"$" <i:number> =>? Ok(AliasParam::ArgId(usize::from_str(i)
.map_err(|_| ParseError::User {
error: "Argument index is too large"
})?)),
Expr => AliasParam::Expression(<>),
"const" <expr:Expr> => AliasParam::Const(expr),
}
IfContainer: Statement = {
<start:@L> "if" <cond:Expr> <end:@R> "{" <contents:Statement*> "}" => Statement { t: StatementType::If(cond, contents, None), start, end },
<start:@L> "if" <cond:Expr> <end:@R> "{" <contents:Statement*> "}" "else" "{" <else_contents:Statement*> "}" => Statement { t: StatementType::If(cond, contents, Some(else_contents)), start, end },
<start:@L> "if" <cond:Expr> <end:@R> "{" <contents:Statement*> "}" "else" <else_contents:IfContainer> => Statement { t: StatementType::If(cond, contents, Some(vec![else_contents])), start, end },
}
Assignment: Statement = {
<start:@L> <l:Iden> "=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l, Box::new(r))), start, end },
<start:@L> <l:Iden> "+=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::Add(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "-=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::Sub(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "*=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::Mul(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "/=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::Div(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "%=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::Mod(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "&=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::BinaryAnd(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "|=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::BinaryOr(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "^=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::BinaryXor(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> "<<=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::ShiftLeft(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
<start:@L> <l:Iden> ">>=" <r:Expr> <end:@R> ";" => Statement { t: StatementType::Expression(Rpn::Set(l.clone(), Box::new(Rpn::ShiftRight(Box::new(Rpn::Variable(l)), Box::new(r))))), start, end },
}
Expr = { LogicalOr }
LogicalOr: Rpn = {
<l:LogicalOr> "||" <r:LogicalAnd> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l != 0 || r != 0) as i64);
}
}
Rpn::LogicalOr(Box::new(l), Box::new(r))
},
LogicalAnd,
}
LogicalAnd: Rpn = {
<l:LogicalAnd> "&&" <r:Compare> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l != 0 && r != 0) as i64);
}
}
Rpn::LogicalAnd(Box::new(l), Box::new(r))
},
Compare,
}
Compare: Rpn = {
<l:Compare> "==" <r:BinaryOr> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l == r) as i64);
}
}
Rpn::Equ(Box::new(l), Box::new(r))
},
<l:Compare> "!=" <r:BinaryOr> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l != r) as i64);
}
}
Rpn::NotEqu(Box::new(l), Box::new(r))
},
<l:Compare> "<" <r:BinaryOr> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l < r) as i64);
}
}
Rpn::LessThan(Box::new(l), Box::new(r))
},
<l:Compare> "<=" <r:BinaryOr> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l <= r) as i64);
}
}
Rpn::LessThanEqu(Box::new(l), Box::new(r))
},
<l:Compare> ">" <r:BinaryOr> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l > r) as i64);
}
}
Rpn::GreaterThan(Box::new(l), Box::new(r))
},
<l:Compare> ">=" <r:BinaryOr> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed((l >= r) as i64);
}
}
Rpn::GreaterThanEqu(Box::new(l), Box::new(r))
},
BinaryOr,
}
BinaryOr: Rpn = {
<l:BinaryOr> "|" <r:BinaryXor> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l | r);
}
}
Rpn::BinaryOr(Box::new(l), Box::new(r))
},
BinaryXor,
}
BinaryXor: Rpn = {
<l:BinaryAnd> "^" <r:BinaryAnd> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l ^ r);
}
}
Rpn::BinaryXor(Box::new(l), Box::new(r))
},
BinaryAnd,
}
BinaryAnd: Rpn = {
<l:BinaryAnd> "&" <r:Shift> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l & r);
}
}
Rpn::BinaryAnd(Box::new(l), Box::new(r))
},
Shift,
}
Shift: Rpn = {
<l:Shift> "<<" <r:Addition> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l << r);
}
}
Rpn::ShiftLeft(Box::new(l), Box::new(r))
},
<l:Shift> ">>" <r:Addition> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l >> r);
}
}
Rpn::ShiftRight(Box::new(l), Box::new(r))
},
Addition,
}
Addition: Rpn = {
<l:Addition> "+" <r:Factor> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l + r);
}
}
Rpn::Add(Box::new(l), Box::new(r))
},
<l:Addition> "-" <r:Factor> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l - r);
}
}
Rpn::Sub(Box::new(l), Box::new(r))
},
Factor,
};
Factor: Rpn = {
<l:Factor> "*" <r:Unary> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l * r);
}
}
Rpn::Mul(Box::new(l), Box::new(r))
},
<l:Factor> "/" <r:Unary> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l / r);
}
}
Rpn::Div(Box::new(l), Box::new(r))
},
<l:Factor> "%" <r:Unary> => {
if let Rpn::Signed(l) = l {
if let Rpn::Signed(r) = r {
return Rpn::Signed(l % r);
}
}
Rpn::Mod(Box::new(l), Box::new(r))
},
Unary,
};
Unary: Rpn = {
"-" <l:Term> => {
if let Rpn::Signed(i) = l {
return Rpn::Signed(-i)
}
Rpn::Negate(Box::new(l))
},
"!" <l:Term> => {
if let Rpn::Signed(i) = l {
return Rpn::Signed(!i)
}
Rpn::Not(Box::new(l))
},
"&" <l:Iden> => Rpn::Address(l),
Term,
};
Term: Rpn = {
Num,
String => Rpn::String(<>),
Iden => Rpn::Variable(<>),
"(" <Expr> ")",
"[" <e:Expr> "]" => Rpn::Deref(Box::new(e)),
<i:Iden> "(" <args:Comma<Expr>> ")" => Rpn::Call(i, args)
};
Num: Rpn = {
number =>? Ok(Rpn::Signed(i64::from_str(<>)
.map_err(|_| ParseError::User {
error: "Integer is too large (maximum of 64 bits, signed)"
})?)),
};
Iden: String = {
identifier => String::from(<>),
};
String: String = {
string =>? {
let mut bytes = <>.bytes().collect::<VecDeque<u8>>();
bytes.pop_front();
bytes.pop_back();
let mut result = String::new();
bytes.read_to_string(&mut result)
.map_err(|err| ParseError::User {
error: "Invalid UTF8"
})?;
Ok(result)
},
}
Comma<T>: Vec<T> = {
<mut v:(<T> ",")*> <e:T?> => match e {
None => v,
Some(e) => {
v.push(e);
v
}
}
};