Added function/variable parsing

- Added block support
- TODO: Tidy it up
This commit is contained in:
Erin 2021-04-18 22:33:55 +02:00 committed by ondra05
parent 48dd930872
commit 7e0c881130
7 changed files with 114 additions and 37 deletions

View file

@ -1,2 +1,10 @@
var hello = true; functio test() {
var test; functio nested() {
var c = false;
}
var a = true;
}
functio another() {
var b = false;
}

19
src/error.rs Normal file
View file

@ -0,0 +1,19 @@
use std::ops::Range;
#[derive(Debug, Clone)]
pub struct Error {
pub kind: ErrorKind,
pub position: Range<usize>,
}
#[derive(Debug, Clone)]
pub enum ErrorKind {
SyntaxError,
}
impl Error {
pub fn panic(&self, span: &str) {
println!("{:?} occured at {:?}", self.kind, self.position);
println!(" {}", &span);
}
}

View file

@ -1,6 +1,7 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
mod base_55; mod base_55;
mod error;
mod parser; mod parser;
mod tokens; mod tokens;
mod variables; mod variables;

View file

@ -1,4 +1,6 @@
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
DeclareVariable { iden: String, init: Option<String> }, VariableDeclaration { iden: String, init: Option<String> },
} FunctionDeclaration { iden: String, body: Vec<Expr> },
BfFDeclaration { iden: String, code: String },
}

View file

@ -3,8 +3,11 @@ mod utils;
use item::Expr; use item::Expr;
use crate::tokens::Token;
use crate::variables::Value; use crate::variables::Value;
use crate::{
error::{Error, ErrorKind},
tokens::Token,
};
use logos::Logos; use logos::Logos;
@ -18,7 +21,6 @@ pub enum ParseError {
/// Parser structure / state machine /// Parser structure / state machine
pub struct Parser<'a> { pub struct Parser<'a> {
lexer: logos::Lexer<'a, Token>, lexer: logos::Lexer<'a, Token>,
ast: Vec<Expr>,
} }
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
@ -26,31 +28,39 @@ impl<'a> Parser<'a> {
pub fn new(source: &'a str) -> Self { pub fn new(source: &'a str) -> Self {
Self { Self {
lexer: Token::lexer(source), lexer: Token::lexer(source),
ast: vec![],
} }
} }
/// Start parsing Token Vector into Abstract Syntax Tree /// Start parsing Token Vector into Abstract Syntax Tree
pub fn parse(&mut self) -> Vec<Expr> { pub fn parse(&mut self) -> Vec<Expr> {
let mut ast = vec![];
while let Some(token) = self.lexer.next() { while let Some(token) = self.lexer.next() {
let expr = match token { let expr = match token {
Token::Variable => self.variable(), Token::Variable => self.variable_declaration(),
tok => { Token::Function => self.function_declaration(),
// TODO: Better error handling Token::BfFunction => self.bff_declaration(),
println!("Parse error"); 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; break;
} }
}; }
self.ast.push(expr.unwrap());
} }
self.ast.clone() ast
} }
/// Parse variable declaration /// Parse variable declaration
/// ///
/// `var [iden] = [literal];` /// `var [iden] = [literal];`
fn variable(&mut self) -> Result<Expr, ParseError> { fn variable_declaration(&mut self) -> Result<Expr, Error> {
let iden = self.require(Token::Identifier)?; let iden = self.require(Token::Identifier)?;
let init = match self.lexer.next() { let init = match self.lexer.next() {
@ -60,9 +70,39 @@ impl<'a> Parser<'a> {
self.require(Token::Semicolon)?; self.require(Token::Semicolon)?;
Some(value) 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<Expr, Error> {
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<Expr, Error> {
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 })
} }
} }

View file

@ -1,4 +1,7 @@
use crate::tokens::{Abool, Token}; use crate::{
error::{Error, ErrorKind},
tokens::{Abool, Token},
};
use super::{ParseError, Parser}; use super::{ParseError, Parser};
@ -20,11 +23,14 @@ pub fn num2abool(number: i32) -> Abool {
impl<'a> Parser<'a> { impl<'a> Parser<'a> {
/// Require type of token as next and return it's value (sometimes irrelevant) /// Require type of token as next and return it's value (sometimes irrelevant)
pub(super) fn require(&mut self, with: Token) -> Result<String, ParseError> { pub(super) fn require(&mut self, with: Token) -> Result<String, Error> {
if self.lexer.next() == Some(with) { if self.lexer.next() == Some(with) {
Ok(self.lexer.slice().to_owned()) Ok(self.lexer.slice().to_owned())
} else { } else {
Err(ParseError::UnexpectedToken) Err(Error {
kind: ErrorKind::SyntaxError,
position: self.lexer.span(),
})
} }
} }
} }

View file

@ -2,6 +2,23 @@ use logos::Logos;
#[derive(Logos, Debug, PartialEq)] #[derive(Logos, Debug, PartialEq)]
pub enum Token { 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 /// A C-complaint identifier
#[regex(r"[a-zA-Z_][a-zA-Z_0-9]*")] #[regex(r"[a-zA-Z_][a-zA-Z_0-9]*")]
Identifier, Identifier,
@ -61,22 +78,6 @@ pub enum Token {
#[token("var")] #[token("var")]
Variable, 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 /// Prints the preceding things
#[token("print")] #[token("print")]
Print, Print,