func args + some fixes
This commit is contained in:
parent
21616e2723
commit
77246ddd24
18
src/lexer.rs
18
src/lexer.rs
|
@ -36,6 +36,7 @@ pub enum Token {
|
||||||
Minus,
|
Minus,
|
||||||
Star,
|
Star,
|
||||||
Slash,
|
Slash,
|
||||||
|
Percent,
|
||||||
Caret,
|
Caret,
|
||||||
|
|
||||||
CurlyOpen,
|
CurlyOpen,
|
||||||
|
@ -47,6 +48,7 @@ pub enum Token {
|
||||||
Comma,
|
Comma,
|
||||||
Eol,
|
Eol,
|
||||||
|
|
||||||
|
Func,
|
||||||
If,
|
If,
|
||||||
Else,
|
Else,
|
||||||
Return,
|
Return,
|
||||||
|
@ -69,8 +71,6 @@ pub enum Token {
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||||
pub enum Precedence {
|
pub enum Precedence {
|
||||||
Min,
|
Min,
|
||||||
Return,
|
|
||||||
If,
|
|
||||||
Assign,
|
Assign,
|
||||||
Logical,
|
Logical,
|
||||||
Equality,
|
Equality,
|
||||||
|
@ -78,7 +78,7 @@ pub enum Precedence {
|
||||||
AddSub,
|
AddSub,
|
||||||
MulDiv,
|
MulDiv,
|
||||||
Pow,
|
Pow,
|
||||||
NegateNot,
|
Prefix,
|
||||||
}
|
}
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub enum Associativity {
|
pub enum Associativity {
|
||||||
|
@ -88,9 +88,9 @@ pub enum Associativity {
|
||||||
impl Token {
|
impl Token {
|
||||||
pub fn prefix_precedence(&self) -> Option<Precedence> {
|
pub fn prefix_precedence(&self) -> Option<Precedence> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
Token::Return => Precedence::Return,
|
Token::Return | Token::If | Token::Func | Token::Minus | Token::Not => {
|
||||||
Token::If => Precedence::If,
|
Precedence::Prefix
|
||||||
Token::Minus | Token::Not => Precedence::NegateNot,
|
}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -195,9 +195,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
match word.as_str() {
|
match word.as_str() {
|
||||||
"return" => Token::Return,
|
"func" => Token::Func,
|
||||||
"if" => Token::If,
|
"if" => Token::If,
|
||||||
"else" => Token::Else,
|
"else" => Token::Else,
|
||||||
|
"return" => Token::Return,
|
||||||
"true" => Token::Literal(Literal::Boolean(true)),
|
"true" => Token::Literal(Literal::Boolean(true)),
|
||||||
"false" => Token::Literal(Literal::Boolean(false)),
|
"false" => Token::Literal(Literal::Boolean(false)),
|
||||||
"nil" => Token::Literal(Literal::Nil),
|
"nil" => Token::Literal(Literal::Nil),
|
||||||
|
@ -270,6 +271,9 @@ where
|
||||||
// / divide
|
// / divide
|
||||||
'/' => self.eat_to(Token::Slash),
|
'/' => self.eat_to(Token::Slash),
|
||||||
|
|
||||||
|
// % modulo
|
||||||
|
'%' => self.eat_to(Token::Percent),
|
||||||
|
|
||||||
// ^ pow
|
// ^ pow
|
||||||
'^' => self.eat_to(Token::Caret),
|
'^' => self.eat_to(Token::Caret),
|
||||||
|
|
||||||
|
|
101
src/parser.rs
101
src/parser.rs
|
@ -9,8 +9,9 @@ pub enum Expr {
|
||||||
// Data and variables
|
// Data and variables
|
||||||
Assignment(Box<Expr>, Box<Expr>),
|
Assignment(Box<Expr>, Box<Expr>),
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
// Runtime datatypes
|
// Non-literal datatypes
|
||||||
Block(Block),
|
Block(Block),
|
||||||
|
Func(Vec<Expr>, Box<Expr>),
|
||||||
// Control flow
|
// Control flow
|
||||||
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
|
If(Box<Expr>, Box<Expr>, Option<Box<Expr>>),
|
||||||
Return(Box<Expr>),
|
Return(Box<Expr>),
|
||||||
|
@ -66,7 +67,7 @@ pub type Result<T> = std::result::Result<T, ParseError>;
|
||||||
|
|
||||||
pub struct Parser<I: Iterator<Item = Token>> {
|
pub struct Parser<I: Iterator<Item = Token>> {
|
||||||
tokens: Peekable<I>,
|
tokens: Peekable<I>,
|
||||||
is_next_eol: bool,
|
saw_eol: bool,
|
||||||
}
|
}
|
||||||
impl<I> Parser<I>
|
impl<I> Parser<I>
|
||||||
where
|
where
|
||||||
|
@ -76,7 +77,7 @@ where
|
||||||
let tokens = tokens.peekable();
|
let tokens = tokens.peekable();
|
||||||
Self {
|
Self {
|
||||||
tokens,
|
tokens,
|
||||||
is_next_eol: false,
|
saw_eol: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,12 +101,12 @@ where
|
||||||
// Peek doesn't advance the token stream, so
|
// Peek doesn't advance the token stream, so
|
||||||
// don't allow it to unset the EOL flag
|
// don't allow it to unset the EOL flag
|
||||||
if self.skip_eol() {
|
if self.skip_eol() {
|
||||||
self.is_next_eol = true;
|
self.saw_eol = true;
|
||||||
}
|
}
|
||||||
self.tokens.peek().ok_or(ParseError::UnexpectedEnd)
|
self.tokens.peek().ok_or(ParseError::UnexpectedEnd)
|
||||||
}
|
}
|
||||||
fn try_next(&mut self) -> Result<Token> {
|
fn try_next(&mut self) -> Result<Token> {
|
||||||
self.is_next_eol = self.skip_eol();
|
self.saw_eol = self.skip_eol();
|
||||||
self.tokens.next().ok_or(ParseError::UnexpectedEnd)
|
self.tokens.next().ok_or(ParseError::UnexpectedEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,26 +134,46 @@ where
|
||||||
// unary ops!! (prefix)
|
// unary ops!! (prefix)
|
||||||
t if t.prefix_precedence().is_some() => {
|
t if t.prefix_precedence().is_some() => {
|
||||||
let prec = t.prefix_precedence().unwrap();
|
let prec = t.prefix_precedence().unwrap();
|
||||||
let rhs = self.parse_expr(prec, in_group)?;
|
// parse function
|
||||||
Box::new(match t {
|
if matches!(t, Token::Func) {
|
||||||
Token::Minus => Expr::Negate(rhs),
|
// expect opening paren
|
||||||
Token::Not => Expr::Not(rhs),
|
let next = self.try_next()?;
|
||||||
Token::Return => Expr::Return(rhs),
|
if !matches!(next, Token::ParenOpen) {
|
||||||
Token::If => {
|
return Err(ParseError::UnexpectedToken(next));
|
||||||
// parse the true case
|
|
||||||
let true_case = self.parse_expr(Precedence::Min, false)?;
|
|
||||||
// and maybe a false case
|
|
||||||
let false_case = matches!(self.try_peek(), Ok(Token::Else))
|
|
||||||
.then(|| {
|
|
||||||
self.eat();
|
|
||||||
self.parse_expr(Precedence::Min, false)
|
|
||||||
})
|
|
||||||
.transpose()?;
|
|
||||||
// pack
|
|
||||||
Expr::If(rhs, true_case, false_case)
|
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
// parse args
|
||||||
})
|
let args = self.parse_args()?;
|
||||||
|
// expect closing paren
|
||||||
|
if !matches!(self.try_peek(), Ok(Token::ParenClose)) {
|
||||||
|
return Err(ParseError::UnexpectedToken(self.next_unwrap()));
|
||||||
|
}
|
||||||
|
self.eat();
|
||||||
|
// parse body
|
||||||
|
let body = self.parse_expr(prec, in_group)?;
|
||||||
|
// pack
|
||||||
|
Box::new(Expr::Func(args, body))
|
||||||
|
} else {
|
||||||
|
let rhs = self.parse_expr(prec, in_group)?;
|
||||||
|
Box::new(match t {
|
||||||
|
Token::Minus => Expr::Negate(rhs),
|
||||||
|
Token::Not => Expr::Not(rhs),
|
||||||
|
Token::Return => Expr::Return(rhs),
|
||||||
|
Token::If => {
|
||||||
|
// parse the true case
|
||||||
|
let true_case = self.parse_expr(prec, in_group)?;
|
||||||
|
// and maybe a false case
|
||||||
|
let false_case = matches!(self.try_peek(), Ok(Token::Else))
|
||||||
|
.then(|| {
|
||||||
|
self.eat();
|
||||||
|
self.parse_expr(prec, in_group)
|
||||||
|
})
|
||||||
|
.transpose()?;
|
||||||
|
// pack
|
||||||
|
Expr::If(rhs, true_case, false_case)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unexpected token
|
// unexpected token
|
||||||
|
@ -173,7 +194,7 @@ where
|
||||||
|
|
||||||
// function call
|
// function call
|
||||||
Ok(Token::ParenOpen) => {
|
Ok(Token::ParenOpen) => {
|
||||||
if self.is_next_eol {
|
if self.saw_eol {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +227,7 @@ where
|
||||||
let (prec, assoc) = op.infix_precedence().unwrap();
|
let (prec, assoc) = op.infix_precedence().unwrap();
|
||||||
|
|
||||||
// break if this op is meant for previous recursion
|
// break if this op is meant for previous recursion
|
||||||
// or it's equal and we would prefer to build leftward..
|
// or it's equal and we prefer to build leftward
|
||||||
if prec < min_prec || (prec == min_prec && assoc == Associativity::Left) {
|
if prec < min_prec || (prec == min_prec && assoc == Associativity::Left) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -246,6 +267,24 @@ where
|
||||||
|
|
||||||
Ok(lhs)
|
Ok(lhs)
|
||||||
}
|
}
|
||||||
|
fn parse_args(&mut self) -> Result<Vec<Expr>> {
|
||||||
|
let mut exprs = Vec::new();
|
||||||
|
while !matches!(self.try_peek(), Ok(Token::ParenClose)) {
|
||||||
|
// try to parse expr
|
||||||
|
exprs.push(*self.parse_expr(Precedence::Min, false)?);
|
||||||
|
// advance
|
||||||
|
let next = self.try_next()?;
|
||||||
|
// check if its the end
|
||||||
|
if matches!(next, Token::ParenClose) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// expect comma
|
||||||
|
if !matches!(next, Token::Comma) {
|
||||||
|
return Err(ParseError::UnexpectedToken(next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(exprs)
|
||||||
|
}
|
||||||
fn parse_block(&mut self, in_block: bool) -> Result<Block> {
|
fn parse_block(&mut self, in_block: bool) -> Result<Block> {
|
||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
|
@ -256,10 +295,16 @@ where
|
||||||
Err(ParseError::UnexpectedEnd) if !in_block => break,
|
Err(ParseError::UnexpectedEnd) if !in_block => break,
|
||||||
|
|
||||||
// try to parse expr
|
// try to parse expr
|
||||||
Ok(_) => exprs.push(*self.parse_expr(Precedence::Min, false)?),
|
Ok(_) => {
|
||||||
|
exprs.push(*self.parse_expr(Precedence::Min, false)?);
|
||||||
|
// expect eol or eof
|
||||||
|
if !matches!(self.try_peek(), Err(ParseError::UnexpectedEnd)) && !self.saw_eol {
|
||||||
|
return Err(ParseError::UnexpectedToken(self.next_unwrap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// invalid
|
// invalid
|
||||||
Err(_) => unreachable!(),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Block { exprs })
|
Ok(Block { exprs })
|
||||||
|
|
|
@ -38,7 +38,7 @@ fn fmt_expr(e: Expr, depth: usize) -> String {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Expr::Return(l) => format!("return {}", fmt_expr(*l, depth)),
|
Expr::Return(l) => format!("return ({})", fmt_expr(*l, depth)),
|
||||||
Expr::Block(b) => {
|
Expr::Block(b) => {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let len = b.exprs.len();
|
let len = b.exprs.len();
|
||||||
|
@ -54,6 +54,14 @@ fn fmt_expr(e: Expr, depth: usize) -> String {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
Expr::Func(a, e) => format!(
|
||||||
|
"(func({}) ({}))",
|
||||||
|
a.into_iter()
|
||||||
|
.map(|e| fmt_expr(e, depth))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
fmt_expr(*e, depth)
|
||||||
|
),
|
||||||
Expr::Negate(l) => format!("(-{})", fmt_expr(*l, depth)),
|
Expr::Negate(l) => format!("(-{})", fmt_expr(*l, depth)),
|
||||||
Expr::Not(l) => format!("(!{})", fmt_expr(*l, depth)),
|
Expr::Not(l) => format!("(!{})", fmt_expr(*l, depth)),
|
||||||
Expr::EqualTo(l, r) => fmt_binop(*l, *r, "==", depth),
|
Expr::EqualTo(l, r) => fmt_binop(*l, *r, "==", depth),
|
||||||
|
|
Loading…
Reference in New Issue