Implement basic enum instances
This commit is contained in:
parent
c2d8bd299f
commit
0de25215b8
@ -16,6 +16,11 @@ use super::{
|
|||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ValueNode {
|
pub enum ValueNode {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
|
EnumInstance {
|
||||||
|
type_name: WithPosition<Identifier>,
|
||||||
|
variant: WithPosition<Identifier>,
|
||||||
|
content: Option<Vec<Expression>>,
|
||||||
|
},
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
List(Vec<Expression>),
|
List(Vec<Expression>),
|
||||||
@ -142,6 +147,34 @@ impl Evaluate for ValueNode {
|
|||||||
) -> Result<Evaluation, RuntimeError> {
|
) -> Result<Evaluation, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||||
|
|
||||||
|
ValueNode::EnumInstance {
|
||||||
|
type_name,
|
||||||
|
variant,
|
||||||
|
content: expressions,
|
||||||
|
} => {
|
||||||
|
let content = if let Some(expressions) = expressions {
|
||||||
|
let mut values = Vec::with_capacity(expressions.len());
|
||||||
|
|
||||||
|
for expression in expressions {
|
||||||
|
let position = expression.position();
|
||||||
|
let evaluation = expression.evaluate(context, _manage_memory)?;
|
||||||
|
|
||||||
|
if let Evaluation::Return(value) = evaluation {
|
||||||
|
values.push(value);
|
||||||
|
} else {
|
||||||
|
return Err(RuntimeError::ValidationFailure(
|
||||||
|
ValidationError::InterpreterExpectedReturn(position),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(values)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Value::enum_instance(type_name.node, variant.node, content)
|
||||||
|
}
|
||||||
ValueNode::Float(float) => Value::float(float),
|
ValueNode::Float(float) => Value::float(float),
|
||||||
ValueNode::Integer(integer) => Value::integer(integer),
|
ValueNode::Integer(integer) => Value::integer(integer),
|
||||||
ValueNode::List(expression_list) => {
|
ValueNode::List(expression_list) => {
|
||||||
@ -267,6 +300,33 @@ 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,
|
||||||
|
(
|
||||||
|
EnumInstance {
|
||||||
|
type_name: left_name,
|
||||||
|
variant: left_variant,
|
||||||
|
content: left_content,
|
||||||
|
},
|
||||||
|
EnumInstance {
|
||||||
|
type_name: right_name,
|
||||||
|
variant: right_variant,
|
||||||
|
content: right_content,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let name_cmp = left_name.cmp(right_name);
|
||||||
|
|
||||||
|
if name_cmp.is_eq() {
|
||||||
|
let variant_cmp = left_variant.cmp(right_variant);
|
||||||
|
|
||||||
|
if variant_cmp.is_eq() {
|
||||||
|
left_content.cmp(right_content)
|
||||||
|
} else {
|
||||||
|
variant_cmp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name_cmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(EnumInstance { .. }, _) => Ordering::Greater,
|
||||||
(
|
(
|
||||||
Function {
|
Function {
|
||||||
type_parameters: left_type_arguments,
|
type_parameters: left_type_arguments,
|
||||||
@ -329,6 +389,15 @@ impl ExpectedType for ValueNode {
|
|||||||
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, context: &mut Context) -> Result<Type, ValidationError> {
|
||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
ValueNode::Boolean(_) => Type::Boolean,
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
|
ValueNode::EnumInstance { type_name, .. } => {
|
||||||
|
if let Some(r#type) = context.get_type(&type_name.node)? {
|
||||||
|
r#type
|
||||||
|
} else {
|
||||||
|
return Err(ValidationError::EnumDefinitionNotFound(
|
||||||
|
type_name.node.clone(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
ValueNode::Float(_) => Type::Float,
|
ValueNode::Float(_) => Type::Float,
|
||||||
ValueNode::Integer(_) => Type::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::List(items) => {
|
ValueNode::List(items) => {
|
||||||
|
@ -160,6 +160,7 @@ pub enum ValidationError {
|
|||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: SourcePosition,
|
position: SourcePosition,
|
||||||
},
|
},
|
||||||
|
EnumDefinitionNotFound(Identifier),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<RwLockPoisonError> for ValidationError {
|
impl From<RwLockPoisonError> for ValidationError {
|
||||||
|
@ -425,8 +425,10 @@ impl InterpreterError {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
ValidationError::ExpectedString { .. } => todo!(),
|
ValidationError::ExpectedString { .. } => todo!(),
|
||||||
|
ValidationError::EnumDefinitionNotFound(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let report = builder.finish();
|
let report = builder.finish();
|
||||||
|
|
||||||
reports.push(report);
|
reports.push(report);
|
||||||
|
@ -316,6 +316,32 @@ pub fn parser<'src>(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let enum_instance = positioned_identifier
|
||||||
|
.clone()
|
||||||
|
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
||||||
|
.then(positioned_identifier.clone())
|
||||||
|
.then(
|
||||||
|
expression
|
||||||
|
.clone()
|
||||||
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
|
.collect()
|
||||||
|
.delimited_by(
|
||||||
|
just(Token::Control(Control::ParenOpen)),
|
||||||
|
just(Token::Control(Control::ParenClose)),
|
||||||
|
)
|
||||||
|
.or_not(),
|
||||||
|
)
|
||||||
|
.map_with(|((type_name, variant), content), state| {
|
||||||
|
Expression::Value(
|
||||||
|
ValueNode::EnumInstance {
|
||||||
|
type_name,
|
||||||
|
variant,
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
.with_position(state.span()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let built_in_function_call = choice((
|
let built_in_function_call = choice((
|
||||||
just(Token::Keyword(Keyword::Length))
|
just(Token::Keyword(Keyword::Length))
|
||||||
.ignore_then(expression.clone())
|
.ignore_then(expression.clone())
|
||||||
@ -390,6 +416,7 @@ pub fn parser<'src>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let atom = choice((
|
let atom = choice((
|
||||||
|
enum_instance.clone(),
|
||||||
range.clone(),
|
range.clone(),
|
||||||
function.clone(),
|
function.clone(),
|
||||||
list.clone(),
|
list.clone(),
|
||||||
@ -411,41 +438,6 @@ pub fn parser<'src>(
|
|||||||
Expression::Logic(Box::new(Logic::Not(expression)).with_position(span))
|
Expression::Logic(Box::new(Logic::Not(expression)).with_position(span))
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
postfix(
|
|
||||||
3,
|
|
||||||
expression.clone().delimited_by(
|
|
||||||
just(Token::Control(Control::SquareOpen)),
|
|
||||||
just(Token::Control(Control::SquareClose)),
|
|
||||||
),
|
|
||||||
|left, right, span| {
|
|
||||||
Expression::ListIndex(
|
|
||||||
Box::new(ListIndex::new(left, right)).with_position(span),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
postfix(
|
|
||||||
3,
|
|
||||||
turbofish.clone().or_not().then(
|
|
||||||
expression
|
|
||||||
.clone()
|
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
|
||||||
.collect()
|
|
||||||
.delimited_by(
|
|
||||||
just(Token::Control(Control::ParenOpen)),
|
|
||||||
just(Token::Control(Control::ParenClose)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|function_expression, (type_parameters, value_parameters), span| {
|
|
||||||
Expression::FunctionCall(
|
|
||||||
FunctionCall::new(
|
|
||||||
function_expression,
|
|
||||||
type_parameters,
|
|
||||||
value_parameters,
|
|
||||||
)
|
|
||||||
.with_position(span),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
infix(
|
infix(
|
||||||
left(1),
|
left(1),
|
||||||
just(Token::Operator(Operator::Equal)),
|
just(Token::Operator(Operator::Equal)),
|
||||||
@ -554,6 +546,42 @@ pub fn parser<'src>(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
postfix(
|
||||||
|
3,
|
||||||
|
expression.clone().delimited_by(
|
||||||
|
just(Token::Control(Control::SquareOpen)),
|
||||||
|
just(Token::Control(Control::SquareClose)),
|
||||||
|
),
|
||||||
|
|left, right, span| {
|
||||||
|
Expression::ListIndex(
|
||||||
|
Box::new(ListIndex::new(left, right)).with_position(span),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Function call
|
||||||
|
postfix(
|
||||||
|
3,
|
||||||
|
turbofish.clone().or_not().then(
|
||||||
|
expression
|
||||||
|
.clone()
|
||||||
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
|
.collect()
|
||||||
|
.delimited_by(
|
||||||
|
just(Token::Control(Control::ParenOpen)),
|
||||||
|
just(Token::Control(Control::ParenClose)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|function_expression, (type_parameters, value_parameters), span| {
|
||||||
|
Expression::FunctionCall(
|
||||||
|
FunctionCall::new(
|
||||||
|
function_expression,
|
||||||
|
type_parameters,
|
||||||
|
value_parameters,
|
||||||
|
)
|
||||||
|
.with_position(span),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
// As
|
// As
|
||||||
postfix(
|
postfix(
|
||||||
2,
|
2,
|
||||||
@ -568,6 +596,7 @@ pub fn parser<'src>(
|
|||||||
|
|
||||||
choice((
|
choice((
|
||||||
logic_math_indexes_as_and_function_calls,
|
logic_math_indexes_as_and_function_calls,
|
||||||
|
enum_instance,
|
||||||
built_in_function_call,
|
built_in_function_call,
|
||||||
range,
|
range,
|
||||||
function,
|
function,
|
||||||
@ -576,7 +605,6 @@ pub fn parser<'src>(
|
|||||||
basic_value,
|
basic_value,
|
||||||
identifier_expression,
|
identifier_expression,
|
||||||
))
|
))
|
||||||
// .delimited_by(comment.clone().or_not(), comment.or_not())
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let expression_statement = expression
|
let expression_statement = expression
|
||||||
|
@ -32,6 +32,18 @@ impl Value {
|
|||||||
Value(Arc::new(ValueInner::Boolean(boolean)))
|
Value(Arc::new(ValueInner::Boolean(boolean)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enum_instance(
|
||||||
|
type_name: Identifier,
|
||||||
|
variant: Identifier,
|
||||||
|
content: Option<Vec<Value>>,
|
||||||
|
) -> Self {
|
||||||
|
Value(Arc::new(ValueInner::EnumInstance {
|
||||||
|
type_name,
|
||||||
|
variant,
|
||||||
|
content,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn float(float: f64) -> Self {
|
pub fn float(float: f64) -> Self {
|
||||||
Value(Arc::new(ValueInner::Float(float)))
|
Value(Arc::new(ValueInner::Float(float)))
|
||||||
}
|
}
|
||||||
@ -107,6 +119,23 @@ impl Display for Value {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self.inner().as_ref() {
|
match self.inner().as_ref() {
|
||||||
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
|
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
|
||||||
|
ValueInner::EnumInstance {
|
||||||
|
type_name,
|
||||||
|
variant,
|
||||||
|
content,
|
||||||
|
} => {
|
||||||
|
if let Some(values) = content {
|
||||||
|
write!(f, "{type_name}::{variant}(")?;
|
||||||
|
|
||||||
|
for value in values {
|
||||||
|
write!(f, "{value}")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
} else {
|
||||||
|
write!(f, "{type_name}::{variant}")
|
||||||
|
}
|
||||||
|
}
|
||||||
ValueInner::Float(float) => write!(f, "{float}"),
|
ValueInner::Float(float) => write!(f, "{float}"),
|
||||||
ValueInner::Integer(integer) => write!(f, "{integer}"),
|
ValueInner::Integer(integer) => write!(f, "{integer}"),
|
||||||
ValueInner::List(list) => {
|
ValueInner::List(list) => {
|
||||||
@ -195,6 +224,19 @@ impl Serialize for Value {
|
|||||||
{
|
{
|
||||||
match self.0.as_ref() {
|
match self.0.as_ref() {
|
||||||
ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean),
|
ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean),
|
||||||
|
ValueInner::EnumInstance {
|
||||||
|
type_name,
|
||||||
|
variant,
|
||||||
|
content,
|
||||||
|
} => {
|
||||||
|
let mut struct_ser = serializer.serialize_struct("EnumInstance", 3)?;
|
||||||
|
|
||||||
|
struct_ser.serialize_field("type_name", type_name)?;
|
||||||
|
struct_ser.serialize_field("variant", variant)?;
|
||||||
|
struct_ser.serialize_field("content", content)?;
|
||||||
|
|
||||||
|
struct_ser.end()
|
||||||
|
}
|
||||||
ValueInner::Float(float) => serializer.serialize_f64(*float),
|
ValueInner::Float(float) => serializer.serialize_f64(*float),
|
||||||
ValueInner::Function(Function {
|
ValueInner::Function(Function {
|
||||||
type_parameters,
|
type_parameters,
|
||||||
@ -496,6 +538,11 @@ impl<'de> Deserialize<'de> for Value {
|
|||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum ValueInner {
|
pub enum ValueInner {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
|
EnumInstance {
|
||||||
|
type_name: Identifier,
|
||||||
|
variant: Identifier,
|
||||||
|
content: Option<Vec<Value>>,
|
||||||
|
},
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
@ -513,6 +560,13 @@ impl ValueInner {
|
|||||||
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
|
pub fn r#type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
ValueInner::Boolean(_) => Type::Boolean,
|
ValueInner::Boolean(_) => Type::Boolean,
|
||||||
|
ValueInner::EnumInstance { type_name, .. } => {
|
||||||
|
if let Some(r#type) = context.get_type(type_name)? {
|
||||||
|
r#type
|
||||||
|
} else {
|
||||||
|
return Err(ValidationError::EnumDefinitionNotFound(type_name.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
ValueInner::Float(_) => Type::Float,
|
ValueInner::Float(_) => Type::Float,
|
||||||
ValueInner::Integer(_) => Type::Integer,
|
ValueInner::Integer(_) => Type::Integer,
|
||||||
ValueInner::List(values) => {
|
ValueInner::List(values) => {
|
||||||
@ -591,6 +645,33 @@ 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,
|
||||||
|
(
|
||||||
|
EnumInstance {
|
||||||
|
type_name: left_name,
|
||||||
|
variant: left_variant,
|
||||||
|
content: left_content,
|
||||||
|
},
|
||||||
|
EnumInstance {
|
||||||
|
type_name: right_name,
|
||||||
|
variant: right_variant,
|
||||||
|
content: right_content,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let name_cmp = left_name.cmp(right_name);
|
||||||
|
|
||||||
|
if name_cmp.is_eq() {
|
||||||
|
let variant_cmp = left_variant.cmp(right_variant);
|
||||||
|
|
||||||
|
if variant_cmp.is_eq() {
|
||||||
|
left_content.cmp(right_content)
|
||||||
|
} else {
|
||||||
|
variant_cmp
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
name_cmp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(EnumInstance { .. }, _) => Ordering::Greater,
|
||||||
(Function(left), Function(right)) => left.cmp(right),
|
(Function(left), Function(right)) => left.cmp(right),
|
||||||
(Function(_), _) => Ordering::Greater,
|
(Function(_), _) => Ordering::Greater,
|
||||||
(
|
(
|
||||||
|
23
dust-lang/tests/enums.rs
Normal file
23
dust-lang/tests/enums.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use dust_lang::{identifier::Identifier, *};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_enum() {
|
||||||
|
assert_eq!(
|
||||||
|
interpret(
|
||||||
|
"test",
|
||||||
|
"
|
||||||
|
type FooBar = enum {
|
||||||
|
Foo,
|
||||||
|
Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
FooBar::Foo
|
||||||
|
"
|
||||||
|
),
|
||||||
|
Ok(Some(Value::enum_instance(
|
||||||
|
Identifier::new("FooBar"),
|
||||||
|
Identifier::new("Foo"),
|
||||||
|
None
|
||||||
|
)))
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user