2024-02-25 18:49:26 +00:00
|
|
|
use std::{
|
2024-02-25 19:26:22 +00:00
|
|
|
cmp::Ordering,
|
2024-02-28 23:36:47 +00:00
|
|
|
collections::BTreeMap,
|
2024-03-06 20:36:58 +00:00
|
|
|
fmt::{self, Display, Formatter},
|
2024-02-25 18:49:26 +00:00
|
|
|
ops::Range,
|
|
|
|
sync::{Arc, OnceLock},
|
|
|
|
};
|
|
|
|
|
2024-03-08 03:20:59 +00:00
|
|
|
use stanza::{
|
|
|
|
renderer::{console::Console, Renderer},
|
|
|
|
style::{HAlign, MinWidth, Styles},
|
|
|
|
table::Table,
|
|
|
|
};
|
|
|
|
|
2024-03-06 22:32:31 +00:00
|
|
|
use crate::{
|
2024-03-09 03:34:17 +00:00
|
|
|
abstract_tree::{Action, Identifier, Statement, Type},
|
|
|
|
context::Context,
|
|
|
|
error::{RuntimeError, ValidationError},
|
2024-03-06 22:32:31 +00:00
|
|
|
};
|
2024-02-25 18:49:26 +00:00
|
|
|
|
|
|
|
pub static NONE: OnceLock<Value> = OnceLock::new();
|
|
|
|
|
2024-03-06 20:36:58 +00:00
|
|
|
fn get_none<'a>() -> &'a Value {
|
|
|
|
NONE.get_or_init(|| {
|
|
|
|
Value(Arc::new(ValueInner::Enum(
|
|
|
|
Identifier::new("Option"),
|
|
|
|
Identifier::new("None"),
|
|
|
|
)))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-02-25 18:49:26 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub struct Value(Arc<ValueInner>);
|
|
|
|
|
|
|
|
impl Value {
|
|
|
|
pub fn inner(&self) -> &Arc<ValueInner> {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
|
2024-03-02 00:15:03 +00:00
|
|
|
pub fn none() -> Self {
|
2024-03-06 20:36:58 +00:00
|
|
|
get_none().clone()
|
2024-03-02 00:15:03 +00:00
|
|
|
}
|
|
|
|
|
2024-02-25 18:49:26 +00:00
|
|
|
pub fn boolean(boolean: bool) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::Boolean(boolean)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn float(float: f64) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::Float(float)))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn integer(integer: i64) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::Integer(integer)))
|
|
|
|
}
|
|
|
|
|
2024-02-26 21:27:01 +00:00
|
|
|
pub fn list(list: Vec<Value>) -> Self {
|
2024-02-25 18:49:26 +00:00
|
|
|
Value(Arc::new(ValueInner::List(list)))
|
|
|
|
}
|
|
|
|
|
2024-02-28 23:36:47 +00:00
|
|
|
pub fn map(map: BTreeMap<Identifier, Value>) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::Map(map)))
|
|
|
|
}
|
2024-02-25 18:49:26 +00:00
|
|
|
|
|
|
|
pub fn range(range: Range<i64>) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::Range(range)))
|
|
|
|
}
|
|
|
|
|
2024-03-08 21:22:24 +00:00
|
|
|
pub fn string(string: String) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::String(string)))
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 23:36:47 +00:00
|
|
|
pub fn r#enum(name: Identifier, variant: Identifier) -> Self {
|
|
|
|
Value(Arc::new(ValueInner::Enum(name, variant)))
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
2024-02-25 19:26:22 +00:00
|
|
|
|
2024-03-08 21:14:47 +00:00
|
|
|
pub fn function(
|
|
|
|
parameters: Vec<(Identifier, Type)>,
|
|
|
|
return_type: Type,
|
|
|
|
body: Statement,
|
|
|
|
) -> Self {
|
2024-03-09 03:34:17 +00:00
|
|
|
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
|
|
|
ParsedFunction {
|
|
|
|
parameters,
|
|
|
|
return_type,
|
|
|
|
body,
|
|
|
|
},
|
|
|
|
))))
|
2024-03-08 21:14:47 +00:00
|
|
|
}
|
|
|
|
|
2024-03-06 22:32:31 +00:00
|
|
|
pub fn r#type(&self) -> Type {
|
|
|
|
match self.0.as_ref() {
|
|
|
|
ValueInner::Boolean(_) => Type::Boolean,
|
|
|
|
ValueInner::Float(_) => Type::Float,
|
|
|
|
ValueInner::Integer(_) => Type::Integer,
|
|
|
|
ValueInner::List(values) => {
|
|
|
|
let mut types = Vec::with_capacity(values.len());
|
|
|
|
|
|
|
|
for value in values {
|
|
|
|
types.push(value.r#type());
|
|
|
|
}
|
|
|
|
|
|
|
|
Type::ListExact(types)
|
|
|
|
}
|
|
|
|
ValueInner::Map(_) => Type::Map,
|
|
|
|
ValueInner::Range(_) => Type::Range,
|
|
|
|
ValueInner::String(_) => Type::String,
|
|
|
|
ValueInner::Enum(name, _) => Type::Custom(name.clone()),
|
2024-03-08 21:14:47 +00:00
|
|
|
ValueInner::Function(_) => todo!(),
|
2024-03-06 22:32:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-29 02:04:38 +00:00
|
|
|
pub fn as_boolean(&self) -> Result<bool, ValidationError> {
|
2024-02-25 19:26:22 +00:00
|
|
|
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
|
|
|
|
return Ok(*boolean);
|
|
|
|
}
|
|
|
|
|
2024-02-29 02:04:38 +00:00
|
|
|
Err(ValidationError::ExpectedBoolean)
|
2024-02-25 19:26:22 +00:00
|
|
|
}
|
2024-03-06 20:36:58 +00:00
|
|
|
|
2024-03-07 11:33:54 +00:00
|
|
|
pub fn as_number(&self) -> Result<bool, ValidationError> {
|
|
|
|
if let ValueInner::Boolean(boolean) = self.0.as_ref() {
|
|
|
|
return Ok(*boolean);
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(ValidationError::ExpectedBoolean)
|
|
|
|
}
|
|
|
|
|
2024-03-07 17:29:07 +00:00
|
|
|
pub fn as_list(&self) -> Option<&Vec<Value>> {
|
|
|
|
if let ValueInner::List(list) = self.inner().as_ref() {
|
|
|
|
Some(list)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn as_integer(&self) -> Option<i64> {
|
|
|
|
if let ValueInner::Integer(integer) = self.inner().as_ref() {
|
|
|
|
Some(*integer)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-06 20:36:58 +00:00
|
|
|
pub fn is_none(&self) -> bool {
|
|
|
|
self == get_none()
|
|
|
|
}
|
2024-03-08 18:26:55 +00:00
|
|
|
|
|
|
|
pub fn add(&self, other: &Self) -> Result<Value, ValidationError> {
|
2024-03-09 00:05:17 +00:00
|
|
|
match (self.inner().as_ref(), other.inner().as_ref()) {
|
|
|
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
|
|
|
let sum = left.saturating_add(*right);
|
|
|
|
|
|
|
|
Ok(Value::integer(sum))
|
|
|
|
}
|
|
|
|
(ValueInner::Float(left), ValueInner::Float(right)) => {
|
|
|
|
let sum = left + right;
|
|
|
|
|
|
|
|
Ok(Value::float(sum))
|
|
|
|
}
|
|
|
|
(ValueInner::Float(left), ValueInner::Integer(right)) => {
|
|
|
|
let sum = left + *right as f64;
|
|
|
|
|
|
|
|
Ok(Value::float(sum))
|
|
|
|
}
|
|
|
|
(ValueInner::Integer(left), ValueInner::Float(right)) => {
|
|
|
|
let sum = *left as f64 + right;
|
|
|
|
|
|
|
|
Ok(Value::float(sum))
|
|
|
|
}
|
|
|
|
_ => Err(ValidationError::ExpectedIntegerOrFloat),
|
2024-03-08 18:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn subtract(&self, other: &Self) -> Result<Value, ValidationError> {
|
2024-03-09 00:05:17 +00:00
|
|
|
match (self.inner().as_ref(), other.inner().as_ref()) {
|
|
|
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
|
|
|
let sum = left.saturating_sub(*right);
|
|
|
|
|
|
|
|
Ok(Value::integer(sum))
|
|
|
|
}
|
|
|
|
(ValueInner::Float(left), ValueInner::Float(right)) => {
|
|
|
|
let sum = left - right;
|
|
|
|
|
|
|
|
Ok(Value::float(sum))
|
|
|
|
}
|
|
|
|
(ValueInner::Float(left), ValueInner::Integer(right)) => {
|
|
|
|
let sum = left - *right as f64;
|
|
|
|
|
|
|
|
Ok(Value::float(sum))
|
|
|
|
}
|
|
|
|
(ValueInner::Integer(left), ValueInner::Float(right)) => {
|
|
|
|
let sum = *left as f64 - right;
|
|
|
|
|
|
|
|
Ok(Value::float(sum))
|
|
|
|
}
|
|
|
|
_ => Err(ValidationError::ExpectedIntegerOrFloat),
|
2024-03-08 18:26:55 +00:00
|
|
|
}
|
|
|
|
}
|
2024-03-06 20:36:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for Value {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
2024-03-08 03:20:59 +00:00
|
|
|
fn create_table() -> Table {
|
|
|
|
Table::with_styles(Styles::default().with(HAlign::Centred).with(MinWidth(3)))
|
|
|
|
}
|
|
|
|
|
2024-03-06 20:36:58 +00:00
|
|
|
match self.inner().as_ref() {
|
2024-03-08 21:14:47 +00:00
|
|
|
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
|
|
|
|
ValueInner::Float(float) => write!(f, "{float}"),
|
|
|
|
ValueInner::Integer(integer) => write!(f, "{integer}"),
|
|
|
|
ValueInner::List(list) => {
|
2024-03-08 03:20:59 +00:00
|
|
|
let mut table = create_table();
|
|
|
|
|
|
|
|
for value in list {
|
|
|
|
table = table.with_row([value.to_string()]);
|
|
|
|
}
|
|
|
|
|
|
|
|
write!(f, "{}", Console::default().render(&table))
|
|
|
|
}
|
2024-03-08 21:14:47 +00:00
|
|
|
ValueInner::Map(map) => {
|
2024-03-08 03:20:59 +00:00
|
|
|
let mut table = create_table();
|
2024-03-07 21:19:24 +00:00
|
|
|
|
|
|
|
for (identifier, value) in map {
|
2024-03-08 03:20:59 +00:00
|
|
|
table = table.with_row([identifier.as_str(), &value.to_string()]);
|
2024-03-07 21:19:24 +00:00
|
|
|
}
|
|
|
|
|
2024-03-08 03:20:59 +00:00
|
|
|
write!(f, "{}", Console::default().render(&table))
|
2024-03-07 21:19:24 +00:00
|
|
|
}
|
2024-03-08 21:14:47 +00:00
|
|
|
ValueInner::Range(_) => todo!(),
|
|
|
|
ValueInner::String(string) => write!(f, "{string}"),
|
|
|
|
|
|
|
|
ValueInner::Enum(_, _) => todo!(),
|
2024-03-09 03:34:17 +00:00
|
|
|
ValueInner::Function(Function::Parsed(ParsedFunction {
|
2024-03-08 21:14:47 +00:00
|
|
|
parameters,
|
|
|
|
return_type,
|
|
|
|
body,
|
2024-03-09 03:34:17 +00:00
|
|
|
})) => {
|
2024-03-08 21:14:47 +00:00
|
|
|
write!(f, "(")?;
|
|
|
|
|
|
|
|
for (identifier, r#type) in parameters {
|
|
|
|
write!(f, "{identifier}: {}", r#type)?;
|
|
|
|
}
|
2024-03-08 03:20:59 +00:00
|
|
|
|
2024-03-08 21:14:47 +00:00
|
|
|
write!(f, "): {return_type} {body:?}")
|
|
|
|
}
|
2024-03-09 03:34:17 +00:00
|
|
|
ValueInner::Function(Function::BuiltIn(built_in_function)) => {
|
|
|
|
write!(f, "{built_in_function}")
|
|
|
|
}
|
2024-03-06 20:36:58 +00:00
|
|
|
}
|
|
|
|
}
|
2024-02-25 19:26:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Eq for Value {}
|
|
|
|
|
|
|
|
impl PartialOrd for Value {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for Value {
|
|
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
|
|
self.0.as_ref().cmp(other.0.as_ref())
|
|
|
|
}
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
|
|
|
pub enum ValueInner {
|
|
|
|
Boolean(bool),
|
|
|
|
Float(f64),
|
2024-03-08 21:14:47 +00:00
|
|
|
Function(Function),
|
2024-02-25 18:49:26 +00:00
|
|
|
Integer(i64),
|
2024-02-26 21:27:01 +00:00
|
|
|
List(Vec<Value>),
|
2024-02-28 23:36:47 +00:00
|
|
|
Map(BTreeMap<Identifier, Value>),
|
2024-02-25 18:49:26 +00:00
|
|
|
Range(Range<i64>),
|
|
|
|
String(String),
|
2024-02-28 23:36:47 +00:00
|
|
|
Enum(Identifier, Identifier),
|
2024-02-25 18:49:26 +00:00
|
|
|
}
|
|
|
|
|
2024-02-25 19:26:22 +00:00
|
|
|
impl Eq for ValueInner {}
|
|
|
|
|
|
|
|
impl PartialOrd for ValueInner {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Ord for ValueInner {
|
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
use ValueInner::*;
|
|
|
|
|
|
|
|
match (self, other) {
|
|
|
|
(Boolean(left), Boolean(right)) => left.cmp(right),
|
|
|
|
(Boolean(_), _) => Ordering::Greater,
|
|
|
|
(Float(left), Float(right)) => left.total_cmp(right),
|
|
|
|
(Float(_), _) => Ordering::Greater,
|
|
|
|
(Integer(left), Integer(right)) => left.cmp(right),
|
|
|
|
(Integer(_), _) => Ordering::Greater,
|
|
|
|
(List(left), List(right)) => left.cmp(right),
|
|
|
|
(List(_), _) => Ordering::Greater,
|
2024-02-28 23:36:47 +00:00
|
|
|
(Map(left), Map(right)) => left.cmp(right),
|
|
|
|
(Map(_), _) => Ordering::Greater,
|
2024-02-25 19:26:22 +00:00
|
|
|
(Range(left), Range(right)) => {
|
|
|
|
let start_cmp = left.start.cmp(&right.start);
|
|
|
|
|
|
|
|
if start_cmp.is_eq() {
|
|
|
|
left.end.cmp(&right.end)
|
|
|
|
} else {
|
|
|
|
start_cmp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(Range(_), _) => Ordering::Greater,
|
|
|
|
(String(left), String(right)) => left.cmp(right),
|
|
|
|
(String(_), _) => Ordering::Greater,
|
2024-02-28 23:36:47 +00:00
|
|
|
(Enum(name_left, variant_left), Enum(name_right, variant_right)) => {
|
|
|
|
let name_cmp = name_left.cmp(name_right);
|
|
|
|
|
|
|
|
if name_cmp.is_eq() {
|
|
|
|
variant_left.cmp(variant_right)
|
|
|
|
} else {
|
|
|
|
name_cmp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(Enum(..), _) => Ordering::Greater,
|
2024-03-08 21:14:47 +00:00
|
|
|
(Function(left), Function(right)) => left.cmp(right),
|
|
|
|
(Function(_), _) => Ordering::Greater,
|
2024-02-25 19:26:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-08 21:14:47 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
2024-03-09 03:34:17 +00:00
|
|
|
pub enum Function {
|
|
|
|
Parsed(ParsedFunction),
|
|
|
|
BuiltIn(BuiltInFunction),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
pub struct ParsedFunction {
|
2024-03-08 21:14:47 +00:00
|
|
|
parameters: Vec<(Identifier, Type)>,
|
|
|
|
return_type: Type,
|
|
|
|
body: Statement,
|
|
|
|
}
|
2024-03-09 03:34:17 +00:00
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
|
|
|
pub enum BuiltInFunction {
|
|
|
|
Output(Value),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BuiltInFunction {
|
|
|
|
fn r#type(&self, context: &Context) -> Type {
|
|
|
|
match self {
|
|
|
|
BuiltInFunction::Output(_) => Type::Function {
|
|
|
|
parameter_types: vec![Type::Any],
|
|
|
|
return_type: Box::new(Type::None),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call(self, context: &Context) -> Result<Action, RuntimeError> {
|
|
|
|
match self {
|
|
|
|
BuiltInFunction::Output(value) => {
|
|
|
|
println!("{value}");
|
|
|
|
|
|
|
|
Ok(Action::None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for BuiltInFunction {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
BuiltInFunction::Output(_) => write!(f, "(to_output : any) : none rust_magic();"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|