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;
var test;
functio 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)]
mod base_55;
mod error;
mod parser;
mod tokens;
mod variables;

View file

@ -1,4 +1,6 @@
#[derive(Debug, Clone)]
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 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<Expr>,
}
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<Expr> {
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<Expr, ParseError> {
fn variable_declaration(&mut self) -> Result<Expr, Error> {
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<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};
@ -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<String, ParseError> {
pub(super) fn require(&mut self, with: Token) -> Result<String, Error> {
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(),
})
}
}
}

View file

@ -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,