SeraphScript/src/parsing/parser/parser_tests.rs

405 lines
13 KiB
Rust

use super::parse;
use super::parsed_statement::ParsedStatement;
use crate::modifiers::TypeModifier;
use crate::parsing::lexer::lex_tokens::TokenType::AutoKeyword;
use crate::parsing::lexer::lex_tokens::{LexToken, TokenType};
use crate::parsing::parser::parsed_statement::ParsedStatementData;
use crate::parsing::parser::parser_operators::{BinaryOperator, PreOperator};
use crate::span::Span;
fn create_tokens(types: Vec<TokenType>) -> Vec<LexToken> {
let mut v = Vec::with_capacity(types.len());
for t in types {
v.push(LexToken {
token_type: t,
span: Span::new(0, 0),
});
}
v
}
#[test]
fn test_empty_namespace() {
let script = parse(
create_tokens(vec![
TokenType::NamespaceKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::OpenCurlyBracket,
TokenType::CloseCurlyBracket,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Namespace { identifier, script } = &statements[0].as_ref().data
{
assert_eq!(identifier, "foo");
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(0, statements.len());
} else {
unreachable!();
}
} else {
unreachable!()
}
} else {
unreachable!();
}
}
#[test]
fn test_empty_interface() {
let script = parse(
create_tokens(vec![
TokenType::InterfaceKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::OpenCurlyBracket,
TokenType::CloseCurlyBracket,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Interface {
type_mod,
identifier,
inherits,
statements,
} = &statements[0].as_ref().data
{
assert!(type_mod.is_empty());
assert_eq!(identifier, "foo");
assert_eq!(inherits.len(), 0);
assert_eq!(statements.len(), 0);
} else {
unreachable!()
}
} else {
unreachable!();
}
}
#[test]
fn test_empty_external_shared_interface() {
let script = parse(
create_tokens(vec![
TokenType::ExternalKeyword,
TokenType::SharedKeyword,
TokenType::InterfaceKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::OpenCurlyBracket,
TokenType::CloseCurlyBracket,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Interface {
type_mod,
identifier,
inherits,
statements,
} = &statements[0].as_ref().data
{
assert!(!type_mod.is_empty());
assert!(type_mod.contains(TypeModifier::External));
assert!(type_mod.contains(TypeModifier::Shared));
assert_eq!(identifier, "foo");
assert_eq!(inherits.len(), 0);
assert_eq!(statements.len(), 0);
} else {
unreachable!()
}
} else {
unreachable!();
}
}
#[test]
fn test_interface_with_virtprop() {
let script = parse(
create_tokens(vec![
TokenType::InterfaceKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::OpenCurlyBracket,
TokenType::Identifier("bar".to_string()),
TokenType::Identifier("get_bar".to_string()),
TokenType::OpenCurlyBracket,
TokenType::GetKeyword,
TokenType::Semicolon,
TokenType::SetKeyword,
TokenType::Semicolon,
TokenType::CloseCurlyBracket,
TokenType::CloseCurlyBracket,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Interface {
type_mod,
identifier,
inherits,
statements,
} = &statements[0].as_ref().data
{
assert!(type_mod.is_empty());
assert_eq!(identifier, "foo");
assert_eq!(inherits.len(), 0);
assert_eq!(statements.len(), 1);
if let ParsedStatementData::VirtProp {
field_mod,
property_type,
identifier,
is_handle,
has_get,
is_get_const,
get_statement,
has_set,
is_set_const,
set_statement,
} = &statements[0].as_ref().data
{
assert_eq!(*field_mod, None);
if let ParsedStatementData::Type {
is_const, datatype, ..
} = &property_type.as_ref().data
{
assert!(!is_const);
if let ParsedStatementData::DataTypeIdentifier { identifier, .. } =
&datatype.as_ref().data
{
assert_eq!(identifier, "bar");
} else {
unreachable!()
}
} else {
unreachable!()
}
assert_eq!(identifier, "get_bar");
assert!(has_get);
assert!(!is_get_const);
assert!(has_set);
assert!(!is_set_const);
assert!(get_statement.is_none());
assert!(set_statement.is_none());
assert!(!is_handle);
} else {
unreachable!()
}
} else {
unreachable!()
}
} else {
unreachable!();
}
}
#[test]
fn test_assign_to_global_variable() {
let script = parse(
create_tokens(vec![
TokenType::AutoKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::Equals,
TokenType::WhiteSpace,
TokenType::IntegerLiteral(100),
TokenType::Semicolon,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Var {
modifier,
var_type,
identifier,
assignment,
} = &statements[0].as_ref().data
{
assert!(modifier.is_empty());
assert_eq!(
var_type.as_ref().data,
ParsedStatementData::Type {
is_const: false,
scope: None,
datatype: Box::from(ParsedStatement {
data: ParsedStatementData::DataTypeAuto,
span: Span { start: 0, end: 0 }
}),
modifiers: vec![]
}
);
assert_eq!(identifier, "foo");
assert!(assignment.is_some());
assert_eq!(
(assignment.as_ref().unwrap().as_ref()).data,
ParsedStatementData::IntegerLiteral(100)
);
} else {
unreachable!()
}
} else {
unreachable!();
}
}
#[test]
fn test_assign_negative_to_global_variable() {
let script = parse(
create_tokens(vec![
TokenType::AutoKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::Equals,
TokenType::WhiteSpace,
TokenType::Minus,
TokenType::IntegerLiteral(100),
TokenType::Semicolon,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Var {
modifier,
var_type,
identifier,
assignment,
} = &statements[0].as_ref().data
{
assert!(modifier.is_empty());
assert_eq!(
var_type.as_ref().data,
ParsedStatementData::Type {
is_const: false,
scope: None,
datatype: Box::from(ParsedStatement {
data: ParsedStatementData::DataTypeAuto,
span: Span { start: 0, end: 0 }
}),
modifiers: vec![]
}
);
assert_eq!(identifier, "foo");
assert!(assignment.is_some());
assert_eq!(
(assignment.as_ref().unwrap().as_ref()).data,
ParsedStatementData::ExprPreOp {
operator: PreOperator::Negative,
operand: Box::from(ParsedStatement {
data: ParsedStatementData::IntegerLiteral(100),
span: Span { start: 0, end: 0 }
}),
}
);
} else {
unreachable!()
}
} else {
unreachable!();
}
}
#[test]
fn test_assign_addition_to_global_variable() {
let script = parse(
create_tokens(vec![
TokenType::AutoKeyword,
TokenType::WhiteSpace,
TokenType::Identifier("foo".to_string()),
TokenType::WhiteSpace,
TokenType::Equals,
TokenType::WhiteSpace,
TokenType::IntegerLiteral(100),
TokenType::Plus,
TokenType::Minus,
TokenType::IntegerLiteral(20),
TokenType::Semicolon,
TokenType::EndOfFile,
]),
&mut |_message, _span| {
std::panic::panic_any(_message.stringify());
},
);
if let ParsedStatementData::Script { statements } = &script.as_ref().data {
assert_eq!(1, statements.len());
if let ParsedStatementData::Var {
modifier,
var_type,
identifier,
assignment,
} = &statements[0].as_ref().data
{
assert!(modifier.is_empty());
assert_eq!(
var_type.as_ref().data,
ParsedStatementData::Type {
is_const: false,
scope: None,
datatype: Box::from(ParsedStatement {
data: ParsedStatementData::DataTypeAuto,
span: Span { start: 0, end: 0 }
}),
modifiers: vec![]
}
);
assert_eq!(identifier, "foo");
assert!(assignment.is_some());
assert_eq!(
(assignment.as_ref().unwrap().as_ref()).data,
ParsedStatementData::BinaryExpr {
left: Box::new(ParsedStatement {
data: ParsedStatementData::IntegerLiteral(100),
span: Span { start: 0, end: 0 }
}),
operator: BinaryOperator::Addition,
right: Box::new(ParsedStatement {
data: ParsedStatementData::ExprPreOp {
operator: PreOperator::Negative,
operand: Box::new(ParsedStatement {
data: ParsedStatementData::IntegerLiteral(20),
span: Span { start: 0, end: 0 }
}),
},
span: Span { start: 0, end: 0 }
}),
}
);
} else {
unreachable!()
}
} else {
unreachable!();
}
}