2018-07-06 18:53:20 -05:00
|
|
|
// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2018-08-13 23:11:35 -05:00
|
|
|
use super::assets::MemoryCache;
|
2018-05-22 18:02:44 -05:00
|
|
|
use super::{Builder, CallDef, MacroDef, SelectDef, Val};
|
|
|
|
use ast::*;
|
2018-05-28 13:18:50 -05:00
|
|
|
|
|
|
|
use std;
|
2018-08-13 23:11:35 -05:00
|
|
|
use std::cell::RefCell;
|
2018-05-22 18:02:44 -05:00
|
|
|
use std::rc::Rc;
|
|
|
|
|
2018-11-16 09:53:19 -06:00
|
|
|
fn test_expr_to_val(mut cases: Vec<(Expression, Val)>, mut b: Builder) {
|
2018-05-22 18:02:44 -05:00
|
|
|
for tpl in cases.drain(0..) {
|
|
|
|
assert_eq!(b.eval_expr(&tpl.0).unwrap(), Rc::new(tpl.1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Expected Float")]
|
|
|
|
fn test_eval_div_expr_fail() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-05-22 18:02:44 -05:00
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Binary(BinaryOpDef {
|
|
|
|
kind: BinaryExprType::Div,
|
2018-11-05 21:34:12 -06:00
|
|
|
left: Box::new(Expression::Simple(Value::Float(value_node!(
|
|
|
|
2.0,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
|
|
|
2,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Float(1.0),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Expected Float")]
|
|
|
|
fn test_eval_mul_expr_fail() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-05-22 18:02:44 -05:00
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Binary(BinaryOpDef {
|
|
|
|
kind: BinaryExprType::Mul,
|
2018-11-05 21:34:12 -06:00
|
|
|
left: Box::new(Expression::Simple(Value::Float(value_node!(
|
|
|
|
2.0,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
|
|
|
20,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Float(1.0),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Expected Float")]
|
|
|
|
fn test_eval_subtract_expr_fail() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-05-22 18:02:44 -05:00
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Binary(BinaryOpDef {
|
|
|
|
kind: BinaryExprType::Sub,
|
2018-11-05 21:34:12 -06:00
|
|
|
left: Box::new(Expression::Simple(Value::Float(value_node!(
|
|
|
|
2.0,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
|
|
|
2,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Float(1.0),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Expected Float")]
|
|
|
|
fn test_eval_add_expr_fail() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-05-22 18:02:44 -05:00
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Binary(BinaryOpDef {
|
|
|
|
kind: BinaryExprType::Add,
|
2018-11-05 21:34:12 -06:00
|
|
|
left: Box::new(Expression::Simple(Value::Float(value_node!(
|
|
|
|
2.0,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
right: Box::new(Expression::Simple(Value::Int(value_node!(
|
|
|
|
2,
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Float(1.0),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_eval_simple_lookup_error() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-08-13 20:37:58 -05:00
|
|
|
b.build_output
|
2018-11-05 21:34:12 -06:00
|
|
|
.entry(value_node!("var1".to_string(), Position::new(1, 0, 0)))
|
2018-05-22 18:02:44 -05:00
|
|
|
.or_insert(Rc::new(Val::Int(1)));
|
2018-11-05 21:34:12 -06:00
|
|
|
let expr = Expression::Simple(Value::Symbol(value_node!(
|
|
|
|
"var".to_string(),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)));
|
2018-05-22 18:02:44 -05:00
|
|
|
assert!(b.eval_expr(&expr).is_err());
|
|
|
|
}
|
|
|
|
|
2018-06-10 13:51:19 -05:00
|
|
|
// Include nested for each.
|
2018-05-22 18:02:44 -05:00
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Unable to find tpl1")]
|
|
|
|
fn test_expr_copy_no_such_tuple() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-05-22 18:02:44 -05:00
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Copy(CopyDef {
|
2018-11-05 21:34:12 -06:00
|
|
|
selector: make_selector!(
|
|
|
|
make_expr!("tpl1", Position::new(1, 1, 1)),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
),
|
2018-05-29 20:48:57 -05:00
|
|
|
fields: Vec::new(),
|
2018-11-05 21:34:12 -06:00
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Tuple(Vec::new()),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2018-11-23 12:50:47 -06:00
|
|
|
#[should_panic(expected = "Expected Tuple or Module got Int(1)")]
|
2018-05-22 18:02:44 -05:00
|
|
|
fn test_expr_copy_not_a_tuple() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-08-13 20:37:58 -05:00
|
|
|
b.build_output
|
2018-11-05 21:34:12 -06:00
|
|
|
.entry(value_node!("tpl1".to_string(), Position::new(1, 0, 0)))
|
2018-05-22 18:02:44 -05:00
|
|
|
.or_insert(Rc::new(Val::Int(1)));
|
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Copy(CopyDef {
|
2018-11-05 21:34:12 -06:00
|
|
|
selector: make_selector!(
|
|
|
|
make_expr!("tpl1", Position::new(1, 1, 1)),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
),
|
2018-05-29 20:48:57 -05:00
|
|
|
fields: Vec::new(),
|
2018-11-05 21:34:12 -06:00
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Tuple(Vec::new()),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Expected type Integer for field fld1 but got String")]
|
|
|
|
fn test_expr_copy_field_type_error() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-08-13 20:37:58 -05:00
|
|
|
b.build_output
|
2018-11-05 21:34:12 -06:00
|
|
|
.entry(value_node!("tpl1".to_string(), Position::new(1, 0, 0)))
|
2018-05-29 20:48:57 -05:00
|
|
|
.or_insert(Rc::new(Val::Tuple(vec![(
|
2018-11-05 21:34:12 -06:00
|
|
|
value_node!("fld1".to_string(), Position::new(1, 0, 0)),
|
2018-05-29 20:48:57 -05:00
|
|
|
Rc::new(Val::Int(1)),
|
|
|
|
)])));
|
2018-05-22 18:02:44 -05:00
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Copy(CopyDef {
|
2018-11-05 21:34:12 -06:00
|
|
|
selector: make_selector!(
|
|
|
|
make_expr!("tpl1", Position::new(1, 1, 1)),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
),
|
2018-05-29 20:48:57 -05:00
|
|
|
fields: vec![(
|
2018-11-05 21:34:12 -06:00
|
|
|
make_tok!("fld1", Position::new(1, 1, 1)),
|
|
|
|
Expression::Simple(Value::Str(value_node!(
|
|
|
|
"2".to_string(),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
))),
|
2018-05-29 20:48:57 -05:00
|
|
|
)],
|
2018-11-05 21:34:12 -06:00
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Tuple(vec![(
|
2018-11-05 21:34:12 -06:00
|
|
|
value_node!("fld1".to_string(), Position::new(1, 1, 1)),
|
2018-06-10 14:13:08 -05:00
|
|
|
Rc::new(Val::Str("2".to_string())),
|
2018-05-29 20:48:57 -05:00
|
|
|
)]),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Unable to find arg1")]
|
|
|
|
fn test_macro_hermetic() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-08-13 20:37:58 -05:00
|
|
|
b.build_output
|
2018-11-05 21:34:12 -06:00
|
|
|
.entry(value_node!("arg1".to_string(), Position::new(1, 0, 0)))
|
2018-06-10 14:13:08 -05:00
|
|
|
.or_insert(Rc::new(Val::Str("bar".to_string())));
|
2018-08-13 20:37:58 -05:00
|
|
|
b.build_output
|
2018-11-05 21:34:12 -06:00
|
|
|
.entry(value_node!("tstmac".to_string(), Position::new(1, 0, 0)))
|
2018-05-22 18:02:44 -05:00
|
|
|
.or_insert(Rc::new(Val::Macro(MacroDef {
|
2018-11-05 21:34:12 -06:00
|
|
|
argdefs: vec![value_node!("arg2".to_string(), Position::new(1, 0, 0))],
|
2018-05-29 20:48:57 -05:00
|
|
|
fields: vec![(
|
2018-11-05 21:34:12 -06:00
|
|
|
make_tok!("foo", Position::new(1, 1, 1)),
|
|
|
|
Expression::Simple(Value::Symbol(value_node!(
|
|
|
|
"arg1".to_string(),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
))),
|
2018-05-29 20:48:57 -05:00
|
|
|
)],
|
2018-11-05 21:34:12 -06:00
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-22 18:02:44 -05:00
|
|
|
})));
|
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Call(CallDef {
|
2018-11-05 21:34:12 -06:00
|
|
|
macroref: make_selector!(
|
|
|
|
make_expr!("tstmac", Position::new(1, 1, 1)),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
),
|
2018-06-10 14:13:08 -05:00
|
|
|
arglist: vec![Expression::Simple(Value::Str(value_node!(
|
2018-05-29 20:48:57 -05:00
|
|
|
"bar".to_string(),
|
2018-11-05 21:34:12 -06:00
|
|
|
Position::new(1, 1, 1)
|
2018-05-29 20:48:57 -05:00
|
|
|
)))],
|
2018-11-05 21:34:12 -06:00
|
|
|
pos: Position::new(1, 1, 1),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Tuple(vec![(
|
2018-11-05 21:34:12 -06:00
|
|
|
value_node!("foo".to_string(), Position::new(1, 1, 1)),
|
2018-06-10 14:13:08 -05:00
|
|
|
Rc::new(Val::Str("bar".to_string())),
|
2018-05-29 20:48:57 -05:00
|
|
|
)]),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected = "Expected String but got Integer in Select expression")]
|
|
|
|
fn test_select_expr_not_a_string() {
|
2018-08-13 23:11:35 -05:00
|
|
|
let cache = Rc::new(RefCell::new(MemoryCache::new()));
|
|
|
|
let mut b = Builder::new(std::env::current_dir().unwrap(), cache);
|
2018-08-13 20:37:58 -05:00
|
|
|
b.build_output
|
2018-11-05 21:34:12 -06:00
|
|
|
.entry(value_node!("foo".to_string(), Position::new(1, 0, 0)))
|
2018-05-22 18:02:44 -05:00
|
|
|
.or_insert(Rc::new(Val::Int(4)));
|
|
|
|
test_expr_to_val(
|
2018-05-29 20:48:57 -05:00
|
|
|
vec![(
|
|
|
|
Expression::Select(SelectDef {
|
|
|
|
val: Box::new(Expression::Simple(Value::Symbol(value_node!(
|
|
|
|
"foo".to_string(),
|
2018-11-05 21:34:12 -06:00
|
|
|
Position::new(1, 1, 1)
|
|
|
|
)))),
|
|
|
|
default: Box::new(Expression::Simple(Value::Int(value_node!(
|
2018-05-29 20:48:57 -05:00
|
|
|
1,
|
2018-11-05 21:34:12 -06:00
|
|
|
Position::new(1, 1, 1)
|
2018-05-29 20:48:57 -05:00
|
|
|
)))),
|
|
|
|
tuple: vec![
|
|
|
|
(
|
2018-11-05 21:34:12 -06:00
|
|
|
make_tok!("bar", Position::new(1, 1, 1)),
|
|
|
|
Expression::Simple(Value::Int(value_node!(2, Position::new(1, 1, 1)))),
|
2018-05-29 20:48:57 -05:00
|
|
|
),
|
|
|
|
(
|
2018-11-05 21:34:12 -06:00
|
|
|
make_tok!("quux", Position::new(1, 1, 1)),
|
|
|
|
Expression::Simple(Value::Str(value_node!(
|
|
|
|
"2".to_string(),
|
|
|
|
Position::new(1, 1, 1)
|
|
|
|
))),
|
2018-05-29 20:48:57 -05:00
|
|
|
),
|
|
|
|
],
|
2018-11-05 21:34:12 -06:00
|
|
|
pos: Position::new(1, 0, 0),
|
2018-05-29 20:48:57 -05:00
|
|
|
}),
|
|
|
|
Val::Int(2),
|
|
|
|
)],
|
2018-05-22 18:02:44 -05:00
|
|
|
b,
|
|
|
|
);
|
|
|
|
}
|