Added function/variable parsing
- Added block support - TODO: Tidy it up
This commit is contained in:
parent
7026711b64
commit
3e2dc5fba9
|
@ -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
19
src/error.rs
Normal 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);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
#![forbid(unsafe_code)]
|
||||
|
||||
mod base_55;
|
||||
mod error;
|
||||
mod parser;
|
||||
mod tokens;
|
||||
mod variables;
|
||||
|
|
|
@ -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 },
|
||||
}
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue