Add support for multiple integer types.

This commit is contained in:
2023-06-04 17:31:26 -07:00
parent 7efd2fb796
commit 469fe35e46
19 changed files with 528 additions and 169 deletions

View File

@@ -1,12 +1,11 @@
use std::collections::HashSet;
use crate::syntax::ast::{Expression, Program, Statement, Value};
use crate::syntax::ast::{ConstantType, Expression, Program, Statement, Value};
use crate::syntax::location::Location;
use proptest::sample::select;
use proptest::{
prelude::{Arbitrary, BoxedStrategy, Strategy},
strategy::{Just, Union},
};
use std::collections::HashMap;
const VALID_VARIABLE_NAMES: &str = r"[a-z][a-zA-Z0-9_]*";
@@ -27,36 +26,38 @@ impl Arbitrary for Program {
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
let optionals = Vec::<Option<Name>>::arbitrary();
let optionals = Vec::<Option<(Name, ConstantType)>>::arbitrary();
optionals
.prop_flat_map(|mut possible_names| {
let mut statements = Vec::new();
let mut defined_variables: HashSet<String> = HashSet::new();
let mut defined_variables: HashMap<String, ConstantType> = HashMap::new();
for possible_name in possible_names.drain(..) {
match possible_name {
None if defined_variables.is_empty() => continue,
None => statements.push(
Union::new(defined_variables.iter().map(|name| {
Union::new(defined_variables.keys().map(|name| {
Just(Statement::Print(Location::manufactured(), name.to_string()))
}))
.boxed(),
),
Some(new_name) => {
Some((new_name, new_type)) => {
let closures_name = new_name.0.clone();
let retval =
Expression::arbitrary_with(Some(defined_variables.clone()))
.prop_map(move |exp| {
Statement::Binding(
Location::manufactured(),
closures_name.clone(),
exp,
)
})
.boxed();
let retval = Expression::arbitrary_with((
Some(defined_variables.clone()),
Some(new_type),
))
.prop_map(move |exp| {
Statement::Binding(
Location::manufactured(),
closures_name.clone(),
exp,
)
})
.boxed();
defined_variables.insert(new_name.0);
defined_variables.insert(new_name.0, new_type);
statements.push(retval);
}
}
@@ -70,7 +71,7 @@ impl Arbitrary for Program {
}
impl Arbitrary for Statement {
type Parameters = Option<HashSet<String>>;
type Parameters = Option<HashMap<String, ConstantType>>;
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
@@ -79,7 +80,7 @@ impl Arbitrary for Statement {
let binding_strategy = (
VALID_VARIABLE_NAMES,
Expression::arbitrary_with(duplicated_args),
Expression::arbitrary_with((duplicated_args, None)),
)
.prop_map(|(name, exp)| Statement::Binding(Location::manufactured(), name, exp))
.boxed();
@@ -89,7 +90,7 @@ impl Arbitrary for Statement {
} else {
let print_strategy = Union::new(
defined_variables
.iter()
.keys()
.map(|x| Just(Statement::Print(Location::manufactured(), x.to_string()))),
)
.boxed();
@@ -100,20 +101,25 @@ impl Arbitrary for Statement {
}
impl Arbitrary for Expression {
type Parameters = Option<HashSet<String>>;
type Parameters = (Option<HashMap<String, ConstantType>>, Option<ConstantType>);
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
let defined_variables = args.unwrap_or_default();
fn arbitrary_with((env, target_type): Self::Parameters) -> Self::Strategy {
let defined_variables = env.unwrap_or_default();
let mut acceptable_variables = defined_variables
.iter()
.filter(|(_, ctype)| Some(**ctype) == target_type)
.map(|(x, _)| x)
.peekable();
let value_strategy = Value::arbitrary()
let value_strategy = Value::arbitrary_with(target_type)
.prop_map(move |x| Expression::Value(Location::manufactured(), x))
.boxed();
let leaf_strategy = if defined_variables.is_empty() {
let leaf_strategy = if acceptable_variables.peek().is_none() {
value_strategy
} else {
let reference_strategy = Union::new(defined_variables.iter().map(|x| {
let reference_strategy = Union::new(acceptable_variables.map(|x| {
Just(Expression::Reference(
Location::manufactured(),
x.to_owned(),
@@ -138,10 +144,10 @@ impl Arbitrary for Expression {
}
impl Arbitrary for Value {
type Parameters = ();
type Parameters = Option<ConstantType>;
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
fn arbitrary_with(target_type: Self::Parameters) -> Self::Strategy {
let base_strategy = Union::new([
Just(None::<u8>),
Just(Some(2)),
@@ -150,10 +156,47 @@ impl Arbitrary for Value {
Just(Some(16)),
]);
let value_strategy = i64::arbitrary();
let type_strategy = if target_type.is_some() {
Just(target_type).boxed()
} else {
proptest::option::of(ConstantType::arbitrary()).boxed()
};
let value_strategy = u64::arbitrary();
(base_strategy, value_strategy)
.prop_map(move |(base, value)| Value::Number(base, value))
(base_strategy, type_strategy, value_strategy)
.prop_map(move |(base, ty, value)| {
let converted_value = match ty {
Some(ConstantType::I8) => value % (i8::MAX as u64),
Some(ConstantType::U8) => value % (u8::MAX as u64),
Some(ConstantType::I16) => value % (i16::MAX as u64),
Some(ConstantType::U16) => value % (u16::MAX as u64),
Some(ConstantType::I32) => value % (i32::MAX as u64),
Some(ConstantType::U32) => value % (u32::MAX as u64),
Some(ConstantType::I64) => value % (i64::MAX as u64),
Some(ConstantType::U64) => value,
None => value,
};
Value::Number(base, ty, converted_value)
})
.boxed()
}
}
impl Arbitrary for ConstantType {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
Union::new([
Just(ConstantType::I8),
Just(ConstantType::I16),
Just(ConstantType::I32),
Just(ConstantType::I64),
Just(ConstantType::U8),
Just(ConstantType::U16),
Just(ConstantType::U32),
Just(ConstantType::U64),
])
.boxed()
}
}