2021-06-05 18:10:40 +00:00
|
|
|
use super::parse;
|
|
|
|
use super::parsed_statement::ParsedStatement;
|
2022-01-01 16:48:57 +00:00
|
|
|
use crate::modifiers::TypeModifier;
|
2021-06-05 18:50:15 +00:00
|
|
|
use crate::parsing::lexer::lex_tokens::{LexToken, TokenType};
|
2022-04-02 21:30:05 +00:00
|
|
|
use crate::parsing::parser::parsed_statement::ParsedStatement::DataTypeAuto;
|
|
|
|
use crate::parsing::parser::parser_operators::{BinaryOperator, PreOperator};
|
2021-06-05 18:50:15 +00:00
|
|
|
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
|
|
|
|
}
|
2021-06-05 18:10:40 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_empty_namespace() {
|
2021-06-05 19:03:14 +00:00
|
|
|
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| {
|
2022-01-01 16:48:57 +00:00
|
|
|
std::panic::panic_any(_message.stringify());
|
2021-06-05 19:03:14 +00:00
|
|
|
},
|
|
|
|
);
|
2022-01-01 16:48:57 +00:00
|
|
|
if let ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Namespace { identifier, script } = &statements[0] {
|
2021-06-05 18:10:40 +00:00
|
|
|
assert_eq!(identifier, "foo");
|
2022-01-01 16:48:57 +00:00
|
|
|
if let ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(0, statements.len());
|
2021-06-05 18:10:40 +00:00
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
2022-01-01 16:48:57 +00:00
|
|
|
|
|
|
|
#[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 ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Interface {
|
|
|
|
type_mod,
|
|
|
|
identifier,
|
|
|
|
inherits,
|
|
|
|
statements,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
|
|
|
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 ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Interface {
|
|
|
|
type_mod,
|
|
|
|
identifier,
|
|
|
|
inherits,
|
|
|
|
statements,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
|
|
|
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 ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Interface {
|
|
|
|
type_mod,
|
|
|
|
identifier,
|
|
|
|
inherits,
|
|
|
|
statements,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
|
|
|
assert!(type_mod.is_empty());
|
|
|
|
assert_eq!(identifier, "foo");
|
|
|
|
assert_eq!(inherits.len(), 0);
|
|
|
|
assert_eq!(statements.len(), 1);
|
|
|
|
if let ParsedStatement::VirtProp {
|
|
|
|
field_mod,
|
|
|
|
property_type,
|
|
|
|
identifier,
|
|
|
|
is_handle,
|
|
|
|
has_get,
|
|
|
|
is_get_const,
|
|
|
|
get_statement,
|
|
|
|
has_set,
|
|
|
|
is_set_const,
|
|
|
|
set_statement,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
2022-04-06 20:39:25 +00:00
|
|
|
assert_eq!(*field_mod, None);
|
2022-01-01 16:48:57 +00:00
|
|
|
if let ParsedStatement::Type {
|
2022-04-02 21:30:05 +00:00
|
|
|
is_const, datatype, ..
|
2022-01-01 16:48:57 +00:00
|
|
|
} = property_type.as_ref()
|
|
|
|
{
|
|
|
|
assert!(!is_const);
|
2022-04-02 21:30:05 +00:00
|
|
|
if let ParsedStatement::DataTypeIdentifier { identifier, .. } =
|
|
|
|
datatype.as_ref()
|
|
|
|
{
|
|
|
|
assert_eq!(identifier, "bar");
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
2022-01-01 16:48:57 +00:00
|
|
|
} 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!();
|
|
|
|
}
|
|
|
|
}
|
2022-04-02 21:30:05 +00:00
|
|
|
|
|
|
|
#[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),
|
2022-04-06 20:39:25 +00:00
|
|
|
TokenType::Semicolon,
|
2022-04-02 21:30:05 +00:00
|
|
|
TokenType::EndOfFile,
|
|
|
|
]),
|
|
|
|
&mut |_message, _span| {
|
|
|
|
std::panic::panic_any(_message.stringify());
|
|
|
|
},
|
|
|
|
);
|
|
|
|
if let ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Var {
|
|
|
|
modifier,
|
|
|
|
var_type,
|
|
|
|
identifier,
|
|
|
|
assignment,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
|
|
|
assert!(modifier.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
*var_type.as_ref(),
|
|
|
|
ParsedStatement::Type {
|
|
|
|
is_const: false,
|
|
|
|
scope: None,
|
|
|
|
datatype: Box::from(DataTypeAuto {}),
|
|
|
|
modifiers: vec![]
|
|
|
|
}
|
|
|
|
);
|
|
|
|
assert_eq!(identifier, "foo");
|
|
|
|
assert!(assignment.is_some());
|
|
|
|
assert_eq!(
|
|
|
|
*(assignment.as_ref().unwrap().as_ref()),
|
2022-04-03 13:25:26 +00:00
|
|
|
ParsedStatement::IntegerLiteral(100)
|
2022-04-02 21:30:05 +00:00
|
|
|
);
|
|
|
|
} 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),
|
2022-04-06 20:39:25 +00:00
|
|
|
TokenType::Semicolon,
|
2022-04-02 21:30:05 +00:00
|
|
|
TokenType::EndOfFile,
|
|
|
|
]),
|
|
|
|
&mut |_message, _span| {
|
|
|
|
std::panic::panic_any(_message.stringify());
|
|
|
|
},
|
|
|
|
);
|
|
|
|
if let ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Var {
|
|
|
|
modifier,
|
|
|
|
var_type,
|
|
|
|
identifier,
|
|
|
|
assignment,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
|
|
|
assert!(modifier.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
*var_type.as_ref(),
|
|
|
|
ParsedStatement::Type {
|
|
|
|
is_const: false,
|
|
|
|
scope: None,
|
|
|
|
datatype: Box::from(DataTypeAuto {}),
|
|
|
|
modifiers: vec![]
|
|
|
|
}
|
|
|
|
);
|
|
|
|
assert_eq!(identifier, "foo");
|
|
|
|
assert!(assignment.is_some());
|
|
|
|
assert_eq!(
|
|
|
|
*(assignment.as_ref().unwrap().as_ref()),
|
2022-04-03 13:25:26 +00:00
|
|
|
ParsedStatement::ExprPreOp {
|
|
|
|
operator: PreOperator::Negative,
|
|
|
|
operand: Box::from(ParsedStatement::IntegerLiteral(100)),
|
2022-04-02 21:30:05 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
} 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),
|
2022-04-06 20:39:25 +00:00
|
|
|
TokenType::Semicolon,
|
2022-04-02 21:30:05 +00:00
|
|
|
TokenType::EndOfFile,
|
|
|
|
]),
|
|
|
|
&mut |_message, _span| {
|
|
|
|
std::panic::panic_any(_message.stringify());
|
|
|
|
},
|
|
|
|
);
|
|
|
|
if let ParsedStatement::Script { statements } = script.as_ref() {
|
|
|
|
assert_eq!(1, statements.len());
|
|
|
|
if let ParsedStatement::Var {
|
|
|
|
modifier,
|
|
|
|
var_type,
|
|
|
|
identifier,
|
|
|
|
assignment,
|
|
|
|
} = &statements[0]
|
|
|
|
{
|
|
|
|
assert!(modifier.is_empty());
|
|
|
|
assert_eq!(
|
|
|
|
*var_type.as_ref(),
|
|
|
|
ParsedStatement::Type {
|
|
|
|
is_const: false,
|
|
|
|
scope: None,
|
|
|
|
datatype: Box::from(DataTypeAuto {}),
|
|
|
|
modifiers: vec![]
|
|
|
|
}
|
|
|
|
);
|
|
|
|
assert_eq!(identifier, "foo");
|
|
|
|
assert!(assignment.is_some());
|
|
|
|
assert_eq!(
|
|
|
|
*(assignment.as_ref().unwrap().as_ref()),
|
|
|
|
ParsedStatement::BinaryExpr {
|
2022-04-03 13:25:26 +00:00
|
|
|
left: Box::new(ParsedStatement::IntegerLiteral(100)),
|
2022-04-02 21:30:05 +00:00
|
|
|
operator: BinaryOperator::Addition,
|
2022-04-03 13:25:26 +00:00
|
|
|
right: Box::new(ParsedStatement::ExprPreOp {
|
|
|
|
operator: PreOperator::Negative,
|
|
|
|
operand: Box::new(ParsedStatement::IntegerLiteral(20)),
|
2022-04-02 21:30:05 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|