Added tests and loop flow

This commit is contained in:
Erin 2021-05-02 18:12:51 +02:00 committed by ondra05
parent f8db60bc7c
commit d80b5514ce
5 changed files with 103 additions and 4 deletions

View file

@ -94,6 +94,12 @@ pub enum Token {
#[token("loop")]
Loop,
#[token("break")]
Break,
#[token("hopback")]
HopBack,
// Literals
/// True, False
#[regex("true|false", get_bool)]
@ -115,6 +121,9 @@ pub enum Token {
#[regex(r"[a-zA-Z_][a-zA-Z_0-9]*", get_iden)]
Identifier(String),
#[regex("nul")]
Nul,
#[token("(")]
LeftParenthesis,

View file

@ -3,7 +3,7 @@ use crate::variables::Value;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct Iden(pub String);
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum Item {
Expr(Expr),
Stmt(Stmt),
@ -15,13 +15,19 @@ impl From<Expr> for Item {
}
}
impl From<Iden> for Item {
fn from(i: Iden) -> Self {
Item::Expr(Expr::Identifier(i))
}
}
impl From<Stmt> for Item {
fn from(s: Stmt) -> Self {
Item::Stmt(s)
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Add { left: Box<Expr>, right: Box<Expr> },
Subtract { left: Box<Expr>, right: Box<Expr> },
@ -43,7 +49,7 @@ impl From<Iden> for Expr {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt {
VariableDeclaration {
iden: Iden,
@ -66,6 +72,11 @@ pub enum Stmt {
iden: Iden,
args: Vec<Expr>,
},
Loop {
body: Vec<Item>,
},
Break,
HopBack,
Print(Expr),
Melo(Iden),
}

View file

@ -67,10 +67,21 @@ impl<'a> Parser<'a> {
| Token::Boolean(_)
| Token::Integer(_)
| Token::String(_)
| Token::Nul
| Token::LogNot => self.parse_ops(token),
// Control flow
Token::If => self.if_cond(),
Token::Loop => self.loop_block(),
Token::HopBack => {
self.require(Token::Semicolon)?;
Ok(Stmt::HopBack.into())
}
Token::Break => {
self.require(Token::Semicolon)?;
Ok(Stmt::Break.into())
}
// Declarations
Token::Variable => self.variable_declaration(),
@ -194,6 +205,14 @@ impl<'a> Parser<'a> {
.into())
}
/// Parse loop
pub fn loop_block(&mut self) -> ParseResult {
self.require(Token::LeftBrace)?;
let body = self.parse_body()?;
Ok(Stmt::Loop { body }.into())
}
/// T-Dark block parsing
pub fn tdark_block(&mut self) -> Result<Vec<Item>, Error> {
self.require(Token::LeftBrace)?;
@ -221,3 +240,62 @@ impl<'a> Parser<'a> {
Ok(body)
}
}
#[cfg(test)]
mod tests {
use super::*;
use Expr::*;
use Stmt::*;
#[test]
fn control_flow() {
let code = r#"loop { var a = 3 + 2; if (a == 5) { break; } }"#;
let expected: &[Item] = &[Item::Stmt(Loop {
body: vec![
VariableDeclaration {
iden: Iden("a".to_owned()),
init: Some(Box::new(
Add {
left: Box::new(Literal(Value::Int(3))),
right: Box::new(Literal(Value::Int(2))),
}
.into(),
)),
}
.into(),
If {
cond: Box::new(
Eq {
left: Box::new(Iden("a".to_owned()).into()),
right: Box::new(Literal(Value::Int(5)).into()),
}
.into(),
),
body: vec![Break.into()],
}
.into(),
],
})];
let ast = Parser::new(code).init().unwrap();
assert_eq!(ast, expected)
}
#[test]
fn tdark() {
let code = r#"T-Dark { var lang = nul; lang print; }"#;
let expected: &[Item] = &[
VariableDeclaration {
iden: Iden("script".to_owned()),
init: Some(Box::new(Literal(Value::Nul).into())),
}
.into(),
Print(Iden("script".to_owned()).into()).into(),
];
let ast = Parser::new(code).init().unwrap();
assert_eq!(ast, expected)
}
}

View file

@ -83,6 +83,7 @@ impl<'a> Parser<'a> {
} else {
i
}))),
Token::Nul => Ok(Expr::Literal(Value::Nul)),
Token::LogNot => {
let next = self.lexer.next();
Ok(Expr::Not(Box::new(self.parse_expr(next)?)))

View file

@ -17,7 +17,7 @@ impl From<Abool> for bool {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum Value {
Str(String),
Int(i32),