Added parsing of conditionals

This commit is contained in:
Erin 2021-04-27 13:48:56 +02:00 committed by ondra05
parent 3f9e6b72cc
commit f3779deeb5
8 changed files with 108 additions and 59 deletions

View file

@ -1 +1,3 @@
bff a {+++<<>>>[]]]][[]]} if (true) {
var a = 3;
}

View file

@ -126,7 +126,8 @@ pub fn num2char(number: i32) -> char {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
#[test] fn str_to_base55() { #[test]
fn str_to_base55() {
let chrs: Vec<i32> = "AbleScript".chars().map(char2num).collect(); let chrs: Vec<i32> = "AbleScript".chars().map(char2num).collect();
assert_eq!(chrs, &[-1, 2, 12, 5, -19, 3, 18, 9, 16, 20]); assert_eq!(chrs, &[-1, 2, 12, 5, -19, 3, 18, 9, 16, 20]);
} }

View file

@ -1,5 +1,8 @@
use crate::variables::Value; use crate::variables::Value;
#[derive(Debug, Clone)]
pub struct Iden(pub String);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
VariableDeclaration { VariableDeclaration {
@ -14,5 +17,11 @@ pub enum Expr {
iden: String, iden: String,
body: String, body: String,
}, },
If {
cond: Box<Expr>,
body: Vec<Expr>,
},
Literal(Value), Literal(Value),
Melo(Iden),
} }

View file

@ -3,11 +3,11 @@ mod utils;
use item::Expr; use item::Expr;
use crate::tokens::Token;
use crate::{ use crate::{
error::{Error, ErrorKind}, error::{Error, ErrorKind},
variables::Value, variables::Value,
}; };
use crate::{parser::item::Iden, tokens::Token};
use logos::Logos; use logos::Logos;
@ -50,13 +50,28 @@ impl<'a> Parser<'a> {
let start = self.lexer.span().start; let start = self.lexer.span().start;
match token { match token {
// Control flow
Token::If => self.if_cond(),
// Declarations
Token::Variable => self.variable_declaration(), Token::Variable => self.variable_declaration(),
Token::Function => self.function_declaration(), Token::Function => self.function_declaration(),
Token::BfFunction => self.bff_declaration(), Token::BfFunction => self.bff_declaration(),
// Literals
Token::String(x) => Ok(Expr::Literal(Value::Str(x))), Token::String(x) => Ok(Expr::Literal(Value::Str(x))),
Token::Integer(x) => Ok(Expr::Literal(Value::Int(x))), Token::Integer(x) => Ok(Expr::Literal(Value::Int(x))),
Token::Boolean(x) => Ok(Expr::Literal(Value::Bool(x))), Token::Boolean(x) => Ok(Expr::Literal(Value::Bool(x))),
Token::Aboolean(x) => Ok(Expr::Literal(Value::Abool(x))), Token::Aboolean(x) => Ok(Expr::Literal(Value::Abool(x))),
// Prefix keywords
// Melo - ban variable from next usage (runtime error)
Token::Melo => {
let e = self.require_iden()?;
self.require(Token::Semicolon)?;
Ok(Expr::Melo(Iden(e)))
}
_ => Err(Error { _ => Err(Error {
kind: ErrorKind::SyntaxError("Unexpected identifier".to_owned()), kind: ErrorKind::SyntaxError("Unexpected identifier".to_owned()),
position: start..self.lexer.span().end, position: start..self.lexer.span().end,
@ -99,25 +114,7 @@ impl<'a> Parser<'a> {
self.require(Token::LeftBrace)?; self.require(Token::LeftBrace)?;
// Parse function body // Parse function body
let mut body = Vec::new(); let body = self.parse_body()?;
loop {
let token = {
match self.lexer.next() {
Some(t) => t,
None => {
return Err(Error {
kind: ErrorKind::EndOfTokenStream,
position: self.lexer.span(),
})
}
}
};
if token == Token::RightBrace {
break;
}
body.push(self.parse_expr(Some(token))?);
}
Ok(Expr::FunctionDeclaration { iden, body }) Ok(Expr::FunctionDeclaration { iden, body })
} }
@ -161,4 +158,21 @@ impl<'a> Parser<'a> {
} }
Ok(Expr::BfFDeclaration { iden, body }) Ok(Expr::BfFDeclaration { iden, body })
} }
/// Parse If-expression
pub fn if_cond(&mut self) -> Result<Expr, Error> {
self.require(Token::LeftParenthesis)?;
let cond = self.lexer.next();
let cond = self.parse_expr(cond)?;
self.require(Token::RightParenthesis)?;
self.require(Token::LeftBrace)?;
let body = self.parse_body()?;
Ok(Expr::If {
cond: Box::new(cond),
body,
})
}
} }

View file

@ -2,7 +2,7 @@ use crate::error::{Error, ErrorKind};
use crate::tokens::Token; use crate::tokens::Token;
use crate::variables::Abool; use crate::variables::Abool;
use super::Parser; use super::{item::Expr, Parser};
pub fn abool2num(abool: Abool) -> i32 { pub fn abool2num(abool: Abool) -> i32 {
match abool { match abool {
@ -51,4 +51,27 @@ impl<'a> Parser<'a> {
position: self.lexer.span(), position: self.lexer.span(),
} }
} }
pub(super) fn parse_body(&mut self) -> Result<Vec<Expr>, Error> {
let mut body = Vec::new();
loop {
let token = {
match self.lexer.next() {
Some(t) => t,
None => {
return Err(Error {
kind: ErrorKind::EndOfTokenStream,
position: self.lexer.span(),
})
}
}
};
if token == Token::RightBrace {
break;
}
body.push(self.parse_expr(Some(token))?);
}
Ok(body)
}
} }

View file

@ -4,6 +4,38 @@ use crate::variables::Abool;
#[derive(Logos, Debug, PartialEq, Clone)] #[derive(Logos, Debug, PartialEq, Clone)]
pub enum Token { pub enum Token {
#[token("functio")]
Function,
/// Brain fuck FFI
#[token("bff")]
BfFunction,
/// Variable bro
#[token("var")]
Variable,
/// Prints the preceding things
#[token("print")]
Print,
/// Ban the following variable from ever being used again
#[token("melo")]
Melo,
#[token("T-Dark")]
TDark,
// Expressions
#[token("if")]
If,
#[token("else")]
Else,
#[token("loop")]
Loop,
// Literals // Literals
/// True, False /// True, False
#[regex("true|false", get_bool)] #[regex("true|false", get_bool)]
@ -88,38 +120,6 @@ pub enum Token {
#[token("'.*'")] #[token("'.*'")]
Char, Char,
#[token("functio")]
Function,
/// Brain fuck FFI
#[token("bff")]
BfFunction,
/// Variable bro
#[token("var")]
Variable,
/// Prints the preceding things
#[token("print")]
Print,
/// Ban the following variable from ever being used again
#[token("melo")]
Melo,
#[token("T-Dark")]
TDark,
// Expressions
#[token("if")]
If,
#[token("else")]
Else,
#[token("loop")]
Loop,
#[regex(r"[ \t\n\f]+", logos::skip)] #[regex(r"[ \t\n\f]+", logos::skip)]
#[error] #[error]
Error, Error,