Pass value tests
This commit is contained in:
parent
ca04103372
commit
86ce1dc3af
@ -55,19 +55,27 @@ use crate::{
|
||||
error::rw_lock_error::RwLockError, Identifier, Type, TypeDefinition, Value,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ContextMode {
|
||||
AllowGarbage,
|
||||
RemoveGarbage,
|
||||
}
|
||||
|
||||
/// An execution context stores that variable and type data during the
|
||||
/// [Interpreter]'s abstraction and execution process.
|
||||
///
|
||||
/// See the [module-level docs][self] for more info.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Context {
|
||||
mode: ContextMode,
|
||||
inner: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageCounter)>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
/// Return a new, empty Context.
|
||||
pub fn new() -> Self {
|
||||
pub fn new(mode: ContextMode) -> Self {
|
||||
Self {
|
||||
mode,
|
||||
inner: Arc::new(RwLock::new(BTreeMap::new())),
|
||||
}
|
||||
}
|
||||
@ -88,6 +96,7 @@ impl Context {
|
||||
}
|
||||
|
||||
Ok(Context {
|
||||
mode: other.mode.clone(),
|
||||
inner: Arc::new(RwLock::new(new_variables)),
|
||||
})
|
||||
}
|
||||
@ -215,7 +224,7 @@ impl Context {
|
||||
|
||||
let (allowances, runtime_uses) = counter.get_counts()?;
|
||||
|
||||
if allowances == runtime_uses {
|
||||
if self.mode == ContextMode::RemoveGarbage && allowances == runtime_uses {
|
||||
self.unset(identifier)?;
|
||||
}
|
||||
|
||||
@ -326,7 +335,7 @@ impl Context {
|
||||
|
||||
impl Default for Context {
|
||||
fn default() -> Self {
|
||||
Context::new()
|
||||
Context::new(ContextMode::RemoveGarbage)
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,7 +395,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn drops_variables() {
|
||||
let context = Context::new();
|
||||
let context = Context::default();
|
||||
|
||||
interpret_with_context(
|
||||
"
|
||||
|
@ -37,14 +37,14 @@
|
||||
//! ```
|
||||
use tree_sitter::{Parser, Tree as SyntaxTree};
|
||||
|
||||
use crate::{language, AbstractTree, Context, Error, Format, Root, Value};
|
||||
use crate::{language, AbstractTree, Context, ContextMode, Error, Format, Root, Value};
|
||||
|
||||
/// Interpret the given source code. Returns the value of last statement or the
|
||||
/// first error encountered.
|
||||
///
|
||||
/// See the [module-level docs][self] for more info.
|
||||
pub fn interpret(source: &str) -> Result<Value, Error> {
|
||||
interpret_with_context(source, Context::new())
|
||||
interpret_with_context(source, Context::new(ContextMode::RemoveGarbage))
|
||||
}
|
||||
|
||||
/// Interpret the given source code with the given context.
|
||||
@ -152,6 +152,6 @@ impl Interpreter {
|
||||
|
||||
impl Default for Interpreter {
|
||||
fn default() -> Self {
|
||||
Interpreter::new(Context::new())
|
||||
Interpreter::new(Context::default())
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,7 @@
|
||||
//! You can use this library externally by calling either of the "interpret"
|
||||
//! functions or by constructing your own Interpreter.
|
||||
pub use crate::{
|
||||
abstract_tree::*,
|
||||
built_in_functions::BuiltInFunction,
|
||||
context::{Context, ValueData},
|
||||
error::Error,
|
||||
interpret::*,
|
||||
abstract_tree::*, built_in_functions::BuiltInFunction, context::*, error::Error, interpret::*,
|
||||
value::*,
|
||||
};
|
||||
|
||||
|
27
src/main.rs
27
src/main.rs
@ -11,7 +11,8 @@ use reedline::{
|
||||
use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command};
|
||||
|
||||
use dust_lang::{
|
||||
built_in_values::all_built_in_values, Context, Error, Identifier, Interpreter, Value, ValueData,
|
||||
built_in_values::all_built_in_values, Context, ContextMode, Error, Interpreter, Value,
|
||||
ValueData,
|
||||
};
|
||||
|
||||
/// Command-line arguments to be parsed.
|
||||
@ -22,14 +23,6 @@ struct Args {
|
||||
#[arg(short, long)]
|
||||
command: Option<String>,
|
||||
|
||||
/// Data to assign to the "input" variable.
|
||||
#[arg(short, long)]
|
||||
input: Option<String>,
|
||||
|
||||
/// File whose contents will be assigned to the "input" variable.
|
||||
#[arg(short = 'p', long)]
|
||||
input_path: Option<String>,
|
||||
|
||||
/// Command for alternate functionality besides running the source.
|
||||
#[command(subcommand)]
|
||||
cli_command: Option<CliCommand>,
|
||||
@ -51,21 +44,7 @@ fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let args = Args::parse();
|
||||
let context = Context::new();
|
||||
|
||||
if let Some(input) = args.input {
|
||||
context
|
||||
.set_value(Identifier::new("input"), Value::string(input))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if let Some(path) = args.input_path {
|
||||
let file_contents = read_to_string(path).unwrap();
|
||||
|
||||
context
|
||||
.set_value(Identifier::new("input"), Value::string(file_contents))
|
||||
.unwrap();
|
||||
}
|
||||
let context = Context::new(ContextMode::AllowGarbage);
|
||||
|
||||
if args.path.is_none() && args.command.is_none() {
|
||||
let run_shell_result = run_shell(context);
|
||||
|
@ -86,21 +86,19 @@ impl Eq for List {}
|
||||
|
||||
impl PartialEq for List {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if let Ok(left) = self.items() {
|
||||
if let Ok(right) = other.items() {
|
||||
if left.len() != right.len() {
|
||||
return false;
|
||||
} else {
|
||||
for (i, j) in left.iter().zip(right.iter()) {
|
||||
if i != j {
|
||||
return false;
|
||||
}
|
||||
if let (Ok(left), Ok(right)) = (self.items(), other.items()) {
|
||||
if left.len() != right.len() {
|
||||
return false;
|
||||
} else {
|
||||
for (i, j) in left.iter().zip(right.iter()) {
|
||||
if i != j {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,12 +110,10 @@ impl PartialOrd for List {
|
||||
|
||||
impl Ord for List {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
if let Ok(left) = self.items() {
|
||||
if let Ok(right) = other.items() {
|
||||
return left.cmp(&right);
|
||||
}
|
||||
if let (Ok(left), Ok(right)) = (self.items(), other.items()) {
|
||||
left.cmp(&right)
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
|
||||
Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
use crate::{
|
||||
built_in_values::BuiltInValue,
|
||||
error::{rw_lock_error::RwLockError, RuntimeError, ValidationError},
|
||||
Identifier, SourcePosition, Type, TypeSpecification,
|
||||
Identifier, SourcePosition, Type,
|
||||
};
|
||||
|
||||
use serde::{
|
||||
@ -93,18 +93,7 @@ impl Value {
|
||||
Type::List(Box::new(Type::Any))
|
||||
}
|
||||
}
|
||||
Value::Map(map) => {
|
||||
let mut identifier_types = Vec::new();
|
||||
|
||||
for (key, value) in map.inner() {
|
||||
identifier_types.push((
|
||||
Identifier::new(key.inner()),
|
||||
TypeSpecification::new(value.r#type()?),
|
||||
));
|
||||
}
|
||||
|
||||
Type::Map
|
||||
}
|
||||
Value::Map(_) => Type::Map,
|
||||
Value::Function(function) => function.r#type().clone(),
|
||||
Value::String(_) => Type::String,
|
||||
Value::Float(_) => Type::Float,
|
||||
@ -263,7 +252,9 @@ impl Value {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left + right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left + right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float((left as f64) + right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left + right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => {
|
||||
Ok(Value::Integer(left.saturating_add(right)))
|
||||
}
|
||||
(Value::List(list), value) | (value, Value::List(list)) => {
|
||||
list.items_mut()?.push(value);
|
||||
|
||||
@ -284,7 +275,9 @@ impl Value {
|
||||
(Value::Float(left), Value::Float(right)) => Ok(Value::Float(left - right)),
|
||||
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left - right as f64)),
|
||||
(Value::Integer(left), Value::Float(right)) => Ok(Value::Float(left as f64 - right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => Ok(Value::Integer(left - right)),
|
||||
(Value::Integer(left), Value::Integer(right)) => {
|
||||
Ok(Value::Integer(left.saturating_sub(right)))
|
||||
}
|
||||
(left, right) => Err(ValidationError::CannotSubtract {
|
||||
left,
|
||||
right,
|
||||
|
@ -2,7 +2,7 @@ use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn format_simple_program() {
|
||||
let mut interpreter = Interpreter::new(Context::new());
|
||||
let mut interpreter = Interpreter::new(Context::default());
|
||||
|
||||
assert_eq!(interpreter.format("x=1"), Ok("x = 1\n".to_string()));
|
||||
}
|
||||
@ -16,7 +16,7 @@ const FORMATTED_BLOCK: &str = "{
|
||||
|
||||
#[test]
|
||||
fn format_block() {
|
||||
let mut interpreter = Interpreter::new(Context::new());
|
||||
let mut interpreter = Interpreter::new(Context::default());
|
||||
|
||||
assert_eq!(
|
||||
interpreter.format("{1 2 3}"),
|
||||
@ -34,7 +34,7 @@ const FORMATTED_MAP: &str = "{
|
||||
|
||||
#[test]
|
||||
fn format_map() {
|
||||
let mut interpreter = Interpreter::new(Context::new());
|
||||
let mut interpreter = Interpreter::new(Context::default());
|
||||
|
||||
assert_eq!(
|
||||
interpreter.format("{{x=1 y <int> = 2}}"),
|
||||
@ -49,7 +49,7 @@ const FORMATTED_FUNCTION: &str = "(x <int>) <num> {
|
||||
|
||||
#[test]
|
||||
fn format_function() {
|
||||
let mut interpreter = Interpreter::new(Context::new());
|
||||
let mut interpreter = Interpreter::new(Context::default());
|
||||
assert_eq!(
|
||||
interpreter.format("( x< int > )<num>{x/2}"),
|
||||
Ok(FORMATTED_FUNCTION.to_string())
|
||||
|
@ -1,7 +1,7 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
fn none() {
|
||||
assert_eq!(interpret("x = 9"), Ok(Value::none()));
|
||||
assert_eq!(interpret("x = 1 + 1"), Ok(Value::none()));
|
||||
}
|
||||
@ -14,14 +14,14 @@ fn integer() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn integer_overflow() {
|
||||
fn integer_saturation() {
|
||||
assert_eq!(
|
||||
interpret("9223372036854775807 + 1"),
|
||||
Ok(Value::Integer(i64::MIN))
|
||||
Ok(Value::Integer(i64::MAX))
|
||||
);
|
||||
assert_eq!(
|
||||
interpret("-9223372036854775808 - 1"),
|
||||
Ok(Value::Integer(i64::MAX))
|
||||
Ok(Value::Integer(i64::MIN))
|
||||
);
|
||||
}
|
||||
|
||||
@ -37,6 +37,18 @@ fn float() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_saturation() {
|
||||
assert_eq!(
|
||||
interpret("1.7976931348623157e308 + 1"),
|
||||
Ok(Value::Float(f64::MAX))
|
||||
);
|
||||
assert_eq!(
|
||||
interpret("-1.7976931348623157e308 - 1"),
|
||||
Ok(Value::Float(f64::MIN))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string() {
|
||||
assert_eq!(interpret("\"one\""), Ok(Value::string("one".to_string())));
|
||||
|
Loading…
Reference in New Issue
Block a user