Parser implements examples

- Function call is now stmt (muhehe)
This commit is contained in:
Erin 2021-05-02 15:43:25 +02:00 committed by ondra05
parent 91bd015e9b
commit 4a9b656093
6 changed files with 122 additions and 32 deletions

View file

@ -8,6 +8,7 @@ mod repl;
mod variables; mod variables;
use clap::{App, Arg}; use clap::{App, Arg};
use logos::Source;
use parser::Parser; use parser::Parser;
fn main() { fn main() {
// variables::test(); // variables::test();
@ -34,7 +35,17 @@ fn main() {
// Parse // Parse
let mut parser = Parser::new(&source); let mut parser = Parser::new(&source);
let ast = parser.init(); let ast = parser.init();
println!("{:#?}", ast); match ast {
Ok(ast) => println!("{:#?}", ast),
Err(e) => {
println!(
"Error `{:?}` occured at span: {:?} = `{:?}`",
e.kind,
e.position.clone(),
source.slice(e.position)
);
}
}
} }
None => { None => {
println!( println!(

View file

@ -27,7 +27,6 @@ pub enum Expr {
Subtract { left: Box<Expr>, right: Box<Expr> }, Subtract { left: Box<Expr>, right: Box<Expr> },
Multiply { left: Box<Expr>, right: Box<Expr> }, Multiply { left: Box<Expr>, right: Box<Expr> },
Divide { left: Box<Expr>, right: Box<Expr> }, Divide { left: Box<Expr>, right: Box<Expr> },
FunctionCall { iden: Iden, args: Vec<Expr> },
Literal(Value), Literal(Value),
Identifier(Iden), Identifier(Iden),
} }
@ -56,6 +55,10 @@ pub enum Stmt {
cond: Box<Item>, cond: Box<Item>,
body: Vec<Item>, body: Vec<Item>,
}, },
FunctionCall {
iden: Iden,
args: Vec<Expr>,
},
Print(Expr),
Melo(Iden), Melo(Iden),
} }

View file

@ -35,9 +35,11 @@ impl<'a> Parser<'a> {
if token.is_none() { if token.is_none() {
return Ok(self.ast.clone()); return Ok(self.ast.clone());
}; };
if matches!(token, Some(Token::Comment)) {
let expr = self.parse_item(token)?; continue;
self.ast.push(expr); }
let item = self.parse_item(token)?;
self.ast.push(item);
} }
} }
@ -112,9 +114,15 @@ impl<'a> Parser<'a> {
fn function_declaration(&mut self) -> ParseResult { fn function_declaration(&mut self) -> ParseResult {
let iden = self.require_iden()?; let iden = self.require_iden()?;
self.require(Token::LeftParenthesis)?; self.require(Token::LeftParenthesis)?;
let args = vec![]; let mut args = vec![];
self.require(Token::RightParenthesis)?; loop {
let next = self.lexer.next();
match next {
Some(Token::RightParenthesis) => break,
Some(Token::Identifier(i)) => args.push(Iden(i)),
_ => return Err(self.unexpected_token(None)),
}
}
self.require(Token::LeftBrace)?; self.require(Token::LeftBrace)?;
// Parse function body // Parse function body
let body = self.parse_body()?; let body = self.parse_body()?;

View file

@ -2,12 +2,17 @@ use super::*;
type ExprResult = Result<Expr, Error>; type ExprResult = Result<Expr, Error>;
/// Generate infix expression by pattern left <op> right
///
/// Credits: `@! ! Reiter#4543`
#[macro_export] #[macro_export]
macro_rules! gen_infix { macro_rules! gen_infix {
($($fn_name: ident => $type: tt);*$(;)?) => {$( ($($fn_name: ident => $type: tt);*$(;)?) => {$(
/// Generated function for infix operator
fn $fn_name(&mut self, left: Expr) -> ExprResult { fn $fn_name(&mut self, left: Expr) -> ExprResult {
self.lexer.next();
let next = self.lexer.next(); let next = self.lexer.next();
let right = self.ensure_expr(next)?; let right = self.parse_expr(next)?;
Ok(Expr::$type { left: Box::new(left), right: Box::new(right) }) Ok(Expr::$type { left: Box::new(left), right: Box::new(right) })
})* })*
}; };
@ -15,14 +20,23 @@ macro_rules! gen_infix {
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
pub(super) fn parse_ops(&mut self, token: Token) -> ParseResult { pub(super) fn parse_ops(&mut self, token: Token) -> ParseResult {
let mut buf: Expr = self.ensure_expr(Some(token))?; if matches!(self.lexer.peek(), Some(Token::LeftParenthesis)) {
return self.fn_call(token);
}
let mut buf: Expr = self.parse_expr(Some(token))?;
loop { loop {
buf = match self.lexer.next() { buf = match self.lexer.peek() {
Some(Token::Addition) => self.addition(buf)?, Some(Token::Addition) => self.addition(buf)?,
Some(Token::Subtract) => self.subtract(buf)?, Some(Token::Subtract) => self.subtract(buf)?,
Some(Token::Multiply) => self.multiply(buf)?, Some(Token::Multiply) => self.multiply(buf)?,
Some(Token::Divide) => self.divide(buf)?, Some(Token::Divide) => self.divide(buf)?,
Some(Token::Print) => {
self.lexer.next();
self.require(Token::Semicolon)?;
return Ok(Stmt::Print(buf).into());
}
_ => return Ok(buf.into()), _ => return Ok(buf.into()),
} }
} }
@ -37,41 +51,84 @@ impl<'a> Parser<'a> {
} }
/// Ensure that input token is an expression /// Ensure that input token is an expression
fn ensure_expr(&mut self, token: Option<Token>) -> ExprResult { fn parse_expr(&mut self, token: Option<Token>) -> ExprResult {
let token = token.ok_or(Error { let token = token.ok_or(Error {
kind: ErrorKind::EndOfTokenStream, kind: ErrorKind::EndOfTokenStream,
position: self.lexer.span(), position: self.lexer.span(),
})?; })?;
match token { match token {
Token::Boolean(b) => Ok(Expr::Literal(Value::Bool(b))), Token::Boolean(b) => Ok(Expr::Literal(Value::Bool(b))),
Token::Integer(i) => Ok(Expr::Literal(Value::Int(i))), Token::Integer(i) => Ok(Expr::Literal(Value::Int(i))),
Token::String(s) => Ok(Expr::Literal(Value::Str(s))), Token::String(s) => Ok(Expr::Literal(Value::Str(s))),
Token::Aboolean(a) => Ok(Expr::Literal(Value::Abool(a))), Token::Aboolean(a) => Ok(Expr::Literal(Value::Abool(a))),
Token::Identifier(i) => Ok(Expr::Identifier(Iden(i))), Token::Identifier(i) => Ok(Expr::Identifier(Iden(i))),
Token::LeftParenthesis => self.parse_paren(),
t => Err(self.unexpected_token(Some(t))), t => Err(self.unexpected_token(Some(t))),
} }
} }
/// Parse function call /// Parse parenthesieted expression
fn fn_call(&mut self, iden: Iden) -> ExprResult { fn parse_paren(&mut self) -> ExprResult {
return todo!();
self.lexer.next();
let mut args: Vec<Expr> = Vec::new();
while let Some(token) = self.lexer.peek() {
match token {
Token::Identifier(id) => {
args.push(Expr::Identifier(Iden(id.clone())));
self.lexer.next();
}
Token::RightParenthesis => break,
_ => {
let next = self.lexer.next(); let next = self.lexer.next();
let mut buf = self.parse_expr(next)?;
loop {
let next = self.lexer.peek().clone().ok_or(Error {
kind: ErrorKind::EndOfTokenStream,
position: self.lexer.span(),
})?;
buf = match Some(next) {
Some(Token::Addition) => self.addition(buf)?,
Some(Token::Subtract) => self.subtract(buf)?,
Some(Token::Multiply) => self.multiply(buf)?,
Some(Token::Divide) => self.divide(buf)?,
Some(Token::LeftParenthesis) => {
return Err(Error {
kind: ErrorKind::SyntaxError(
"Function call isn't an expression!".to_owned(),
),
position: self.lexer.span(),
})
}
Some(Token::RightParenthesis) => {
self.lexer.next();
return Ok(buf);
}
_ => return Ok(buf.into()),
};
} }
} }
self.require(Token::Comma)?;
/// Parse function call
fn fn_call(&mut self, token: Token) -> ParseResult {
let iden = if let Token::Identifier(i) = token {
Iden(i)
} else {
return Err(Error {
kind: ErrorKind::InvalidIdentifier,
position: self.lexer.span(),
});
};
self.lexer.next();
let mut args = Vec::new();
loop {
let next = self.lexer.next();
// No argument function
if matches!(next, Some(Token::RightParenthesis)) {
break;
} }
self.require(Token::RightParenthesis)?;
Ok(Expr::FunctionCall { iden, args }) args.push(self.parse_expr(next)?);
match self.lexer.next() {
Some(Token::RightParenthesis) => break,
Some(Token::Comma) => continue,
_ => return Err(self.unexpected_token(None)),
}
}
self.require(Token::Semicolon)?;
Ok(Stmt::FunctionCall { iden, args }.into())
} }
} }

View file

@ -1,3 +1,4 @@
use logos::Source;
use rustyline::Editor; use rustyline::Editor;
use crate::parser::Parser; use crate::parser::Parser;
@ -14,7 +15,17 @@ pub fn repl() {
} }
let mut parser = Parser::new(&line); let mut parser = Parser::new(&line);
let ast = parser.init(); let ast = parser.init();
println!("{:#?}", ast); match ast {
Ok(ast) => println!("{:?}", ast),
Err(e) => {
println!(
"Error `{:?}` occured at span: {:?} = `{:?}`",
e.kind,
e.position.clone(),
line.slice(e.position)
);
}
}
} }
Err(rustyline::error::ReadlineError::Eof) => { Err(rustyline::error::ReadlineError::Eof) => {
println!("bye"); println!("bye");