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

View file

@ -11,4 +11,4 @@ pub enum ErrorKind {
SyntaxError(String),
EndOfTokenStream,
InvalidIdentifier,
}
}

View file

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

View file

@ -3,11 +3,11 @@ mod utils;
use item::Expr;
use crate::tokens::Token;
use crate::{
error::{Error, ErrorKind},
variables::Value,
};
use crate::{parser::item::Iden, tokens::Token};
use logos::Logos;
@ -50,13 +50,28 @@ impl<'a> Parser<'a> {
let start = self.lexer.span().start;
match token {
// Control flow
Token::If => self.if_cond(),
// Declarations
Token::Variable => self.variable_declaration(),
Token::Function => self.function_declaration(),
Token::BfFunction => self.bff_declaration(),
// Literals
Token::String(x) => Ok(Expr::Literal(Value::Str(x))),
Token::Integer(x) => Ok(Expr::Literal(Value::Int(x))),
Token::Boolean(x) => Ok(Expr::Literal(Value::Bool(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 {
kind: ErrorKind::SyntaxError("Unexpected identifier".to_owned()),
position: start..self.lexer.span().end,
@ -99,25 +114,7 @@ impl<'a> Parser<'a> {
self.require(Token::LeftBrace)?;
// Parse function body
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))?);
}
let body = self.parse_body()?;
Ok(Expr::FunctionDeclaration { iden, body })
}
@ -161,4 +158,21 @@ impl<'a> Parser<'a> {
}
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::variables::Abool;
use super::Parser;
use super::{item::Expr, Parser};
pub fn abool2num(abool: Abool) -> i32 {
match abool {
@ -51,4 +51,27 @@ impl<'a> Parser<'a> {
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)]
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
/// True, False
#[regex("true|false", get_bool)]
@ -88,38 +120,6 @@ pub enum Token {
#[token("'.*'")]
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)]
#[error]
Error,
@ -184,4 +184,4 @@ mod tests {
let result: Vec<Token> = lexer.collect();
assert_eq!(result, expected);
}
}
}

View file

@ -29,4 +29,4 @@ pub enum Value {
pub struct Variable {
melo: bool,
value: Value,
}
}