1
0

Pass value tests

This commit is contained in:
Jeff 2024-02-18 01:50:15 -05:00
parent ca04103372
commit 86ce1dc3af
8 changed files with 60 additions and 75 deletions

View File

@ -55,19 +55,27 @@ use crate::{
error::rw_lock_error::RwLockError, Identifier, Type, TypeDefinition, Value, 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 /// An execution context stores that variable and type data during the
/// [Interpreter]'s abstraction and execution process. /// [Interpreter]'s abstraction and execution process.
/// ///
/// See the [module-level docs][self] for more info. /// See the [module-level docs][self] for more info.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Context { pub struct Context {
mode: ContextMode,
inner: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageCounter)>>>, inner: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageCounter)>>>,
} }
impl Context { impl Context {
/// Return a new, empty Context. /// Return a new, empty Context.
pub fn new() -> Self { pub fn new(mode: ContextMode) -> Self {
Self { Self {
mode,
inner: Arc::new(RwLock::new(BTreeMap::new())), inner: Arc::new(RwLock::new(BTreeMap::new())),
} }
} }
@ -88,6 +96,7 @@ impl Context {
} }
Ok(Context { Ok(Context {
mode: other.mode.clone(),
inner: Arc::new(RwLock::new(new_variables)), inner: Arc::new(RwLock::new(new_variables)),
}) })
} }
@ -215,7 +224,7 @@ impl Context {
let (allowances, runtime_uses) = counter.get_counts()?; let (allowances, runtime_uses) = counter.get_counts()?;
if allowances == runtime_uses { if self.mode == ContextMode::RemoveGarbage && allowances == runtime_uses {
self.unset(identifier)?; self.unset(identifier)?;
} }
@ -326,7 +335,7 @@ impl Context {
impl Default for Context { impl Default for Context {
fn default() -> Self { fn default() -> Self {
Context::new() Context::new(ContextMode::RemoveGarbage)
} }
} }
@ -386,7 +395,7 @@ mod tests {
#[test] #[test]
fn drops_variables() { fn drops_variables() {
let context = Context::new(); let context = Context::default();
interpret_with_context( interpret_with_context(
" "

View File

@ -37,14 +37,14 @@
//! ``` //! ```
use tree_sitter::{Parser, Tree as SyntaxTree}; 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 /// Interpret the given source code. Returns the value of last statement or the
/// first error encountered. /// first error encountered.
/// ///
/// See the [module-level docs][self] for more info. /// See the [module-level docs][self] for more info.
pub fn interpret(source: &str) -> Result<Value, Error> { 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. /// Interpret the given source code with the given context.
@ -152,6 +152,6 @@ impl Interpreter {
impl Default for Interpreter { impl Default for Interpreter {
fn default() -> Self { fn default() -> Self {
Interpreter::new(Context::new()) Interpreter::new(Context::default())
} }
} }

View File

@ -5,11 +5,7 @@
//! You can use this library externally by calling either of the "interpret" //! You can use this library externally by calling either of the "interpret"
//! functions or by constructing your own Interpreter. //! functions or by constructing your own Interpreter.
pub use crate::{ pub use crate::{
abstract_tree::*, abstract_tree::*, built_in_functions::BuiltInFunction, context::*, error::Error, interpret::*,
built_in_functions::BuiltInFunction,
context::{Context, ValueData},
error::Error,
interpret::*,
value::*, value::*,
}; };

View File

@ -11,7 +11,8 @@ use reedline::{
use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command}; use std::{borrow::Cow, fs::read_to_string, path::PathBuf, process::Command};
use dust_lang::{ 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. /// Command-line arguments to be parsed.
@ -22,14 +23,6 @@ struct Args {
#[arg(short, long)] #[arg(short, long)]
command: Option<String>, 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 for alternate functionality besides running the source.
#[command(subcommand)] #[command(subcommand)]
cli_command: Option<CliCommand>, cli_command: Option<CliCommand>,
@ -51,21 +44,7 @@ fn main() {
env_logger::init(); env_logger::init();
let args = Args::parse(); let args = Args::parse();
let context = Context::new(); let context = Context::new(ContextMode::AllowGarbage);
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();
}
if args.path.is_none() && args.command.is_none() { if args.path.is_none() && args.command.is_none() {
let run_shell_result = run_shell(context); let run_shell_result = run_shell(context);

View File

@ -86,8 +86,7 @@ impl Eq for List {}
impl PartialEq for List { impl PartialEq for List {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if let Ok(left) = self.items() { if let (Ok(left), Ok(right)) = (self.items(), other.items()) {
if let Ok(right) = other.items() {
if left.len() != right.len() { if left.len() != right.len() {
return false; return false;
} else { } else {
@ -98,9 +97,8 @@ impl PartialEq for List {
} }
} }
} }
}
false true
} }
} }
@ -112,12 +110,10 @@ impl PartialOrd for List {
impl Ord for List { impl Ord for List {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
if let Ok(left) = self.items() { if let (Ok(left), Ok(right)) = (self.items(), other.items()) {
if let Ok(right) = other.items() { left.cmp(&right)
return left.cmp(&right); } else {
}
}
Ordering::Equal Ordering::Equal
} }
} }
}

View File

@ -2,7 +2,7 @@
use crate::{ use crate::{
built_in_values::BuiltInValue, built_in_values::BuiltInValue,
error::{rw_lock_error::RwLockError, RuntimeError, ValidationError}, error::{rw_lock_error::RwLockError, RuntimeError, ValidationError},
Identifier, SourcePosition, Type, TypeSpecification, Identifier, SourcePosition, Type,
}; };
use serde::{ use serde::{
@ -93,18 +93,7 @@ impl Value {
Type::List(Box::new(Type::Any)) Type::List(Box::new(Type::Any))
} }
} }
Value::Map(map) => { Value::Map(_) => Type::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::Function(function) => function.r#type().clone(), Value::Function(function) => function.r#type().clone(),
Value::String(_) => Type::String, Value::String(_) => Type::String,
Value::Float(_) => Type::Float, 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::Float(right)) => Ok(Value::Float(left + right)),
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left + right as f64)), (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::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)) => { (Value::List(list), value) | (value, Value::List(list)) => {
list.items_mut()?.push(value); 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::Float(right)) => Ok(Value::Float(left - right)),
(Value::Float(left), Value::Integer(right)) => Ok(Value::Float(left - right as f64)), (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::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) => Err(ValidationError::CannotSubtract {
left, left,
right, right,

View File

@ -2,7 +2,7 @@ use dust_lang::*;
#[test] #[test]
fn format_simple_program() { 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())); assert_eq!(interpreter.format("x=1"), Ok("x = 1\n".to_string()));
} }
@ -16,7 +16,7 @@ const FORMATTED_BLOCK: &str = "{
#[test] #[test]
fn format_block() { fn format_block() {
let mut interpreter = Interpreter::new(Context::new()); let mut interpreter = Interpreter::new(Context::default());
assert_eq!( assert_eq!(
interpreter.format("{1 2 3}"), interpreter.format("{1 2 3}"),
@ -34,7 +34,7 @@ const FORMATTED_MAP: &str = "{
#[test] #[test]
fn format_map() { fn format_map() {
let mut interpreter = Interpreter::new(Context::new()); let mut interpreter = Interpreter::new(Context::default());
assert_eq!( assert_eq!(
interpreter.format("{{x=1 y <int> = 2}}"), interpreter.format("{{x=1 y <int> = 2}}"),
@ -49,7 +49,7 @@ const FORMATTED_FUNCTION: &str = "(x <int>) <num> {
#[test] #[test]
fn format_function() { fn format_function() {
let mut interpreter = Interpreter::new(Context::new()); let mut interpreter = Interpreter::new(Context::default());
assert_eq!( assert_eq!(
interpreter.format("( x< int > )<num>{x/2}"), interpreter.format("( x< int > )<num>{x/2}"),
Ok(FORMATTED_FUNCTION.to_string()) Ok(FORMATTED_FUNCTION.to_string())

View File

@ -1,7 +1,7 @@
use dust_lang::*; use dust_lang::*;
#[test] #[test]
fn empty() { fn none() {
assert_eq!(interpret("x = 9"), Ok(Value::none())); assert_eq!(interpret("x = 9"), Ok(Value::none()));
assert_eq!(interpret("x = 1 + 1"), Ok(Value::none())); assert_eq!(interpret("x = 1 + 1"), Ok(Value::none()));
} }
@ -14,14 +14,14 @@ fn integer() {
} }
#[test] #[test]
fn integer_overflow() { fn integer_saturation() {
assert_eq!( assert_eq!(
interpret("9223372036854775807 + 1"), interpret("9223372036854775807 + 1"),
Ok(Value::Integer(i64::MIN)) Ok(Value::Integer(i64::MAX))
); );
assert_eq!( assert_eq!(
interpret("-9223372036854775808 - 1"), 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] #[test]
fn string() { fn string() {
assert_eq!(interpret("\"one\""), Ok(Value::string("one".to_string()))); assert_eq!(interpret("\"one\""), Ok(Value::string("one".to_string())));