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,
};
#[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(
"

View File

@ -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())
}
}

View File

@ -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::*,
};

View File

@ -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);

View File

@ -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
}
}

View File

@ -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,

View File

@ -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())

View File

@ -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())));