diff --git a/able-script-test/parse_test.able b/able-script-test/parse_test.able index 04c522b3..72786dce 100644 --- a/able-script-test/parse_test.able +++ b/able-script-test/parse_test.able @@ -1,2 +1,10 @@ -var hello = true; -var test; \ No newline at end of file +functio test() { + functio nested() { + var c = false; + } + var a = true; +} + +functio another() { + var b = false; +} \ No newline at end of file diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..510aa334 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,19 @@ +use std::ops::Range; + +#[derive(Debug, Clone)] +pub struct Error { + pub kind: ErrorKind, + pub position: Range, +} + +#[derive(Debug, Clone)] +pub enum ErrorKind { + SyntaxError, +} + +impl Error { + pub fn panic(&self, span: &str) { + println!("{:?} occured at {:?}", self.kind, self.position); + println!(" {}", &span); + } +} diff --git a/src/main.rs b/src/main.rs index 69be9c49..bf9230a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![forbid(unsafe_code)] mod base_55; +mod error; mod parser; mod tokens; mod variables; diff --git a/src/parser/item.rs b/src/parser/item.rs index 030b3b8d..af6af748 100644 --- a/src/parser/item.rs +++ b/src/parser/item.rs @@ -1,4 +1,6 @@ #[derive(Debug, Clone)] pub enum Expr { - DeclareVariable { iden: String, init: Option }, -} \ No newline at end of file + VariableDeclaration { iden: String, init: Option }, + FunctionDeclaration { iden: String, body: Vec }, + BfFDeclaration { iden: String, code: String }, +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 891f18bb..aeffcadb 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -3,8 +3,11 @@ mod utils; use item::Expr; -use crate::tokens::Token; use crate::variables::Value; +use crate::{ + error::{Error, ErrorKind}, + tokens::Token, +}; use logos::Logos; @@ -18,7 +21,6 @@ pub enum ParseError { /// Parser structure / state machine pub struct Parser<'a> { lexer: logos::Lexer<'a, Token>, - ast: Vec, } impl<'a> Parser<'a> { @@ -26,31 +28,39 @@ impl<'a> Parser<'a> { pub fn new(source: &'a str) -> Self { Self { lexer: Token::lexer(source), - ast: vec![], } } /// Start parsing Token Vector into Abstract Syntax Tree pub fn parse(&mut self) -> Vec { + let mut ast = vec![]; while let Some(token) = self.lexer.next() { - let expr = match token { - Token::Variable => self.variable(), - tok => { - // TODO: Better error handling - println!("Parse error"); + let expr = match token { + Token::Variable => self.variable_declaration(), + Token::Function => self.function_declaration(), + Token::BfFunction => self.bff_declaration(), + Token::RightBrace => return ast, + _ => Err(Error { + kind: ErrorKind::SyntaxError, + position: 0..0, + }), + }; + match expr { + Ok(o) => ast.push(o), + Err(e) => { + e.panic(self.lexer.slice()); break; } - }; - self.ast.push(expr.unwrap()); + } } - self.ast.clone() + ast } /// Parse variable declaration /// /// `var [iden] = [literal];` - fn variable(&mut self) -> Result { + fn variable_declaration(&mut self) -> Result { let iden = self.require(Token::Identifier)?; let init = match self.lexer.next() { @@ -60,9 +70,39 @@ impl<'a> Parser<'a> { self.require(Token::Semicolon)?; Some(value) } - _ => return Err(ParseError::UnexpectedToken), + _ => { + return Err(Error { + kind: ErrorKind::SyntaxError, + position: self.lexer.span(), + }) + } }; - Ok(Expr::DeclareVariable { iden, init }) + Ok(Expr::VariableDeclaration { iden, init }) + } + + /// Declare function + /// + /// `functio [iden] ([expr], [expr]) { ... } + fn function_declaration(&mut self) -> Result { + let iden = self.require(Token::Identifier)?; + self.require(Token::LeftParenthesis)?; + // TODO: Arguments + self.require(Token::RightParenthesis)?; + self.require(Token::LeftBrace)?; + let body = self.parse(); + + Ok(Expr::FunctionDeclaration { iden, body }) + } + + /// Declare BF FFI Function + /// + /// `bff [iden] { ... }` + fn bff_declaration(&mut self) -> Result { + let iden = self.require(Token::Identifier)?; + self.require(Token::LeftBrace)?; + let code = self.require(Token::String)?; // <-- Nasty hack, but works + self.require(Token::RightBrace)?; + Ok(Expr::BfFDeclaration { iden, code }) } } diff --git a/src/parser/utils.rs b/src/parser/utils.rs index 496f857a..68098dd0 100644 --- a/src/parser/utils.rs +++ b/src/parser/utils.rs @@ -1,4 +1,7 @@ -use crate::tokens::{Abool, Token}; +use crate::{ + error::{Error, ErrorKind}, + tokens::{Abool, Token}, +}; use super::{ParseError, Parser}; @@ -20,11 +23,14 @@ pub fn num2abool(number: i32) -> Abool { impl<'a> Parser<'a> { /// Require type of token as next and return it's value (sometimes irrelevant) - pub(super) fn require(&mut self, with: Token) -> Result { + pub(super) fn require(&mut self, with: Token) -> Result { if self.lexer.next() == Some(with) { Ok(self.lexer.slice().to_owned()) } else { - Err(ParseError::UnexpectedToken) + Err(Error { + kind: ErrorKind::SyntaxError, + position: self.lexer.span(), + }) } } } diff --git a/src/tokens.rs b/src/tokens.rs index a41e401f..902c3db5 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -2,6 +2,23 @@ use logos::Logos; #[derive(Logos, Debug, PartialEq)] pub enum Token { + // Literals + /// True, False + #[regex("true|false")] + Boolean, + + /// Always, Sometimes, Never + #[regex("always|sometimes|never")] + Aboolean, + + /// String + #[regex("\"(\\.|[^\"])*\"")] + String, + + /// Integer + #[regex(r"[0-9]+")] + Integer, + /// A C-complaint identifier #[regex(r"[a-zA-Z_][a-zA-Z_0-9]*")] Identifier, @@ -61,22 +78,6 @@ pub enum Token { #[token("var")] Variable, - /// True, False - #[regex("true|false")] - Boolean, - - /// Always, Sometimes, Never - #[regex("always|sometimes|never")] - Aboolean, - - /// String - #[regex("\"(\\.|[^\"])*\"")] - String, - - /// Integer - #[regex(r"[0-9]+")] - Integer, - /// Prints the preceding things #[token("print")] Print,