use super::*;
use std::io;
#[test]
fn parse_works() -> io::Result<()> {
let src1 = io::Cursor::new(SRC1);
let statements1 = parse(src1)?.unwrap();
assert_eq!(statements1, get_src1_statements());
let src2 = io::Cursor::new(SRC2);
let statements2 = parse(src2)?.unwrap();
assert_eq!(statements2, get_src2_statements());
Ok(())
}
#[test]
fn parser_parse_expr_works() {
let mut parser = Parser::new();
let bool_var1 = "boolVar1";
let int_var1 = "intVar1";
let str_var1 = "strVar1";
let int_arr1 = "intArr1";
[
(bool_var1, VarType::Boolean),
(int_var1, VarType::Integer),
(str_var1, VarType::String),
(int_arr1, VarType::ArrayOfInteger(5)),
]
.iter()
.for_each(|(v, t)| {
parser.variables.insert(v.to_string(), *t);
});
let src = vec![
(
vec![(1, Token::Boolean(true))],
Expr::LitBoolean(true),
"True",
),
(
vec![(1, Token::Integer(1234))],
Expr::LitInteger(1234),
"1234",
),
(
vec![(1, Token::String("text".into()))],
Expr::LitString("text".into()),
r#""text""#,
),
(
vec![(1, Token::Name(bool_var1.into()))],
Expr::VarBoolean(bool_var1.into()),
"boolVar1",
),
(
vec![(1, Token::Name(int_var1.into()))],
Expr::VarInteger(int_var1.into()),
"intVar1",
),
(
vec![(1, Token::Name(str_var1.into()))],
Expr::VarString(str_var1.into()),
"strVar1",
),
(
vec![
(1, Token::Operator(Operator::Not)),
(2, Token::Boolean(true)),
],
Expr::UnaryOperatorBoolean(Operator::Not, Box::new(Expr::LitBoolean(true))),
"Not(True)",
),
(
vec![
(1, Token::Operator(Operator::Sub)),
(2, Token::Integer(1234)),
],
Expr::LitInteger(-1234),
"-1234",
),
(
vec![
(1, Token::Operator(Operator::Sub)),
(2, Token::Integer(0x8000)),
],
Expr::LitInteger(-0x8000),
"-32768",
),
(
vec![
(1, Token::Operator(Operator::Not)),
(2, Token::Integer(1234)),
],
Expr::UnaryOperatorInteger(Operator::Not, Box::new(Expr::LitInteger(1234))),
"Not(1234)",
),
(
vec![
(1, Token::Operator(Operator::Not)),
(2, Token::Name(bool_var1.into())),
],
Expr::UnaryOperatorBoolean(Operator::Not, Box::new(Expr::VarBoolean(bool_var1.into()))),
"Not(boolVar1)",
),
(
vec![
(1, Token::Operator(Operator::Not)),
(2, Token::Name(int_var1.into())),
],
Expr::UnaryOperatorInteger(Operator::Not, Box::new(Expr::VarInteger(int_var1.into()))),
"Not(intVar1)",
),
(
vec![
(1, Token::Operator(Operator::Sub)),
(2, Token::Name(int_var1.into())),
],
Expr::UnaryOperatorInteger(Operator::Sub, Box::new(Expr::VarInteger(int_var1.into()))),
"-(intVar1)",
),
(
vec![
(1, Token::Integer(123)),
(2, Token::Operator(Operator::Add)),
(3, Token::Integer(456)),
],
Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::LitInteger(123)),
Box::new(Expr::LitInteger(456)),
),
"(123 + 456)",
),
(
vec![
(1, Token::Integer(1)),
(2, Token::Operator(Operator::Add)),
(3, Token::Integer(1)),
(4, Token::Operator(Operator::Add)),
(5, Token::Integer(1)),
(6, Token::Operator(Operator::Add)),
(7, Token::Integer(1)),
(8, Token::Operator(Operator::Add)),
(9, Token::Integer(1)),
],
Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::LitInteger(1)),
Box::new(Expr::LitInteger(1)),
)),
Box::new(Expr::LitInteger(1)),
)),
Box::new(Expr::LitInteger(1)),
)),
Box::new(Expr::LitInteger(1)),
),
"((((1 + 1) + 1) + 1) + 1)",
),
(
vec![
(1, Token::Operator(Operator::Sub)),
(2, Token::Integer(123)),
(3, Token::Operator(Operator::Add)),
(4, Token::Operator(Operator::Sub)),
(5, Token::Integer(456)),
],
Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::LitInteger(-123)),
Box::new(Expr::LitInteger(-456)),
),
"(-123 + -456)",
),
(
vec![
(1, Token::Integer(12)),
(2, Token::Operator(Operator::Add)),
(3, Token::Operator(Operator::Sub)),
(4, Token::Integer(34)),
(5, Token::Operator(Operator::Mul)),
(6, Token::Integer(56)),
],
Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::LitInteger(12)),
Box::new(Expr::BinaryOperatorInteger(
Operator::Mul,
Box::new(Expr::LitInteger(-34)),
Box::new(Expr::LitInteger(56)),
)),
),
"(12 + (-34 * 56))",
),
(
vec![
(1, Token::Name(int_var1.into())),
(2, Token::Operator(Operator::Equal)),
(3, Token::Integer(12)),
(4, Token::Operator(Operator::Or)),
(5, Token::Name(bool_var1.into())),
],
Expr::BinaryOperatorBoolean(
Operator::Or,
Box::new(Expr::BinaryOperatorBoolean(
Operator::Equal,
Box::new(Expr::VarInteger(int_var1.into())),
Box::new(Expr::LitInteger(12)),
)),
Box::new(Expr::VarBoolean(bool_var1.into())),
),
"((intVar1 = 12) Or boolVar1)",
),
(
vec![
(1, Token::Integer(3)),
(2, Token::Operator(Operator::Mul)),
(3, Token::Name(int_arr1.into())),
(4, Token::Operator(Operator::OpenBracket)),
(5, Token::Integer(5)),
(6, Token::Operator(Operator::Mul)),
(7, Token::Integer(10)),
(8, Token::Operator(Operator::CloseBracket)),
(9, Token::Operator(Operator::And)),
(10, Token::Integer(4)),
],
Expr::BinaryOperatorInteger(
Operator::And,
Box::new(Expr::BinaryOperatorInteger(
Operator::Mul,
Box::new(Expr::LitInteger(3)),
Box::new(Expr::VarArrayOfInteger(
int_arr1.into(),
Box::new(Expr::BinaryOperatorInteger(
Operator::Mul,
Box::new(Expr::LitInteger(5)),
Box::new(Expr::LitInteger(10)),
)),
)),
)),
Box::new(Expr::LitInteger(4)),
),
"((3 * intArr1(5 * 10)) And 4)",
),
(
vec![
(1, Token::Operator(Operator::Sub)),
(2, Token::Function(Function::Max)),
(3, Token::Operator(Operator::OpenBracket)),
(4, Token::Integer(123)),
(5, Token::Operator(Operator::Comma)),
(6, Token::Integer(456)),
(7, Token::Operator(Operator::CloseBracket)),
(8, Token::Operator(Operator::Add)),
(9, Token::Operator(Operator::Sub)),
(10, Token::Operator(Operator::OpenBracket)),
(11, Token::Integer(987)),
(12, Token::Operator(Operator::Sub)),
(13, Token::Integer(321)),
(14, Token::Operator(Operator::CloseBracket)),
(15, Token::Operator(Operator::Mul)),
(16, Token::Operator(Operator::Not)),
(17, Token::Name(int_var1.into())),
],
Expr::BinaryOperatorInteger(
Operator::Add,
Box::new(Expr::UnaryOperatorInteger(
Operator::Sub,
Box::new(Expr::FunctionInteger(
Function::Max,
Box::new(Expr::ParamList(vec![
Expr::LitInteger(123),
Expr::LitInteger(456),
])),
)),
)),
Box::new(Expr::BinaryOperatorInteger(
Operator::Mul,
Box::new(Expr::UnaryOperatorInteger(
Operator::Sub,
Box::new(Expr::BinaryOperatorInteger(
Operator::Sub,
Box::new(Expr::LitInteger(987)),
Box::new(Expr::LitInteger(321)),
)),
)),
Box::new(Expr::UnaryOperatorInteger(
Operator::Not,
Box::new(Expr::VarInteger(int_var1.into())),
)),
)),
),
"(-(Max(123, 456)) + (-((987 - 321)) * Not(intVar1)))",
),
];
for (tokens, expr, disp) in src {
assert_eq!(parser.parse_expr(&tokens).unwrap(), expr);
assert_eq!(expr.to_string(), disp);
}
}
const SRC1: &str = r#"
Dim i As Integer
Dim c As Integer
Print "Limit?"
Input c
c = Max(1, Min(100, c))
For i = 1 To c Step 1
Select Case i Mod 15
Case 0
Print "FizzBuzz"
Case 3, 6, 9, 12
Print "Fizz"
Case 5, 10
Print "Buzz"
Case Else
Print i
End Select
Next i
"#;
const SRC2: &str = r#"
Dim s As String
Dim n As Integer
Do
Print "Number?"
Input s
If s = "end" Then
Exit Do
End If
n = CInt(s)
If n < 1 Then
Print "Invalid Input"
Continue Do
End If
If n Mod 15 = 0 Then
s = "FizzBuzz"
ElseIf n Mod 3 = 0 Then
s = "Fizz"
ElseIf n Mod 5 = 0 Then
s = "Buzz"
End If
Print s
Loop
"#;
fn get_src1_statements() -> Vec<Statement> {
vec![
Statement::Dim {
var_name: "i".into(),
var_type: VarType::Integer,
},
Statement::Dim {
var_name: "c".into(),
var_type: VarType::Integer,
},
Statement::PrintLitString {
value: "Limit?".into(),
},
Statement::InputInteger {
var_name: "c".into(),
},
Statement::AssignInteger {
var_name: "c".into(),
value: Expr::FunctionInteger(
Function::Max,
Box::new(Expr::ParamList(vec![
Expr::LitInteger(1),
Expr::FunctionInteger(
Function::Min,
Box::new(Expr::ParamList(vec![
Expr::LitInteger(100),
Expr::VarInteger("c".into()),
])),
),
])),
),
},
Statement::For {
exit_id: 0,
counter: "i".into(),
counter_is_ref: false,
init: Expr::LitInteger(1),
end: Expr::VarInteger("c".into()),
step: Some(Expr::LitInteger(1)),
block: vec![
Statement::SelectInteger {
exit_id: 1,
value: Expr::BinaryOperatorInteger(
Operator::Mod,
Box::new(Expr::VarInteger("i".into())),
Box::new(Expr::LitInteger(15)),
),
case_blocks: vec![
Statement::CaseInteger {
values: vec![CaseIntegerItem::Integer(0)],
block: vec![
Statement::PrintLitString {
value: "FizzBuzz".into(),
},
],
},
Statement::CaseInteger {
values: vec![
CaseIntegerItem::Integer(3),
CaseIntegerItem::Integer(6),
CaseIntegerItem::Integer(9),
CaseIntegerItem::Integer(12),
],
block: vec![
Statement::PrintLitString {
value: "Fizz".into(),
},
],
},
Statement::CaseInteger {
values: vec![CaseIntegerItem::Integer(5), CaseIntegerItem::Integer(10)],
block: vec![
Statement::PrintLitString {
value: "Buzz".into(),
},
],
},
Statement::CaseElse {
block: vec![
Statement::PrintExprInteger {
value: Expr::VarInteger("i".into()),
},
],
},
],
},
],
},
]
}
fn get_src2_statements() -> Vec<Statement> {
vec![
Statement::Dim {
var_name: "s".into(),
var_type: VarType::String,
},
Statement::Dim {
var_name: "n".into(),
var_type: VarType::Integer,
},
Statement::DoLoop {
exit_id: 0,
block: vec![
Statement::PrintLitString {
value: "Number?".into(),
},
Statement::InputString {
var_name: "s".into(),
},
Statement::If {
condition: Expr::BinaryOperatorBoolean(
Operator::Equal,
Box::new(Expr::VarString("s".into())),
Box::new(Expr::LitString("end".into())),
),
block: vec![
Statement::ExitDo { exit_id: 0 },
],
else_blocks: vec![
],
},
Statement::AssignInteger {
var_name: "n".into(),
value: Expr::FunctionInteger(
Function::CInt,
Box::new(Expr::VarString("s".into())),
),
},
Statement::If {
condition: Expr::BinaryOperatorBoolean(
Operator::LessThan,
Box::new(Expr::VarInteger("n".into())),
Box::new(Expr::LitInteger(1)),
),
block: vec![
Statement::PrintLitString {
value: "Invalid Input".into(),
},
Statement::ContinueDo { exit_id: 0 },
],
else_blocks: vec![
],
},
Statement::If {
condition: Expr::BinaryOperatorBoolean(
Operator::Equal,
Box::new(Expr::BinaryOperatorInteger(
Operator::Mod,
Box::new(Expr::VarInteger("n".into())),
Box::new(Expr::LitInteger(15)),
)),
Box::new(Expr::LitInteger(0)),
),
block: vec![
Statement::AssignString {
var_name: "s".into(),
value: Expr::LitString("FizzBuzz".into()),
},
],
else_blocks: vec![
Statement::ElseIf {
condition: Expr::BinaryOperatorBoolean(
Operator::Equal,
Box::new(Expr::BinaryOperatorInteger(
Operator::Mod,
Box::new(Expr::VarInteger("n".into())),
Box::new(Expr::LitInteger(3)),
)),
Box::new(Expr::LitInteger(0)),
),
block: vec![
Statement::AssignString {
var_name: "s".into(),
value: Expr::LitString("Fizz".into()),
},
],
},
Statement::ElseIf {
condition: Expr::BinaryOperatorBoolean(
Operator::Equal,
Box::new(Expr::BinaryOperatorInteger(
Operator::Mod,
Box::new(Expr::VarInteger("n".into())),
Box::new(Expr::LitInteger(5)),
)),
Box::new(Expr::LitInteger(0)),
),
block: vec![
Statement::AssignString {
var_name: "s".into(),
value: Expr::LitString("Buzz".into()),
},
],
},
],
},
Statement::PrintVarString {
var_name: "s".into(),
},
],
},
]
}
#[test]
fn parse_argument_1_works() -> io::Result<()> {
let src = r#"
Extern Sub FOO
Extern Sub BAR With
ByRef xArray(10) As Integer To GR1
ByVal barList(10) As Integer To GR2
ByRef barText As String To GR3,GR4
ByVal barLine As String To GR5,GR6
ByRef zCount As Integer To GR7
End Sub
Sub BAZ
Argument
ByRef someNumber As Integer From GR1
ByRef someText As String From GR2,GR3
ByVal bazText As String From GR4,GR5
ByRef bazArray(10) As Integer From GR6
ByVal yesArray(10) As Integer From GR7
End Argument
Dim int1 As Integer
Dim str1 As String
Dim arr1(10) As Integer
int1 = someNumber
someNumber = 123
str1 = someText
someText = str1
someText(0) = "A"c
someText(1) = "A"c
someText(int1) = "A"c
int1 = someText(0)
int1 = someText(1)
int1 = someText(int1)
int1 = bazArray(0)
int1 = bazArray(1)
int1 = bazArray(int1)
bazArray(0) = int1
bazArray(1) = int1
bazArray(int1) = int1
Call FOO
Call BAR (arr1, arr1, str1, str1, int1)
Call BAR With
xArray = arr1
barList = arr1
barText = str1
barLine = str1
zCount = int1
End Call
End Sub
"#;
let src = io::Cursor::new(src);
let statements = parse(src)?.unwrap();
for stmt in statements {
eprintln!("{:?}", stmt);
}
Ok(())
}