231 lines
7.6 KiB
Rust
231 lines
7.6 KiB
Rust
use super::{Expectable, Parser, Position, SyntaxError};
|
|
|
|
type Ident = String;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct ParsedReid(pub Expression);
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Statement {
|
|
LetStatement(Position, Ident, Box<Expression>),
|
|
ExprStatement(Position, Expression),
|
|
}
|
|
|
|
impl Statement {
|
|
pub fn parse(parser: &mut Parser) -> Result<Statement, SyntaxError> {
|
|
let pos = parser.pos();
|
|
|
|
if parser.expect_static("let").get().is_some() {
|
|
let ident = parser
|
|
.expect_ident()
|
|
.get_or(SyntaxError::ExpectedIdent(pos))?;
|
|
parser
|
|
.expect_static("=")
|
|
.get_or(SyntaxError::ExpectedToken(pos, '='))?;
|
|
match Expression::parse(parser, true) {
|
|
Ok(expr) => {
|
|
parser
|
|
.expect_static(";")
|
|
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
|
Ok(Statement::LetStatement(pos, ident, Box::new(expr)))
|
|
}
|
|
Err(err) => Err(SyntaxError::ExpectedExpression(pos, Some(Box::new(err)))),
|
|
}
|
|
} else {
|
|
match Expression::parse(parser, true) {
|
|
Ok(expr) => {
|
|
let statement = Statement::ExprStatement(pos, expr);
|
|
parser
|
|
.expect_static(";")
|
|
.get_or(SyntaxError::ExpectedToken(pos, ';'))?;
|
|
Ok(statement)
|
|
}
|
|
Err(err) => Err(SyntaxError::ExpectedStatement(pos, Some(Box::new(err)))),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Expression {
|
|
BlockExpr(Position, Vec<Statement>),
|
|
FunctionCall(Position, Ident, Vec<Expression>),
|
|
ArithmeticExpression(Position, Box<ArithmeticExpression>),
|
|
ValueRef(Position, Pattern),
|
|
}
|
|
|
|
impl Expression {
|
|
pub fn parse(parser: &mut Parser, allow_arithmetic: bool) -> Result<Expression, SyntaxError> {
|
|
let begin_pos = parser.pos();
|
|
|
|
let first = if parser.expect_static("{").get().is_some() {
|
|
let mut statement_list = Vec::new();
|
|
while {
|
|
match Statement::parse(parser) {
|
|
Ok(exp) => {
|
|
statement_list.push(exp);
|
|
true
|
|
}
|
|
Err(_) => false,
|
|
}
|
|
} {}
|
|
if parser.expect_static("}").get().is_some() {
|
|
Ok(Expression::BlockExpr(begin_pos, statement_list))
|
|
} else {
|
|
Err(SyntaxError::ExpectedToken(parser.pos(), '}'))
|
|
}
|
|
} else if let Some(texts) = parser.expect_ident().and(Expectable::Static("(")).get() {
|
|
let pos = parser.pos();
|
|
let name = texts.get(0).unwrap();
|
|
let mut arg_list = Vec::new();
|
|
while {
|
|
match Expression::parse(parser, true) {
|
|
Ok(exp) => {
|
|
arg_list.push(exp);
|
|
parser.expect_static(",").get().is_some()
|
|
}
|
|
Err(err) => {
|
|
if arg_list.is_empty() {
|
|
false
|
|
} else {
|
|
return Err(err);
|
|
}
|
|
}
|
|
}
|
|
} {}
|
|
parser
|
|
.expect_static(")")
|
|
.get_or(SyntaxError::ExpectedToken(pos, ')'))?;
|
|
Ok(Expression::FunctionCall(pos, name.clone(), arg_list))
|
|
} else if let Ok(pattern) = Pattern::parse(parser) {
|
|
Ok(Expression::ValueRef(begin_pos, pattern))
|
|
} else {
|
|
Err(SyntaxError::ExpectedExpression(begin_pos, None))
|
|
}?;
|
|
|
|
if allow_arithmetic {
|
|
if let Ok(exp) = ArithmeticExpression::parse(first.clone(), parser) {
|
|
Ok(Expression::ArithmeticExpression(begin_pos, Box::new(exp)))
|
|
} else {
|
|
Ok(first)
|
|
}
|
|
} else {
|
|
Ok(first)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum ArithmeticExpression {
|
|
Add(Expression, Expression),
|
|
Subtract(Expression, Expression),
|
|
Mult(Expression, Expression),
|
|
}
|
|
|
|
impl ArithmeticExpression {
|
|
fn parse(
|
|
first_exp: Expression,
|
|
parser: &mut Parser,
|
|
) -> Result<ArithmeticExpression, SyntaxError> {
|
|
let mut list = Vec::new();
|
|
let mut exp = first_exp;
|
|
while {
|
|
let sign = parser
|
|
.expect_static("+")
|
|
.get()
|
|
.or_else(|| parser.expect_static("-").get())
|
|
.or_else(|| parser.expect_static("*").get());
|
|
if sign.is_some() {
|
|
list.push((exp, sign.clone()));
|
|
exp = Expression::parse(parser, false)?;
|
|
}
|
|
sign.is_some()
|
|
} {}
|
|
list.push((exp, None));
|
|
if list.len() == 1 {
|
|
return Err(SyntaxError::Fatal);
|
|
}
|
|
|
|
// Replace all (expr, "*"), (expr, any) => ((mult_expr, any)
|
|
let clone = list.clone();
|
|
let iter = clone.iter().enumerate().rev();
|
|
for (idx, (exp, sign)) in iter {
|
|
if let Some(sign) = sign {
|
|
if sign == "*" {
|
|
if let Some((exp2, sign2)) = list.clone().get(idx + 1) {
|
|
list.remove(idx + 1);
|
|
list.remove(idx);
|
|
let expr = Expression::ArithmeticExpression(
|
|
parser.pos(),
|
|
Box::new(ArithmeticExpression::Mult(exp.clone(), exp2.clone())),
|
|
);
|
|
list.insert(idx, (expr, sign2.clone()));
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut ret = Err(SyntaxError::Fatal);
|
|
while list.len() > 1 {
|
|
let (exp2, sign2) = list.remove(1);
|
|
let (exp1, sign1) = list.remove(0);
|
|
let expr = if let Some(sign1) = sign1 {
|
|
match &*sign1 {
|
|
"+" => Some(Box::new(ArithmeticExpression::Add(exp1, exp2))),
|
|
"-" => Some(Box::new(ArithmeticExpression::Subtract(exp1, exp2))),
|
|
_ => None,
|
|
}
|
|
} else {
|
|
return Err(SyntaxError::ExpectedExpression(parser.pos(), None));
|
|
};
|
|
if let Some(expr) = expr {
|
|
list.insert(
|
|
0,
|
|
(Expression::ArithmeticExpression(parser.pos(), expr), sign2),
|
|
);
|
|
}
|
|
}
|
|
|
|
if let Some(first) = list.get(0) {
|
|
if let Expression::ArithmeticExpression(_, expr) = &first.0 {
|
|
ret = Ok(*expr.clone());
|
|
}
|
|
}
|
|
|
|
ret
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Pattern {
|
|
IdentPattern(Position, Ident),
|
|
LiteralPattern(Position, LiteralPattern),
|
|
}
|
|
|
|
impl Pattern {
|
|
fn parse(parser: &mut Parser) -> Result<Pattern, SyntaxError> {
|
|
let pos = parser.pos();
|
|
if let Some(string) = parser.expect_string_lit().get() {
|
|
Ok(Pattern::LiteralPattern(
|
|
pos,
|
|
LiteralPattern::StringLit(string),
|
|
))
|
|
} else if let Some(int) = parser.expect_numeral_lit().get() {
|
|
Ok(Pattern::LiteralPattern(
|
|
pos,
|
|
LiteralPattern::Integer32Lit(int),
|
|
))
|
|
} else if let Some(ident) = parser.expect_ident().get() {
|
|
Ok(Pattern::IdentPattern(pos, ident))
|
|
} else {
|
|
Err(SyntaxError::ExpectedPattern(pos))
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum LiteralPattern {
|
|
StringLit(String),
|
|
Integer32Lit(String),
|
|
}
|