use crate::{Identifier, tir::{TirProgram, TirDeclaration, TirStructure, TirFunction, TirExpression, TirConstant, TirStatement, TirType}};
grammar;
pub Program: TirProgram = <(Declaration)*> => TirProgram::new(<>, 512);
Declaration: TirDeclaration = {
"#" "[" "header" "(" <Str> ")" "]" => TirDeclaration::DocumentHeader(<>),
"#" "[" "std" "]" => TirDeclaration::RequireStd,
"#" "[" "no_std" "]" => TirDeclaration::NoStd,
"#" "[" "assert" "(" <Constant> ")" "]" => TirDeclaration::Assert(<>),
"#" "[" "extern" "(" <Str> ")" "]" => TirDeclaration::Extern(<>),
"#" "[" "include" "(" <Str> ")" "]" => TirDeclaration::Include(<>),
"#" "[" "memory" "(" <Num> ")" "]" => TirDeclaration::Memory(<> as i32),
"#" "[" "error" "(" <Str> ")" "]" => TirDeclaration::Error(<>),
"#" "[" "if" "(" <cond:Constant> ")" "{" <code:Program> "}" "]" => TirDeclaration::If(cond, code),
"#" "[" "if" "(" <cond:Constant> ")" "{" <then_code:Program> "}" "else" "{" <else_code:Program> "}" "]" => TirDeclaration::IfElse(cond, then_code, else_code),
"#" "[" "define" "(" <name:Str> "," <constant:Constant> ")" "]" => TirDeclaration::Constant(None, name, constant),
"#" "[" "doc" "(" <doc:Str> ")" "]" "const" <name:Ident> "=" <constant:Constant> ";" => TirDeclaration::Constant(Some(doc), name, constant),
"const" <name:Ident> "=" <constant:Constant> ";" => TirDeclaration::Constant(None, name, constant),
<Function> => TirDeclaration::Function(<>),
<Structure> => TirDeclaration::Structure(<>),
}
Str: String = <s:r#""(\\.|[^"])*""#> => String::from(&s[1..s.len()-1]).replace("\\\"", "\"").replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t").replace("\\0", "\0");
Char: char = <s:r#"'(\\.|[^'])'"#> => s.replace("\\'", "'").replace("\\n", "\n").replace("\\r", "\r").replace("\\t", "\t").replace("\\0", "\0").chars().nth(1).unwrap() as char;
Num: f64 = {
// r"([0-9]+([.][0-9]*)?|[.][0-9]+)" => <>.to_string().parse::<f64>().unwrap(),
r"([1-9][0-9]*|[0])([.][0-9]+)?" => <>.to_string().parse::<f64>().unwrap(),
}
Ident: Identifier = {
<head:(r"[a-zA-Z_][a-zA-Z0-9_]*" "::")*> <tail:r"[a-zA-Z_][a-zA-Z0-9_]*"> => {
let mut result = String::new();
for (a, b) in head {
result += a;
result += b;
}
result += tail;
result
}
}
List<Begin, T, Sep, End>: Vec<T> = {
<first:Begin> <list: (<T> <Sep>)*> <end:T?> <last:End> => {
match end {
None => list.iter().map(|(v, s)| v.clone()).collect(),
Some(val) => {
let mut list: Vec<_> = list.iter().map(|(v, s)| v.clone()).collect();
list.push(val);
list
}
}
}
}
Constant: TirConstant = {
<cond:ConstantMathBottom> "?" <then:Constant> ":" <otherwise:Constant> => TirConstant::Conditional(Box::new(cond), Box::new(then), Box::new(otherwise)),
<ConstantMathBottom> => <>
}
ConstantAtom: TirConstant = {
"is_movable" "(" <Type> ")" => TirConstant::IsMovable(<>),
"sizeof" "(" <Type> ")" => TirConstant::SizeOf(<>),
"is_defined" "(" <Str> ")" => TirConstant::IsDefined(<>),
"true" => TirConstant::True,
"false" => TirConstant::False,
<Ident> => TirConstant::Constant(<>),
<Num> => TirConstant::Float(<>),
<Char> => TirConstant::Character(<>),
"-" <ConstantAtom> => TirConstant::Subtract(Box::new(TirConstant::Float(0.0)), Box::new(<>)),
"!" <ConstantAtom> => TirConstant::Not(Box::new(<>))
}
ConstantMathBottom: TirConstant = {
<l:ConstantMathLow> "&&" <r:ConstantMathLow> => TirConstant::And(Box::new(l), Box::new(r)),
<l:ConstantMathLow> "||" <r:ConstantMathLow> => TirConstant::Or(Box::new(l), Box::new(r)),
<ConstantMathLow> => <>
}
ConstantMathLow: TirConstant = {
<l:ConstantMathMiddle> "==" <r:ConstantMathMiddle> => TirConstant::Equal(Box::new(l), Box::new(r)),
<l:ConstantMathMiddle> "!=" <r:ConstantMathMiddle> => TirConstant::NotEqual(Box::new(l), Box::new(r)),
<l:ConstantMathMiddle> ">=" <r:ConstantMathMiddle> => TirConstant::GreaterEqual(Box::new(l), Box::new(r)),
<l:ConstantMathMiddle> ">" <r:ConstantMathMiddle> => TirConstant::Greater(Box::new(l), Box::new(r)),
<l:ConstantMathMiddle> "<=" <r:ConstantMathMiddle> => TirConstant::LessEqual(Box::new(l), Box::new(r)),
<l:ConstantMathMiddle> "<" <r:ConstantMathMiddle> => TirConstant::Less(Box::new(l), Box::new(r)),
<ConstantMathMiddle> => <>
}
ConstantMathMiddle: TirConstant = {
<l:ConstantMathHigh> "+" <r:ConstantMathHigh> => TirConstant::Add(Box::new(l), Box::new(r)),
<l:ConstantMathHigh> "-" <r:ConstantMathHigh> => TirConstant::Subtract(Box::new(l), Box::new(r)),
<ConstantMathHigh> => <>
}
ConstantMathHigh: TirConstant = {
<l:ConstantAtom> "*" <r:ConstantAtom> => TirConstant::Multiply(Box::new(l), Box::new(r)),
<l:ConstantAtom> "/" <r:ConstantAtom> => TirConstant::Divide(Box::new(l), Box::new(r)),
<ConstantAtom> => <>
}
Function: TirFunction = {
"#" "[" "doc" "(" <doc:Str> ")" "]" "fn" <name:Ident> <args:List<"(", (Ident ":" Type), ",", ")">> <body:Body> => TirFunction::new(Some(doc), name, args.iter().map(|(a, _, t)| (a.clone(), t.clone())).collect(), TirType::Void, body),
"#" "[" "doc" "(" <doc:Str> ")" "]" "fn" <name:Ident> <args:List<"(", (Ident ":" Type), ",", ")">> "->" <return_type:Type> <body:Body> => TirFunction::new(Some(doc), name, args.iter().map(|(a, _, t)| (a.clone(), t.clone())).collect(), return_type, body),
"fn" <name:Ident> <args:List<"(", (Ident ":" Type), ",", ")">> <body:Body> => TirFunction::new(None, name, args.iter().map(|(a, _, t)| (a.clone(), t.clone())).collect(), TirType::Void, body),
"fn" <name:Ident> <args:List<"(", (Ident ":" Type), ",", ")">> "->" <return_type:Type> <body:Body> => TirFunction::new(None, name, args.iter().map(|(a, _, t)| (a.clone(), t.clone())).collect(), return_type, body),
}
Structure: TirStructure = {
"#" "[" "doc" "(" <doc:Str> ")" "]" "struct" <name:Ident> "{" <members: List<"let", (Ident ":" Type), ",", ";">> <methods:Function*> "}" => TirStructure::new(Some(doc), name, members.iter().map(|(a, _, t)| (a.clone(), t.clone())).collect(), methods),
"struct" <name:Ident> "{" <members: List<"let", (Ident ":" Type), ",", ";">> <methods:Function*> "}" => TirStructure::new(None, name, members.iter().map(|(a, _, t)| (a.clone(), t.clone())).collect(), methods),
}
Body: Vec<TirStatement> = "{" <head: Statement*> <tail: SmallStatement?> "}" => {
let mut result = Vec::new();
for stmt in head { result.push(stmt) }
if let Some(stmt) = tail { result.push(stmt) }
result
};
Type: TirType = {
"&" <Type> => TirType::Pointer(Box::new(<>)),
"&&" <Type> => TirType::Pointer(Box::new(TirType::Pointer(Box::new(<>)))),
"void" => TirType::Void,
"num" => TirType::Float,
"bool" => TirType::Boolean,
"char" => TirType::Character,
<Ident> => TirType::Structure(<>)
}
Statement: TirStatement = {
<BodyStatement> => <>,
<SmallStatement> ";" => <>
}
BodyStatement: TirStatement = {
"for" "(" <pre:SmallStatement> ";" <cond:Expression> ";" <post:SmallStatement> ")" <body:Body> => TirStatement::For(Box::new(pre), cond, Box::new(post), body),
"for" <var:Ident> "in" <from:Expression> ".." <to:Expression> <body:Body> => TirStatement::ForRange(var, from, to, body),
"while" <cond:Expression> <body:Body> => TirStatement::While(cond, body),
"if" <cond:Expression> <body:Body> => TirStatement::If(cond, body),
"if" <cond:Expression> <then_body:Body> "else" <else_body:Body> => TirStatement::IfElse(cond, then_body, else_body),
"if" <cond:Expression> <then_body:Body> <elifs:("else" "if" Expression Body)+> "else" <else_body:Body> => {
TirStatement::IfElifElse(cond, then_body, elifs.iter().map(|(_, _, cond, body)| (cond.clone(), body.clone())).collect(), else_body)
},
}
SmallStatement: TirStatement = {
"return" <exprs:List<"[", Expression, ",", "]">> => TirStatement::Return(exprs),
"return" <expr:Expression> => TirStatement::Return(vec![expr]),
"free" <addr:Expression> ":" <size:Expression> => TirStatement::Free(addr, size),
"let" <name:Ident> "=" <expr:Expression> => TirStatement::AutoDefine(name, expr),
"let" <name:Ident> ":" <t:Type> "=" <expr:Expression> => TirStatement::Define(name, t, expr),
<name:Ident> "=" <expr:Expression> => TirStatement::AssignVariable(name, expr),
<name:Ident> "+=" <expr:Expression> => TirStatement::AddAssignVariable(name, expr),
<name:Ident> "-=" <expr:Expression> => TirStatement::SubtractAssignVariable(name, expr),
<name:Ident> "*=" <expr:Expression> => TirStatement::MultiplyAssignVariable(name, expr),
<name:Ident> "/=" <expr:Expression> => TirStatement::DivideAssignVariable(name, expr),
"*" <lhs:Expression> "=" <rhs:Expression> => TirStatement::AssignAddress(lhs, rhs),
"*" <lhs:Expression> "+=" <rhs:Expression> => TirStatement::AddAssignAddress(lhs, rhs),
"*" <lhs:Expression> "-=" <rhs:Expression> => TirStatement::SubtractAssignAddress(lhs, rhs),
"*" <lhs:Expression> "*=" <rhs:Expression> => TirStatement::MultiplyAssignAddress(lhs, rhs),
"*" <lhs:Expression> "/=" <rhs:Expression> => TirStatement::DivideAssignAddress(lhs, rhs),
<ptr:ExpressionAtom> "[" <idx:Expression> "]" "=" <rhs:Expression> => TirStatement::AssignAddress(TirExpression::Index(Box::new(ptr), Box::new(idx)), rhs),
<ptr:ExpressionAtom> "[" <idx:Expression> "]" "+=" <rhs:Expression> => TirStatement::AddAssignAddress(TirExpression::Index(Box::new(ptr), Box::new(idx)), rhs),
<ptr:ExpressionAtom> "[" <idx:Expression> "]" "-=" <rhs:Expression> => TirStatement::SubtractAssignAddress(TirExpression::Index(Box::new(ptr), Box::new(idx)), rhs),
<ptr:ExpressionAtom> "[" <idx:Expression> "]" "*=" <rhs:Expression> => TirStatement::MultiplyAssignAddress(TirExpression::Index(Box::new(ptr), Box::new(idx)), rhs),
<ptr:ExpressionAtom> "[" <idx:Expression> "]" "/=" <rhs:Expression> => TirStatement::DivideAssignAddress(TirExpression::Index(Box::new(ptr), Box::new(idx)), rhs),
<instance:ExpressionAtom> "->" <name:Ident> "=" <rhs:Expression> => TirStatement::AssignAddress(TirExpression::Method(Box::new(instance), name, vec![]), rhs),
<instance:ExpressionAtom> "->" <name:Ident> "+=" <rhs:Expression> => TirStatement::AddAssignAddress(TirExpression::Method(Box::new(instance), name, vec![]), rhs),
<instance:ExpressionAtom> "->" <name:Ident> "-=" <rhs:Expression> => TirStatement::SubtractAssignAddress(TirExpression::Method(Box::new(instance), name, vec![]), rhs),
<instance:ExpressionAtom> "->" <name:Ident> "*=" <rhs:Expression> => TirStatement::MultiplyAssignAddress(TirExpression::Method(Box::new(instance), name, vec![]), rhs),
<instance:ExpressionAtom> "->" <name:Ident> "/=" <rhs:Expression> => TirStatement::DivideAssignAddress(TirExpression::Method(Box::new(instance), name, vec![]), rhs),
<Expression> => TirStatement::Expression(<>)
}
Expression: TirExpression = {
<cond:ExpressionBottom> "?" <then:Expression> ":" <otherwise:Expression> => TirExpression::Conditional(Box::new(cond), Box::new(then), Box::new(otherwise)),
<expr:ExpressionAtom> "as" <t:Type> => TirExpression::TypeCast(Box::new(expr), t),
"*" <ptr:ExpressionBottom> => TirExpression::Deref(Box::new(ptr)),
<ExpressionBottom> => <>,
}
ExpressionAtom: TirExpression = {
"is_movable" "(" <Type> ")" => TirExpression::IsMovable(<>),
"is_defined" "(" <Str> ")" => TirExpression::Constant(TirConstant::IsDefined(<>)),
"move" "(" <val:Expression> ")" => TirExpression::Move(Box::new(val)),
"sizeof" "(" <Type> ")" => TirExpression::SizeOf(<>),
"alloc" "(" <size:Expression> ")" => TirExpression::Alloc(Box::new(size)),
<name:Ident> <args:List<"(", Expression, ",", ")">> => TirExpression::Call(name, args),
<name:Ident> "!" <args:List<"(", Expression, ",", ")">> => TirExpression::ForeignCall(name, args),
"true" => TirExpression::True,
"false" => TirExpression::False,
<Ident> => TirExpression::Variable(<>),
<Str> => TirExpression::String(<>),
"@" => TirExpression::Void,
<Num> => TirExpression::Constant(TirConstant::Float(<>)),
<Char> => TirExpression::Character(<>),
"!" <ExpressionAtom> => TirExpression::Not(Box::new(<>)),
"(" <Expression> ")" => <>,
"-" <ExpressionAtom> => TirExpression::Subtract(Box::new(TirExpression::Constant(TirConstant::Float(0.0))), Box::new(<>)),
}
ExpressionBottom: TirExpression = {
<l:ExpressionLow> "&&" <r:ExpressionLow> => TirExpression::And(Box::new(l), Box::new(r)),
<l:ExpressionLow> "||" <r:ExpressionLow> => TirExpression::Or(Box::new(l), Box::new(r)),
<ExpressionLow> => <>
}
ExpressionLow: TirExpression = {
<l:ExpressionMiddle> "==" <r:ExpressionMiddle> => TirExpression::Equal(Box::new(l), Box::new(r)),
<l:ExpressionMiddle> "!=" <r:ExpressionMiddle> => TirExpression::NotEqual(Box::new(l), Box::new(r)),
<l:ExpressionMiddle> ">=" <r:ExpressionMiddle> => TirExpression::GreaterEqual(Box::new(l), Box::new(r)),
<l:ExpressionMiddle> ">" <r:ExpressionMiddle> => TirExpression::Greater(Box::new(l), Box::new(r)),
<l:ExpressionMiddle> "<=" <r:ExpressionMiddle> => TirExpression::LessEqual(Box::new(l), Box::new(r)),
<l:ExpressionMiddle> "<" <r:ExpressionMiddle> => TirExpression::Less(Box::new(l), Box::new(r)),
<ExpressionMiddle> => <>
}
ExpressionMiddle: TirExpression = {
<l:ExpressionHigh> "+" <r:ExpressionHigh> => TirExpression::Add(Box::new(l), Box::new(r)),
<l:ExpressionHigh> "-" <r:ExpressionHigh> => TirExpression::Subtract(Box::new(l), Box::new(r)),
<ExpressionHigh> => <>
}
ExpressionHigh: TirExpression = {
"&" <ptr:ExpressionAtom> "[" <idx:Expression> "]" => TirExpression::Index(Box::new(ptr), Box::new(idx)),
"&" <instance:ExpressionAtom> "->" <name:Ident> <args:List<"(", Expression, ",", ")">> => TirExpression::Method(Box::new(instance), name, args),
"&" <instance:ExpressionAtom> "->" <name:Ident> => TirExpression::Method(Box::new(instance), name, vec![]),
"&" <name:Ident> => TirExpression::Refer(name),
<ptr:ExpressionAtom> "[" <idx:Expression> "]" => TirExpression::Deref(Box::new(TirExpression::Index(Box::new(ptr), Box::new(idx)))),
<instance:ExpressionAtom> "." <name:Ident> <args:List<"(", Expression, ",", ")">> => TirExpression::Method(Box::new(instance), name, args),
<instance:ExpressionAtom> "." <name:Ident> => TirExpression::Method(Box::new(instance), name, vec![]),
<instance:ExpressionAtom> "->" <name:Ident> <args:List<"(", Expression, ",", ")">> => TirExpression::Deref(Box::new(TirExpression::Method(Box::new(instance), name, args))),
<instance:ExpressionAtom> "->" <name:Ident> => TirExpression::Deref(Box::new(TirExpression::Method(Box::new(instance), name, vec![]))),
<l:ExpressionAtom> "*" <r:ExpressionAtom> => TirExpression::Multiply(Box::new(l), Box::new(r)),
<l:ExpressionAtom> "/" <r:ExpressionAtom> => TirExpression::Divide(Box::new(l), Box::new(r)),
<ExpressionAtom> => <>
}