Add memory management
This commit is contained in:
parent
4be32d0a5d
commit
fdf286cb51
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -204,6 +204,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
|
"log",
|
||||||
"stanza",
|
"stanza",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -18,4 +18,5 @@ chumsky = { version = "1.0.0-alpha.6", features = ["pratt", "label"] }
|
|||||||
clap = { version = "4.5.2", features = ["derive"] }
|
clap = { version = "4.5.2", features = ["derive"] }
|
||||||
colored = "2.1.0"
|
colored = "2.1.0"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.11.3"
|
||||||
|
log = "0.4.21"
|
||||||
stanza = "0.5.1"
|
stanza = "0.5.1"
|
||||||
|
@ -52,6 +52,7 @@ impl AbstractTree for Assignment {
|
|||||||
context.set_type(self.identifier.clone(), statement_type)?;
|
context.set_type(self.identifier.clone(), statement_type)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.identifier.validate(context)?;
|
||||||
self.statement.validate(context)?;
|
self.statement.validate(context)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -38,12 +38,12 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let value = self.function.run(context)?.as_value()?;
|
let value = self.function.run(context)?.as_return_value()?;
|
||||||
let function = value.as_function()?;
|
let function = value.as_function()?;
|
||||||
let mut arguments = Vec::with_capacity(self.arguments.len());
|
let mut arguments = Vec::with_capacity(self.arguments.len());
|
||||||
|
|
||||||
for expression in self.arguments {
|
for expression in self.arguments {
|
||||||
let value = expression.run(context)?.as_value()?;
|
let value = expression.run(context)?.as_return_value()?;
|
||||||
|
|
||||||
arguments.push(value);
|
arguments.push(value);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use std::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Action, Type};
|
use super::{AbstractTree, Action, Type};
|
||||||
@ -34,7 +33,7 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
if let Some(_) = context.get_data(self)? {
|
if context.add_allowance(self)? {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(ValidationError::VariableNotFound(self.clone()))
|
Err(ValidationError::VariableNotFound(self.clone()))
|
||||||
@ -42,12 +41,15 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let value = context
|
let return_action = context.get_value(&self)?.map(|value| Action::Return(value));
|
||||||
.get_value(&self)?
|
|
||||||
.unwrap_or_else(Value::none)
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
Ok(Action::Return(value))
|
if let Some(action) = return_action {
|
||||||
|
Ok(action)
|
||||||
|
} else {
|
||||||
|
Err(RuntimeError::ValidationFailure(
|
||||||
|
ValidationError::VariableNotFound(self.clone()),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
Value,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Action, Expression, Type, ValueNode};
|
use super::{AbstractTree, Action, Expression, Type, ValueNode};
|
||||||
@ -63,11 +62,13 @@ impl AbstractTree for Index {
|
|||||||
let right_value = self.right.run(_context)?.as_return_value()?;
|
let right_value = self.right.run(_context)?.as_return_value()?;
|
||||||
|
|
||||||
if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) {
|
if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) {
|
||||||
Ok(Action::Return(
|
let found_item = list.get(index as usize);
|
||||||
list.get(index as usize)
|
|
||||||
.cloned()
|
if let Some(item) = found_item {
|
||||||
.unwrap_or_else(Value::none),
|
Ok(Action::Return(item.clone()))
|
||||||
))
|
} else {
|
||||||
|
Ok(Action::None)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(RuntimeError::ValidationFailure(
|
Err(RuntimeError::ValidationFailure(
|
||||||
ValidationError::CannotIndexWith(left_value.r#type(), right_value.r#type()),
|
ValidationError::CannotIndexWith(left_value.r#type(), right_value.r#type()),
|
||||||
|
@ -44,19 +44,12 @@ pub trait AbstractTree {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
Break,
|
|
||||||
Return(Value),
|
Return(Value),
|
||||||
|
Break,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Action {
|
impl Action {
|
||||||
pub fn as_value(self) -> Result<Value, ValidationError> {
|
|
||||||
match self {
|
|
||||||
Action::Return(value) => Ok(value),
|
|
||||||
_ => Err(ValidationError::ExpectedValue),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_return_value(self) -> Result<Value, ValidationError> {
|
pub fn as_return_value(self) -> Result<Value, ValidationError> {
|
||||||
if let Action::Return(value) = self {
|
if let Action::Return(value) = self {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -17,7 +17,6 @@ pub enum ValueNode {
|
|||||||
Map(Vec<(Identifier, Option<Type>, Expression)>),
|
Map(Vec<(Identifier, Option<Type>, Expression)>),
|
||||||
Range(Range<i64>),
|
Range(Range<i64>),
|
||||||
String(String),
|
String(String),
|
||||||
Enum(Identifier, Identifier),
|
|
||||||
Function {
|
Function {
|
||||||
parameters: Vec<(Identifier, Type)>,
|
parameters: Vec<(Identifier, Type)>,
|
||||||
return_type: Type,
|
return_type: Type,
|
||||||
@ -43,7 +42,6 @@ impl AbstractTree for ValueNode {
|
|||||||
ValueNode::Map(_) => Type::Map,
|
ValueNode::Map(_) => Type::Map,
|
||||||
ValueNode::Range(_) => Type::Range,
|
ValueNode::Range(_) => Type::Range,
|
||||||
ValueNode::String(_) => Type::String,
|
ValueNode::String(_) => Type::String,
|
||||||
ValueNode::Enum(name, _) => Type::Custom(name.clone()),
|
|
||||||
ValueNode::Function {
|
ValueNode::Function {
|
||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
@ -123,13 +121,6 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
ValueNode::Range(range) => Value::range(range),
|
ValueNode::Range(range) => Value::range(range),
|
||||||
ValueNode::String(string) => Value::string(string),
|
ValueNode::String(string) => Value::string(string),
|
||||||
ValueNode::Enum(name, variant) => {
|
|
||||||
if name.as_str() == "Option" && variant.as_str() == "None" {
|
|
||||||
Value::none()
|
|
||||||
} else {
|
|
||||||
Value::r#enum(name, variant)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ValueNode::Function {
|
ValueNode::Function {
|
||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
@ -176,16 +167,6 @@ impl Ord for ValueNode {
|
|||||||
(Range(_), _) => Ordering::Greater,
|
(Range(_), _) => Ordering::Greater,
|
||||||
(String(left), String(right)) => left.cmp(right),
|
(String(left), String(right)) => left.cmp(right),
|
||||||
(String(_), _) => Ordering::Greater,
|
(String(_), _) => Ordering::Greater,
|
||||||
(Enum(left_name, left_variant), Enum(right_name, right_variant)) => {
|
|
||||||
let name_cmp = left_name.cmp(right_name);
|
|
||||||
|
|
||||||
if name_cmp.is_eq() {
|
|
||||||
left_variant.cmp(right_variant)
|
|
||||||
} else {
|
|
||||||
name_cmp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Enum(_, _), _) => Ordering::Greater,
|
|
||||||
(
|
(
|
||||||
Function {
|
Function {
|
||||||
parameters: left_parameters,
|
parameters: left_parameters,
|
||||||
|
@ -27,15 +27,15 @@ impl AbstractTree for While {
|
|||||||
self.block.validate(_context)
|
self.block.validate(_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
||||||
while self
|
while self
|
||||||
.expression
|
.expression
|
||||||
.clone()
|
.clone()
|
||||||
.run(_context)?
|
.run(context)?
|
||||||
.as_return_value()?
|
.as_return_value()?
|
||||||
.as_boolean()?
|
.as_boolean()?
|
||||||
{
|
{
|
||||||
if let Action::Break = self.block.clone().run(_context)? {
|
if let Action::Break = self.block.clone().run(context)? {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
107
src/context.rs
107
src/context.rs
@ -11,7 +11,25 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
inner: Arc<RwLock<BTreeMap<Identifier, ValueData>>>,
|
inner: Arc<RwLock<BTreeMap<Identifier, (ValueData, UsageData)>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct UsageData(Arc<RwLock<UsageDataInner>>);
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct UsageDataInner {
|
||||||
|
pub allowances: usize,
|
||||||
|
pub uses: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UsageData {
|
||||||
|
fn default() -> Self {
|
||||||
|
UsageData(Arc::new(RwLock::new(UsageDataInner {
|
||||||
|
allowances: 0,
|
||||||
|
uses: 0,
|
||||||
|
})))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -27,7 +45,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_data(data: BTreeMap<Identifier, ValueData>) -> Self {
|
pub fn with_data(data: BTreeMap<Identifier, (ValueData, UsageData)>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(RwLock::new(data)),
|
inner: Arc::new(RwLock::new(data)),
|
||||||
}
|
}
|
||||||
@ -36,10 +54,10 @@ impl Context {
|
|||||||
pub fn inherit_types_from(other: &Context) -> Result<Self, RwLockPoisonError> {
|
pub fn inherit_types_from(other: &Context) -> Result<Self, RwLockPoisonError> {
|
||||||
let mut new_data = BTreeMap::new();
|
let mut new_data = BTreeMap::new();
|
||||||
|
|
||||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() {
|
||||||
if let ValueData::Type(r#type) = value_data {
|
if let ValueData::Type(r#type) = value_data {
|
||||||
if let Type::Function { .. } = r#type {
|
if let Type::Function { .. } = r#type {
|
||||||
new_data.insert(identifier.clone(), value_data.clone());
|
new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,15 +68,15 @@ impl Context {
|
|||||||
pub fn inherit_data_from(other: &Context) -> Result<Self, RwLockPoisonError> {
|
pub fn inherit_data_from(other: &Context) -> Result<Self, RwLockPoisonError> {
|
||||||
let mut new_data = BTreeMap::new();
|
let mut new_data = BTreeMap::new();
|
||||||
|
|
||||||
for (identifier, value_data) in other.inner.read()?.iter() {
|
for (identifier, (value_data, usage_data)) in other.inner.read()?.iter() {
|
||||||
if let ValueData::Type(r#type) = value_data {
|
if let ValueData::Type(r#type) = value_data {
|
||||||
if let Type::Function { .. } = r#type {
|
if let Type::Function { .. } = r#type {
|
||||||
new_data.insert(identifier.clone(), value_data.clone());
|
new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let ValueData::Value(value) = value_data {
|
if let ValueData::Value(value) = value_data {
|
||||||
if let ValueInner::Function { .. } = value.inner().as_ref() {
|
if let ValueInner::Function { .. } = value.inner().as_ref() {
|
||||||
new_data.insert(identifier.clone(), value_data.clone());
|
new_data.insert(identifier.clone(), (value_data.clone(), usage_data.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,12 +84,41 @@ impl Context {
|
|||||||
Ok(Self::with_data(new_data))
|
Ok(Self::with_data(new_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_allowance(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
|
||||||
|
if let Some((_, usage_data)) = self.inner.read()?.get(identifier) {
|
||||||
|
usage_data.0.write()?.allowances += 1;
|
||||||
|
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_data(
|
pub fn get_data(
|
||||||
&self,
|
&self,
|
||||||
identifier: &Identifier,
|
identifier: &Identifier,
|
||||||
) -> Result<Option<ValueData>, RwLockPoisonError> {
|
) -> Result<Option<ValueData>, RwLockPoisonError> {
|
||||||
if let Some(value_data) = self.inner.read()?.get(identifier) {
|
let should_remove =
|
||||||
return Ok(Some(value_data.clone()));
|
if let Some((value_data, usage_data)) = self.inner.read()?.get(identifier) {
|
||||||
|
let mut usage_data = usage_data.0.write()?;
|
||||||
|
|
||||||
|
log::trace!("Adding use for variable: {identifier}");
|
||||||
|
|
||||||
|
usage_data.uses += 1;
|
||||||
|
|
||||||
|
if usage_data.uses == usage_data.allowances {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
return Ok(Some(value_data.clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_remove {
|
||||||
|
log::trace!("Removing varialble: {identifier}");
|
||||||
|
|
||||||
|
self.inner.write()?.remove(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
let value_data = match identifier.as_str() {
|
let value_data = match identifier.as_str() {
|
||||||
@ -83,7 +130,11 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> {
|
pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> {
|
||||||
if let Some(ValueData::Type(r#type)) = self.inner.read()?.get(identifier) {
|
if let Some((ValueData::Type(r#type), usage_data)) = self.inner.read()?.get(identifier) {
|
||||||
|
log::trace!("Adding use for variable: {identifier}");
|
||||||
|
|
||||||
|
usage_data.0.write()?.uses += 1;
|
||||||
|
|
||||||
return Ok(Some(r#type.clone()));
|
return Ok(Some(r#type.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +147,28 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
pub fn get_value(&self, identifier: &Identifier) -> Result<Option<Value>, RwLockPoisonError> {
|
||||||
if let Some(ValueData::Value(value)) = self.inner.read()?.get(identifier) {
|
let should_remove = if let Some((ValueData::Value(value), usage_data)) =
|
||||||
return Ok(Some(value.clone()));
|
self.inner.read()?.get(identifier)
|
||||||
|
{
|
||||||
|
let mut usage_data = usage_data.0.write()?;
|
||||||
|
|
||||||
|
log::trace!("Adding use for variable: {identifier}");
|
||||||
|
|
||||||
|
usage_data.uses += 1;
|
||||||
|
|
||||||
|
if usage_data.uses == usage_data.allowances {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
return Ok(Some(value.clone()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if should_remove {
|
||||||
|
log::trace!("Removing varialble: {identifier}");
|
||||||
|
|
||||||
|
self.inner.write()?.remove(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
let value = match identifier.as_str() {
|
let value = match identifier.as_str() {
|
||||||
@ -111,15 +182,19 @@ impl Context {
|
|||||||
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> {
|
pub fn set_type(&self, identifier: Identifier, r#type: Type) -> Result<(), RwLockPoisonError> {
|
||||||
self.inner
|
self.inner
|
||||||
.write()?
|
.write()?
|
||||||
.insert(identifier, ValueData::Type(r#type));
|
.insert(identifier, (ValueData::Type(r#type), UsageData::default()));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> {
|
pub fn set_value(&self, identifier: Identifier, value: Value) -> Result<(), RwLockPoisonError> {
|
||||||
self.inner
|
let mut inner = self.inner.write()?;
|
||||||
.write()?
|
|
||||||
.insert(identifier, ValueData::Value(value));
|
if let Some((_value_data, usage_data)) = inner.remove(&identifier) {
|
||||||
|
inner.insert(identifier, (ValueData::Value(value), usage_data));
|
||||||
|
} else {
|
||||||
|
inner.insert(identifier, (ValueData::Value(value), UsageData::default()));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -169,13 +169,6 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
)
|
)
|
||||||
.map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list)));
|
.map(|map_assigment_list| Expression::Value(ValueNode::Map(map_assigment_list)));
|
||||||
|
|
||||||
let r#enum = identifier
|
|
||||||
.clone()
|
|
||||||
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
|
||||||
.then(identifier.clone())
|
|
||||||
.map(|(name, variant)| Expression::Value(ValueNode::Enum(name, variant)))
|
|
||||||
.boxed();
|
|
||||||
|
|
||||||
let function = identifier
|
let function = identifier
|
||||||
.clone()
|
.clone()
|
||||||
.then(type_specification.clone())
|
.then(type_specification.clone())
|
||||||
@ -219,7 +212,6 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
identifier_expression.clone(),
|
identifier_expression.clone(),
|
||||||
basic_value.clone(),
|
basic_value.clone(),
|
||||||
list.clone(),
|
list.clone(),
|
||||||
r#enum.clone(),
|
|
||||||
expression.clone().delimited_by(
|
expression.clone().delimited_by(
|
||||||
just(Token::Control(Control::ParenOpen)),
|
just(Token::Control(Control::ParenOpen)),
|
||||||
just(Token::Control(Control::ParenClose)),
|
just(Token::Control(Control::ParenClose)),
|
||||||
@ -289,7 +281,6 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
choice((
|
choice((
|
||||||
function,
|
function,
|
||||||
range,
|
range,
|
||||||
r#enum,
|
|
||||||
logic_math_and_index,
|
logic_math_and_index,
|
||||||
identifier_expression,
|
identifier_expression,
|
||||||
list,
|
list,
|
||||||
@ -661,22 +652,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assignment_with_custom_type() {
|
|
||||||
assert_eq!(
|
|
||||||
parse(&lex("foobar: Foo = Foo::Bar").unwrap()).unwrap()[0].0,
|
|
||||||
Statement::Assignment(Assignment::new(
|
|
||||||
Identifier::new("foobar"),
|
|
||||||
Some(Type::Custom(Identifier::new("Foo"))),
|
|
||||||
AssignmentOperator::Assign,
|
|
||||||
Statement::Expression(Expression::Value(ValueNode::Enum(
|
|
||||||
Identifier::new("Foo"),
|
|
||||||
Identifier::new("Bar")
|
|
||||||
)))
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn assignment_with_list_types() {
|
fn assignment_with_list_types() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -755,17 +730,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn r#enum() {
|
|
||||||
assert_eq!(
|
|
||||||
parse(&lex("Option::None").unwrap()).unwrap()[0].0,
|
|
||||||
Statement::Expression(Expression::Value(ValueNode::Enum(
|
|
||||||
Identifier::new("Option"),
|
|
||||||
Identifier::new("None")
|
|
||||||
)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list() {
|
fn list() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
37
src/value.rs
37
src/value.rs
@ -18,17 +18,6 @@ use crate::{
|
|||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static NONE: OnceLock<Value> = OnceLock::new();
|
|
||||||
|
|
||||||
fn get_none<'a>() -> &'a Value {
|
|
||||||
NONE.get_or_init(|| {
|
|
||||||
Value(Arc::new(ValueInner::Enum(
|
|
||||||
Identifier::new("Option"),
|
|
||||||
Identifier::new("None"),
|
|
||||||
)))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Value(Arc<ValueInner>);
|
pub struct Value(Arc<ValueInner>);
|
||||||
|
|
||||||
@ -37,10 +26,6 @@ impl Value {
|
|||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn none() -> Self {
|
|
||||||
get_none().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn boolean(boolean: bool) -> Self {
|
pub fn boolean(boolean: bool) -> Self {
|
||||||
Value(Arc::new(ValueInner::Boolean(boolean)))
|
Value(Arc::new(ValueInner::Boolean(boolean)))
|
||||||
}
|
}
|
||||||
@ -69,10 +54,6 @@ impl Value {
|
|||||||
Value(Arc::new(ValueInner::String(string)))
|
Value(Arc::new(ValueInner::String(string)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn r#enum(name: Identifier, variant: Identifier) -> Self {
|
|
||||||
Value(Arc::new(ValueInner::Enum(name, variant)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn function(parameters: Vec<(Identifier, Type)>, return_type: Type, body: Block) -> Self {
|
pub fn function(parameters: Vec<(Identifier, Type)>, return_type: Type, body: Block) -> Self {
|
||||||
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
||||||
ParsedFunction {
|
ParsedFunction {
|
||||||
@ -104,7 +85,6 @@ impl Value {
|
|||||||
ValueInner::Map(_) => Type::Map,
|
ValueInner::Map(_) => Type::Map,
|
||||||
ValueInner::Range(_) => Type::Range,
|
ValueInner::Range(_) => Type::Range,
|
||||||
ValueInner::String(_) => Type::String,
|
ValueInner::String(_) => Type::String,
|
||||||
ValueInner::Enum(name, _) => Type::Custom(name.clone()),
|
|
||||||
ValueInner::Function(_) => todo!(),
|
ValueInner::Function(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,10 +129,6 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_none(&self) -> bool {
|
|
||||||
self == get_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&self, other: &Self) -> Result<Value, ValidationError> {
|
pub fn add(&self, other: &Self) -> Result<Value, ValidationError> {
|
||||||
match (self.inner().as_ref(), other.inner().as_ref()) {
|
match (self.inner().as_ref(), other.inner().as_ref()) {
|
||||||
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
|
||||||
@ -236,8 +212,6 @@ impl Display for Value {
|
|||||||
}
|
}
|
||||||
ValueInner::Range(_) => todo!(),
|
ValueInner::Range(_) => todo!(),
|
||||||
ValueInner::String(string) => write!(f, "{string}"),
|
ValueInner::String(string) => write!(f, "{string}"),
|
||||||
|
|
||||||
ValueInner::Enum(_, _) => todo!(),
|
|
||||||
ValueInner::Function(Function::Parsed(ParsedFunction {
|
ValueInner::Function(Function::Parsed(ParsedFunction {
|
||||||
parameters,
|
parameters,
|
||||||
return_type,
|
return_type,
|
||||||
@ -282,7 +256,6 @@ pub enum ValueInner {
|
|||||||
Map(BTreeMap<Identifier, Value>),
|
Map(BTreeMap<Identifier, Value>),
|
||||||
Range(Range<i64>),
|
Range(Range<i64>),
|
||||||
String(String),
|
String(String),
|
||||||
Enum(Identifier, Identifier),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for ValueInner {}
|
impl Eq for ValueInner {}
|
||||||
@ -320,16 +293,6 @@ impl Ord for ValueInner {
|
|||||||
(Range(_), _) => Ordering::Greater,
|
(Range(_), _) => Ordering::Greater,
|
||||||
(String(left), String(right)) => left.cmp(right),
|
(String(left), String(right)) => left.cmp(right),
|
||||||
(String(_), _) => Ordering::Greater,
|
(String(_), _) => Ordering::Greater,
|
||||||
(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,
|
|
||||||
(Function(left), Function(right)) => left.cmp(right),
|
(Function(left), Function(right)) => left.cmp(right),
|
||||||
(Function(_), _) => Ordering::Greater,
|
(Function(_), _) => Ordering::Greater,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user