mirror of
https://github.com/Noratrieb/dilaria.git
synced 2026-01-16 18:35:02 +01:00
tests
This commit is contained in:
parent
c6200a901c
commit
7b1c7335c2
3 changed files with 245 additions and 17 deletions
|
|
@ -7,7 +7,7 @@ pub use span::Span;
|
||||||
|
|
||||||
mod span {
|
mod span {
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
|
#[derive(Debug, Default, Copy, Clone, PartialOrd, PartialEq, Ord, Eq, Hash)]
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
pub end: usize,
|
pub end: usize,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ impl<'code> Parser<'code> {
|
||||||
let mut stmts = Vec::new();
|
let mut stmts = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
if let Some(TokenType::BraceC) | None = self.peek_kind() {
|
if let Some(TokenType::BraceC) | None = self.peek_kind() {
|
||||||
let _ = self.next();
|
|
||||||
return Ok(stmts);
|
return Ok(stmts);
|
||||||
}
|
}
|
||||||
let stmt = self.statement()?;
|
let stmt = self.statement()?;
|
||||||
|
|
@ -176,7 +175,11 @@ impl<'code> Parser<'code> {
|
||||||
fn while_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
fn while_stmt(&mut self) -> ParseResult<'code, Stmt> {
|
||||||
let keyword_span = self.expect(TokenType::While)?.span;
|
let keyword_span = self.expect(TokenType::While)?.span;
|
||||||
let cond = self.expression()?;
|
let cond = self.expression()?;
|
||||||
|
|
||||||
|
self.inside_loop_depth += 1;
|
||||||
let body = self.block()?;
|
let body = self.block()?;
|
||||||
|
self.inside_loop_depth -= 1;
|
||||||
|
|
||||||
Ok(Stmt::While(WhileStmt {
|
Ok(Stmt::While(WhileStmt {
|
||||||
span: keyword_span.extend(body.span),
|
span: keyword_span.extend(body.span),
|
||||||
cond,
|
cond,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ use crate::parse::Parser;
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
|
||||||
mod prelude {
|
mod prelude {
|
||||||
pub(super) use super::{parser, test_literal_bin_op, test_number_literal, token};
|
pub(super) use super::{
|
||||||
|
empty_block, num_lit, parser, test_literal_bin_op, test_number_literal, token,
|
||||||
|
};
|
||||||
pub(super) use crate::ast::*;
|
pub(super) use crate::ast::*;
|
||||||
pub(super) use crate::errors::Span;
|
pub(super) use crate::errors::Span;
|
||||||
pub(super) use crate::lex::{
|
pub(super) use crate::lex::{
|
||||||
|
|
@ -19,6 +21,17 @@ fn token(kind: TokenType) -> Token {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn num_lit(number: f64) -> Expr {
|
||||||
|
Expr::Literal(Literal::Number(number, Span::dummy()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_block() -> Block {
|
||||||
|
Block {
|
||||||
|
stmts: vec![],
|
||||||
|
span: Span::dummy(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parser(tokens: Vec<Token>) -> Parser {
|
fn parser(tokens: Vec<Token>) -> Parser {
|
||||||
Parser {
|
Parser {
|
||||||
tokens: tokens.into_iter().peekable(),
|
tokens: tokens.into_iter().peekable(),
|
||||||
|
|
@ -39,8 +52,8 @@ fn test_literal_bin_op<F: FnOnce(Vec<Token<'_>>) -> Expr>(
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::BinaryOp(Box::new(BinaryOp {
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
lhs: num_lit(10.0),
|
||||||
rhs: Expr::Literal(Literal::Number(4.0, Span::dummy())),
|
rhs: num_lit(4.0),
|
||||||
kind: expected_op_kind
|
kind: expected_op_kind
|
||||||
})),
|
})),
|
||||||
factor
|
factor
|
||||||
|
|
@ -50,7 +63,147 @@ fn test_literal_bin_op<F: FnOnce(Vec<Token<'_>>) -> Expr>(
|
||||||
fn test_number_literal<F: FnOnce(Vec<Token<'_>>) -> Expr>(parser: F) {
|
fn test_number_literal<F: FnOnce(Vec<Token<'_>>) -> Expr>(parser: F) {
|
||||||
let tokens = [TokenType::Number(10.0)].map(token).into();
|
let tokens = [TokenType::Number(10.0)].map(token).into();
|
||||||
let unary = parser(tokens);
|
let unary = parser(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), unary);
|
assert_eq!(num_lit(10.0), unary);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod r#if {
|
||||||
|
use super::prelude::*;
|
||||||
|
|
||||||
|
fn parse_if(tokens: Vec<Token>) -> IfStmt {
|
||||||
|
let mut parser = parser(tokens);
|
||||||
|
parser.if_stmt().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty() {
|
||||||
|
let tokens = [If, True, BraceO, BraceC].map(token).into();
|
||||||
|
let ast = parse_if(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
IfStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block(),
|
||||||
|
else_part: None
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else() {
|
||||||
|
let tokens = [If, True, BraceO, BraceC, Else, BraceO, BraceC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let ast = parse_if(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
IfStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block(),
|
||||||
|
else_part: Some(Box::new(ElsePart::Else(empty_block(), Span::dummy())))
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else_if() {
|
||||||
|
let tokens = [If, True, BraceO, BraceC, Else, If, True, BraceO, BraceC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let ast = parse_if(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
IfStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block(),
|
||||||
|
else_part: Some(Box::new(ElsePart::ElseIf(
|
||||||
|
IfStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block(),
|
||||||
|
else_part: None
|
||||||
|
},
|
||||||
|
Span::dummy()
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn if_else_if_else() {
|
||||||
|
let tokens = [
|
||||||
|
If, True, BraceO, BraceC, Else, If, True, BraceO, BraceC, Else, BraceO, BraceC,
|
||||||
|
]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let ast = parse_if(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
IfStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block(),
|
||||||
|
else_part: Some(Box::new(ElsePart::ElseIf(
|
||||||
|
IfStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block(),
|
||||||
|
else_part: Some(Box::new(ElsePart::Else(empty_block(), Span::dummy())))
|
||||||
|
},
|
||||||
|
Span::dummy()
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod r#while {
|
||||||
|
use super::prelude::*;
|
||||||
|
|
||||||
|
fn parse_while(tokens: Vec<Token>) -> Stmt {
|
||||||
|
let mut parser = parser(tokens);
|
||||||
|
parser.while_stmt().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty() {
|
||||||
|
let tokens = [While, True, BraceO, BraceC].map(token).into();
|
||||||
|
let ast = parse_while(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Stmt::While(WhileStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
body: empty_block()
|
||||||
|
}),
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn or_condition_break() {
|
||||||
|
let tokens = [While, False, Or, True, BraceO, Break, Semi, BraceC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let ast = parse_while(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Stmt::While(WhileStmt {
|
||||||
|
span: Span::dummy(),
|
||||||
|
cond: Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
|
span: Span::dummy(),
|
||||||
|
lhs: Expr::Literal(Literal::Boolean(false, Span::dummy())),
|
||||||
|
rhs: Expr::Literal(Literal::Boolean(true, Span::dummy())),
|
||||||
|
kind: BinaryOpKind::Or
|
||||||
|
})),
|
||||||
|
body: Block {
|
||||||
|
stmts: vec![Stmt::Break(Span::dummy())],
|
||||||
|
span: Span::dummy()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod r#loop {
|
mod r#loop {
|
||||||
|
|
@ -65,10 +218,38 @@ mod r#loop {
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let tokens = [Loop, BraceO, BraceC].map(token).into();
|
let tokens = [Loop, BraceO, BraceC].map(token).into();
|
||||||
let ast = parse_loop(tokens);
|
let ast = parse_loop(tokens);
|
||||||
|
assert_eq!(Stmt::Loop(empty_block(), Span::dummy()), ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn with_break() {
|
||||||
|
let tokens = [Loop, BraceO, Break, Semi, BraceC].map(token).into();
|
||||||
|
let ast = parse_loop(tokens);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Stmt::Loop(
|
Stmt::Loop(
|
||||||
Block {
|
Block {
|
||||||
stmts: vec![],
|
stmts: vec![Stmt::Break(Span::dummy())],
|
||||||
|
span: Default::default()
|
||||||
|
},
|
||||||
|
Span::dummy()
|
||||||
|
),
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn break_after_inner() {
|
||||||
|
let tokens = [Loop, BraceO, Loop, BraceO, BraceC, Break, Semi, BraceC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let ast = parse_loop(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Stmt::Loop(
|
||||||
|
Block {
|
||||||
|
stmts: vec![
|
||||||
|
Stmt::Loop(empty_block(), Span::dummy()),
|
||||||
|
Stmt::Break(Span::dummy())
|
||||||
|
],
|
||||||
span: Span::dummy()
|
span: Span::dummy()
|
||||||
},
|
},
|
||||||
Span::dummy()
|
Span::dummy()
|
||||||
|
|
@ -78,6 +259,50 @@ mod r#loop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod block {
|
||||||
|
use super::prelude::*;
|
||||||
|
|
||||||
|
fn parse_block(tokens: Vec<Token>) -> Block {
|
||||||
|
let mut parser = parser(tokens);
|
||||||
|
parser.block().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty() {
|
||||||
|
let tokens = [BraceO, BraceC].map(token).into();
|
||||||
|
let ast = parse_block(tokens);
|
||||||
|
assert_eq!(empty_block(), ast);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn two_expressions() {
|
||||||
|
let tokens = [BraceO, Number(10.0), Semi, Number(20.0), Semi, BraceC]
|
||||||
|
.map(token)
|
||||||
|
.into();
|
||||||
|
let ast = parse_block(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Block {
|
||||||
|
stmts: vec![Stmt::Expr(num_lit(10.0)), Stmt::Expr(num_lit(20.0)),],
|
||||||
|
span: Span::dummy()
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested() {
|
||||||
|
let tokens = [BraceO, BraceO, BraceC, BraceC].map(token).into();
|
||||||
|
let ast = parse_block(tokens);
|
||||||
|
assert_eq!(
|
||||||
|
Block {
|
||||||
|
stmts: vec![Stmt::Block(empty_block())],
|
||||||
|
span: Span::dummy()
|
||||||
|
},
|
||||||
|
ast
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod expr {
|
mod expr {
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use crate::ast::{UnaryOp, UnaryOpKind};
|
use crate::ast::{UnaryOp, UnaryOpKind};
|
||||||
|
|
@ -101,11 +326,11 @@ mod expr {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::BinaryOp(Box::new(BinaryOp {
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
lhs: num_lit(10.0),
|
||||||
rhs: Expr::BinaryOp(Box::new(BinaryOp {
|
rhs: Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
lhs: Expr::Literal(Literal::Number(20.0, Span::dummy())),
|
lhs: num_lit(20.0),
|
||||||
rhs: Expr::Literal(Literal::Number(100.0, Span::dummy())),
|
rhs: num_lit(100.0),
|
||||||
|
|
||||||
kind: BinaryOpKind::Mul
|
kind: BinaryOpKind::Mul
|
||||||
})),
|
})),
|
||||||
|
|
@ -124,10 +349,10 @@ mod expr {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::BinaryOp(Box::new(BinaryOp {
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
lhs: num_lit(10.0),
|
||||||
rhs: Expr::UnaryOp(Box::new(UnaryOp {
|
rhs: Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
expr: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
expr: num_lit(10.0),
|
||||||
kind: UnaryOpKind::Neg
|
kind: UnaryOpKind::Neg
|
||||||
})),
|
})),
|
||||||
kind: BinaryOpKind::Equal
|
kind: BinaryOpKind::Equal
|
||||||
|
|
@ -153,11 +378,11 @@ mod expr {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::BinaryOp(Box::new(BinaryOp {
|
Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
lhs: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
lhs: num_lit(10.0),
|
||||||
rhs: Expr::BinaryOp(Box::new(BinaryOp {
|
rhs: Expr::BinaryOp(Box::new(BinaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
lhs: Expr::Literal(Literal::Number(20.0, Span::dummy())),
|
lhs: num_lit(20.0),
|
||||||
rhs: Expr::Literal(Literal::Number(30.0, Span::dummy())),
|
rhs: num_lit(30.0),
|
||||||
|
|
||||||
kind: BinaryOpKind::Add
|
kind: BinaryOpKind::Add
|
||||||
})),
|
})),
|
||||||
|
|
@ -364,7 +589,7 @@ mod unary {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Expr::UnaryOp(Box::new(UnaryOp {
|
Expr::UnaryOp(Box::new(UnaryOp {
|
||||||
span: Span::dummy(),
|
span: Span::dummy(),
|
||||||
expr: Expr::Literal(Literal::Number(10.0, Span::dummy())),
|
expr: num_lit(10.0),
|
||||||
kind: UnaryOpKind::Neg
|
kind: UnaryOpKind::Neg
|
||||||
})),
|
})),
|
||||||
unary
|
unary
|
||||||
|
|
@ -397,7 +622,7 @@ mod primary {
|
||||||
fn string() {
|
fn string() {
|
||||||
let tokens = [TokenType::Number(10.0)].map(token).into();
|
let tokens = [TokenType::Number(10.0)].map(token).into();
|
||||||
let literal = parse_primary(tokens);
|
let literal = parse_primary(tokens);
|
||||||
assert_eq!(Expr::Literal(Literal::Number(10.0, Span::dummy())), literal);
|
assert_eq!(num_lit(10.0), literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue