forked from AbleScript/ablescript
Added parsing of conditionals
This commit is contained in:
parent
fc8c3a3499
commit
00a464321a
|
@ -1 +1,3 @@
|
||||||
bff a {+++<<>>>[]]]][[]]}
|
if (true) {
|
||||||
|
var a = 3;
|
||||||
|
}
|
|
@ -126,8 +126,9 @@ 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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,4 +11,4 @@ pub enum ErrorKind {
|
||||||
SyntaxError(String),
|
SyntaxError(String),
|
||||||
EndOfTokenStream,
|
EndOfTokenStream,
|
||||||
InvalidIdentifier,
|
InvalidIdentifier,
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -184,4 +184,4 @@ mod tests {
|
||||||
let result: Vec<Token> = lexer.collect();
|
let result: Vec<Token> = lexer.collect();
|
||||||
assert_eq!(result, expected);
|
assert_eq!(result, expected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,4 +29,4 @@ pub enum Value {
|
||||||
pub struct Variable {
|
pub struct Variable {
|
||||||
melo: bool,
|
melo: bool,
|
||||||
value: Value,
|
value: Value,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue