use crate::ast::Element;
use std::str::FromStr;
use lalrpop_util::ErrorRecovery;
grammar<'err>(errors: &'err mut Vec<ErrorRecovery<usize, Token<'input>, crate::parser::InnerError>>, filename: &str);
extern {
type Location = usize;
type Error = crate::parser::InnerError;
}
match {
r"\s*" => { }, // The default whitespace skipping is disabled if an `ignore pattern` is specified
r"//[^\n\r]*[\n\r]*" => { }, // Skip `// comments`
r"/\*[^*]*\*+(?:[^/*][^*]*\*+)*/" => { }, // Skip `/* comments */`
} else {
_
}
pub File: crate::ast::File = {
<s: @L> <expression:Term> <e: @R> => crate::ast::File {
name: filename.to_string(),
expression,
location: crate::ast::Location::new(s, e, filename),
},
};
IsExternal: bool = {
"external" => true
};
Semi: std::string::String = {
";" => ";".to_string(),
};
Primary: crate::ast::Term = {
"(" <Term> ")" => <>,
<s: @L> "true" <e: @R> => crate::ast::Term::Bool(crate::ast::Bool {
value: true,
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> "false" <e: @R> => crate::ast::Term::Bool(crate::ast::Bool {
value: false,
location: crate::ast::Location::new(s, e, filename),
}),
<Reference> => crate::ast::Term::Var(<>),
<s: @L> <value:String> <e: @R> => crate::ast::Term::Str(crate::ast::Str {
value,
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> <value:Int> <e: @R> => crate::ast::Term::Int(crate::ast::Int {
value,
location: crate::ast::Location::new(s, e, filename),
}),
};
Call: crate::ast::Term = {
<s: @L> "print" "(" <value:Term> ")" <e: @R> => crate::ast::Term::Print(crate::ast::Print {
value: Box::new(value),
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> "first" "(" <value:Term> ")" <e: @R> => crate::ast::Term::First(crate::ast::First {
value: Box::new(value),
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> "second" "(" <value:Term> ")" <e: @R> => crate::ast::Term::Second(crate::ast::Second {
value: Box::new(value),
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> <callee:Apply> "(" <arguments:Sep<",", Term>> ")" <e: @R> =>crate::ast::Term::Call(crate::ast::Call {
callee: Box::new(callee),
arguments,
location: crate::ast::Location::new(s, e, filename),
}),
};
FactorOp: crate::ast::BinaryOp = {
"*" => crate::ast::BinaryOp::Mul,
"/" => crate::ast::BinaryOp::Div,
"%" => crate::ast::BinaryOp::Rem,
};
Factor: crate::ast::Term = {
Apply,
<s: @L> <value:Apply> "." <name:Reference> <e: @R> => {
// Report the error
errors.push(lalrpop_util::ErrorRecovery {
dropped_tokens: vec![],
error: lalrpop_util::ParseError::User {
error: crate::parser::InnerError::UnsupportedRecordIndex {
err_span: name.location.into(),
}
},
});
crate::ast::Term::Error(crate::ast::Error {
message: format!("unsupported record indexing `{}`", name.text),
full_text: (&input[s..e]).to_string(),
location: crate::ast::Location::new(s, e, filename),
})
},
<s: @L> <a:Apply> <op:FactorOp> <b:Factor> <e: @R> => crate::ast::Term::Binary(crate::ast::Binary {
location: crate::ast::Location::new(s, e, filename),
op,
lhs: a.into(),
rhs: b.into(),
}),
};
ArithmeticOp: crate::ast::BinaryOp = {
"+" => crate::ast::BinaryOp::Add,
"-" => crate::ast::BinaryOp::Sub,
}
Arithmetic: crate::ast::Term = {
Factor,
<s: @L> <a:Factor> <op:ArithmeticOp> <b:Arithmetic> <e: @R> => crate::ast::Term::Binary(crate::ast::Binary {
location: crate::ast::Location::new(s, e, filename),
op,
lhs: a.into(),
rhs: b.into(),
}),
};
LogicalOp: crate::ast::BinaryOp = {
"&&" => crate::ast::BinaryOp::And,
"||" => crate::ast::BinaryOp::Or,
"==" => crate::ast::BinaryOp::Eq,
"!=" => crate::ast::BinaryOp::Neq,
"<=" => crate::ast::BinaryOp::Lte,
">=" => crate::ast::BinaryOp::Gte,
"<" => crate::ast::BinaryOp::Lt,
">" => crate::ast::BinaryOp::Gt,
};
Logical: crate::ast::Term = {
Arithmetic,
<s: @L> <a:Arithmetic> <op:LogicalOp> <b:Logical> <e: @R> => crate::ast::Term::Binary(crate::ast::Binary {
location: crate::ast::Location::new(s, e, filename),
op,
lhs: a.into(),
rhs: b.into(),
}),
};
Apply: crate::ast::Term = {
Primary,
Call,
};
pub Term: crate::ast::Term = {
Logical,
<s: @L> "(" <first: Term> "," <second: Term> ")" <e: @R> => crate::ast::Term::Tuple(crate::ast::Tuple {
first: Box::new(first),
second: Box::new(second),
location: crate::ast::Location::new(s, e, filename),
}),
"{" <term: Term> "}" => term,
<s: @L> "let" <name:Reference> "=" <value:Term> ";" <next:Term> <e: @R> => crate::ast::Term::Let(crate::ast::Let {
name,
value: value.into(),
next: next.into(),
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> "if" "(" <condition:Term> ")" "{" <then:Term> "}" "else" "{" <otherwise:Term> "}" <e: @R> => crate::ast::Term::If(crate::ast::If {
condition: condition.into(),
then: then.into(),
otherwise: otherwise.into(),
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> "fn" "(" <parameters:Sep<",", Reference>> ")" "=>" <body:Term?> <e: @R> => crate::ast::Term::Function(crate::ast::Function {
parameters,
value: match body {
Some(value) => Box::new(value),
None => {
// Report the error
errors.push(lalrpop_util::ErrorRecovery {
dropped_tokens: vec![],
error: lalrpop_util::ParseError::User {
error: crate::parser::InnerError::FunctionBodyMissing {
err_span: crate::ast::Location::new(s, e, filename).into(),
}
},
});
crate::ast::Term::Int(crate::ast::Int { value: 0, location: crate::ast::Location::new(s, e, filename).into() }).into()
},
},
location: crate::ast::Location::new(s, e, filename),
}),
<s: @L> <error:!> <e: @R> => {
let message = error.error.to_string();
errors.push(error);
crate::ast::Term::Error(crate::ast::Error {
message,
full_text: (&input[s..e]).to_string(),
location: crate::ast::Location::new(s, e, filename),
})
},
}
Int: i32 = <s:r"[0123456789]+"> => i32::from_str(s).unwrap();
String: std::string::String = <text:r#""(\\\\|\\"|[^"\\])*""#> => (&text[1..text.len() - 1]).to_string();
Text: std::string::String = {
<text:"_"> => text.to_string(),
<text:r"[a-zA-Z][a-zA-Z0-9/_]*"> => text.to_string(),
}
Reference: crate::parser::Var = {
<s: @L> <text:Text> <e: @R> => crate::parser::Var {
text: text.to_string(),
location: crate::ast::Location::new(s, e, filename),
}
};
#[inline]
Sep<U, T>: Vec<T> = {
<mut v:(<T> U)*> <e:T?> => match e {
Some(e) => {
v.push(e);
v
}
None => v
}
}