mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-05-25 18:21:36 +08:00
add (define) and some tests for it
This commit is contained in:
54
blockstack-vm/src/functions/define.rs
Normal file
54
blockstack-vm/src/functions/define.rs
Normal file
@@ -0,0 +1,54 @@
|
||||
use super::super::types::{ValueType, DefinedFunction};
|
||||
use super::super::representations::SymbolicExpression;
|
||||
use super::super::representations::SymbolicExpression::{Atom,List};
|
||||
use super::super::{Context,CallStack,eval};
|
||||
|
||||
pub enum DefineResult {
|
||||
Variable(String, ValueType),
|
||||
Function(String, DefinedFunction)
|
||||
}
|
||||
|
||||
pub fn handle_define_variable(variable: &String, expression: &SymbolicExpression, context: &Context) -> DefineResult {
|
||||
let mut call_stack = CallStack::new();
|
||||
let value = eval(expression, context, &mut call_stack, context);
|
||||
DefineResult::Variable(variable.clone(), value)
|
||||
}
|
||||
|
||||
pub fn handle_define_function(signature: &[SymbolicExpression], expression: &SymbolicExpression, _context: &Context) -> DefineResult {
|
||||
let coerced_atoms: Result<Vec<_>, _> = signature.iter().map(|x| {
|
||||
if let Atom(name) = x {
|
||||
Ok(name)
|
||||
} else {
|
||||
Err("Non-atomic argument to method signature in define".to_string())
|
||||
}
|
||||
}).collect();
|
||||
|
||||
if let Ok(names) = coerced_atoms {
|
||||
if let Some((function_name, arg_names)) = names.split_first() {
|
||||
let function = DefinedFunction {
|
||||
arguments: arg_names.iter().map(|x| (*x).clone()).collect(),
|
||||
body: expression.clone()
|
||||
};
|
||||
DefineResult::Function((*function_name).clone(), function)
|
||||
} else {
|
||||
panic!("Must supply atleast a name argument to define a function")
|
||||
}
|
||||
} else {
|
||||
panic!("Non-atomic argument to method signature in define")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn evaluate_define(expression: &SymbolicExpression, context: &Context) -> Option<DefineResult> {
|
||||
if let SymbolicExpression::List(elements) = expression {
|
||||
if elements.len() != 3 || elements[0] != Atom("define".to_string()) {
|
||||
None
|
||||
} else {
|
||||
match elements[1] {
|
||||
Atom(ref variable) => Some(handle_define_variable(variable, &elements[2], context)),
|
||||
List(ref function_signature) => Some(handle_define_function(&function_signature, &elements[2], context))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
65
blockstack-vm/tests/defines.rs
Normal file
65
blockstack-vm/tests/defines.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
extern crate blockstack_vm;
|
||||
|
||||
use blockstack_vm::types::ValueType;
|
||||
|
||||
use blockstack_vm::parser::parse;
|
||||
use blockstack_vm::eval_all;
|
||||
|
||||
#[test]
|
||||
fn test_defines() {
|
||||
let tests = parse(&
|
||||
"(define x 10)
|
||||
(define y 15)
|
||||
(define (f a b) (+ x y a b))
|
||||
(f 3 1)");
|
||||
|
||||
if let Ok(to_eval) = tests {
|
||||
assert_eq!(Ok(ValueType::IntType(29)), eval_all(&to_eval));
|
||||
} else {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_recursive_panic() {
|
||||
let tests = parse(&
|
||||
"(define (factorial a)
|
||||
(if (eq? a 0)
|
||||
1
|
||||
(* a (factorial (- a 1)))))
|
||||
(factorial 10)");
|
||||
|
||||
if let Ok(to_eval) = tests {
|
||||
assert_eq!(Ok(ValueType::IntType(29)), eval_all(&to_eval));
|
||||
} else {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_define_parse_panic() {
|
||||
let tests = parse(&
|
||||
"(define () 1)");
|
||||
|
||||
if let Ok(to_eval) = tests {
|
||||
assert_eq!(Ok(ValueType::IntType(29)), eval_all(&to_eval));
|
||||
} else {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_define_parse_panic_2() {
|
||||
let tests = parse(&
|
||||
"(define (a b (d)) 1)");
|
||||
|
||||
if let Ok(to_eval) = tests {
|
||||
assert_eq!(Ok(ValueType::IntType(29)), eval_all(&to_eval));
|
||||
} else {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
extern crate blockstack_vm;
|
||||
|
||||
use blockstack_vm::{eval, eval_all};
|
||||
use blockstack_vm::eval;
|
||||
use blockstack_vm::{Context, CallStack};
|
||||
use blockstack_vm::types::{ValueType, DefinedFunction};
|
||||
use blockstack_vm::representations::SymbolicExpression;
|
||||
@@ -138,36 +138,3 @@ fn test_simple_arithmetic_functions() {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_defines() {
|
||||
let tests = parse(&
|
||||
"(define x 10)
|
||||
(define y 15)
|
||||
(define (f a b) (+ x y a b))
|
||||
(f 3 1)");
|
||||
|
||||
if let Ok(to_eval) = tests {
|
||||
assert_eq!(Ok(ValueType::IntType(29)), eval_all(&to_eval));
|
||||
} else {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_recursive_panic() {
|
||||
let tests = parse(&
|
||||
"(define (factorial a)
|
||||
(if (eq? a 0)
|
||||
1
|
||||
(* a (factorial (- a 1)))))
|
||||
(factorial 10)");
|
||||
|
||||
if let Ok(to_eval) = tests {
|
||||
assert_eq!(Ok(ValueType::IntType(29)), eval_all(&to_eval));
|
||||
} else {
|
||||
assert!(false, "Failed to parse function bodies.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user