Begin implementing type arguments
This commit is contained in:
parent
a0a9bc2fdf
commit
6b0bb0016f
@ -161,7 +161,7 @@ impl AbstractNode for Assignment {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{Expression, ValueNode},
|
||||
abstract_tree::{Expression, ValueNode, WithPos},
|
||||
error::TypeConflict,
|
||||
};
|
||||
|
||||
|
@ -51,7 +51,7 @@ impl AbstractNode for Block {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{Expression, ValueNode},
|
||||
abstract_tree::{Expression, ValueNode, WithPos},
|
||||
Value,
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
value::ValueInner,
|
||||
value::{Function, ParsedFunction, ValueInner},
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Expression, Type, WithPosition};
|
||||
@ -32,7 +32,7 @@ impl AbstractNode for FunctionCall {
|
||||
let function_node_type = self.function.node.expected_type(_context)?;
|
||||
|
||||
if let Type::Function { return_type, .. } = function_node_type {
|
||||
Ok(*return_type)
|
||||
Ok(return_type.node)
|
||||
} else {
|
||||
Err(ValidationError::ExpectedFunction {
|
||||
actual: function_node_type,
|
||||
@ -41,14 +41,31 @@ impl AbstractNode for FunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||
for expression in &self.arguments {
|
||||
expression.node.validate(_context)?;
|
||||
expression.node.validate(context)?;
|
||||
}
|
||||
|
||||
let function_node_type = self.function.node.expected_type(_context)?;
|
||||
let function_node_type = self.function.node.expected_type(context)?;
|
||||
|
||||
if let Type::Function {
|
||||
parameter_types,
|
||||
return_type: _,
|
||||
} = function_node_type
|
||||
{
|
||||
for (type_parameter, type_argument) in
|
||||
parameter_types.iter().zip(self.type_arguments.iter())
|
||||
{
|
||||
type_parameter
|
||||
.node
|
||||
.check(&type_argument.node)
|
||||
.map_err(|conflict| ValidationError::TypeCheck {
|
||||
conflict,
|
||||
actual_position: type_argument.position,
|
||||
expected_position: type_parameter.position,
|
||||
})?;
|
||||
}
|
||||
|
||||
if let Type::Function { .. } = function_node_type {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ValidationError::ExpectedFunction {
|
||||
@ -94,6 +111,21 @@ impl AbstractNode for FunctionCall {
|
||||
|
||||
let function_context = Context::new();
|
||||
|
||||
if let Function::Parsed(ParsedFunction {
|
||||
type_parameters, ..
|
||||
}) = function
|
||||
{
|
||||
for (type_parameter, type_argument) in type_parameters
|
||||
.iter()
|
||||
.map(|r#type| r#type.node.clone())
|
||||
.zip(self.type_arguments.into_iter().map(|r#type| r#type.node))
|
||||
{
|
||||
if let Type::Argument(identifier) = type_parameter {
|
||||
function_context.set_type(identifier, type_argument)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function_context.inherit_data_from(&context)?;
|
||||
function.clone().call(arguments, function_context)
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ impl AbstractNode for IfElse {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{Statement, ValueNode},
|
||||
abstract_tree::{Statement, ValueNode, WithPos},
|
||||
Value,
|
||||
};
|
||||
|
||||
|
@ -90,7 +90,7 @@ impl AbstractNode for ListIndex {
|
||||
let found_item = list.get(index as usize);
|
||||
|
||||
if let Some(item) = found_item {
|
||||
Ok(Action::Return(item.clone()))
|
||||
Ok(Action::Return(item.node.clone()))
|
||||
} else {
|
||||
Ok(Action::None)
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ impl AbstractNode for Logic {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::abstract_tree::ValueNode;
|
||||
use crate::abstract_tree::{ValueNode, WithPos};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -70,7 +70,8 @@ impl Ord for Loop {
|
||||
mod tests {
|
||||
use crate::{
|
||||
abstract_tree::{
|
||||
Assignment, AssignmentOperator, Block, Expression, Identifier, IfElse, Logic, ValueNode,
|
||||
Assignment, AssignmentOperator, Block, Expression, Identifier, IfElse, Logic,
|
||||
ValueNode, WithPos,
|
||||
},
|
||||
Value,
|
||||
};
|
||||
@ -99,19 +100,19 @@ mod tests {
|
||||
.with_position((0, 0)),
|
||||
Statement::Loop(Loop::new(vec![Statement::IfElse(IfElse::new(
|
||||
Expression::Logic(Box::new(Logic::Greater(
|
||||
Expression::Identifier(Identifier::new("i")).with_position((10, 11)),
|
||||
Expression::Value(ValueNode::Integer(2)).with_position((14, 15)),
|
||||
Expression::Identifier(Identifier::new("i")).with_position((0, 0)),
|
||||
Expression::Value(ValueNode::Integer(2)).with_position((0, 0)),
|
||||
)))
|
||||
.with_position((10, 15)),
|
||||
Block::new(vec![Statement::Break.with_position((18, 24))]),
|
||||
.with_position((0, 0)),
|
||||
Block::new(vec![Statement::Break.with_position((0, 0))]),
|
||||
Some(Block::new(vec![Statement::Assignment(Assignment::new(
|
||||
Identifier::new("i").with_position((0, 0)),
|
||||
None,
|
||||
AssignmentOperator::AddAssign,
|
||||
Statement::Expression(Expression::Value(ValueNode::Integer(1)))
|
||||
.with_position((38, 39)),
|
||||
.with_position((0, 0)),
|
||||
))
|
||||
.with_position((33, 39))])),
|
||||
.with_position((0, 0))])),
|
||||
))
|
||||
.with_position((0, 0))]))
|
||||
.with_position((0, 0)),
|
||||
|
@ -52,6 +52,17 @@ pub struct WithPosition<T> {
|
||||
pub position: SourcePosition,
|
||||
}
|
||||
|
||||
pub trait WithPos: Sized {
|
||||
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
|
||||
WithPosition {
|
||||
node: self,
|
||||
position: span.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> WithPos for T {}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct SourcePosition(pub usize, pub usize);
|
||||
|
||||
@ -164,11 +175,4 @@ pub trait AbstractNode: Sized {
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError>;
|
||||
fn validate(&self, context: &Context) -> Result<(), ValidationError>;
|
||||
fn run(self, context: &Context) -> Result<Action, RuntimeError>;
|
||||
|
||||
fn with_position<T: Into<SourcePosition>>(self, span: T) -> WithPosition<Self> {
|
||||
WithPosition {
|
||||
node: self,
|
||||
position: span.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,13 @@ pub enum Type {
|
||||
Boolean,
|
||||
Float,
|
||||
Function {
|
||||
parameter_types: Vec<Type>,
|
||||
return_type: Box<Type>,
|
||||
parameter_types: Vec<WithPosition<Type>>,
|
||||
return_type: Box<WithPosition<Type>>,
|
||||
},
|
||||
Integer,
|
||||
List,
|
||||
ListOf(Box<Type>),
|
||||
ListExact(Vec<Type>),
|
||||
ListOf(Box<WithPosition<Type>>),
|
||||
ListExact(Vec<WithPosition<Type>>),
|
||||
Map,
|
||||
None,
|
||||
Range,
|
||||
@ -52,27 +52,27 @@ impl Type {
|
||||
| (Type::Range, Type::Range)
|
||||
| (Type::String, Type::String) => return Ok(()),
|
||||
(Type::ListOf(left), Type::ListOf(right)) => {
|
||||
if let Ok(()) = left.check(right) {
|
||||
if let Ok(()) = left.node.check(&right.node) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
(Type::ListOf(list_of), Type::ListExact(list_exact)) => {
|
||||
for r#type in list_exact {
|
||||
list_of.check(r#type)?;
|
||||
list_of.node.check(&r#type.node)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(Type::ListExact(list_exact), Type::ListOf(list_of)) => {
|
||||
for r#type in list_exact {
|
||||
r#type.check(&list_of)?;
|
||||
r#type.node.check(&list_of.node)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(Type::ListExact(left), Type::ListExact(right)) => {
|
||||
for (left, right) in left.iter().zip(right.iter()) {
|
||||
left.check(right)?;
|
||||
left.node.check(&right.node)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
@ -149,15 +149,15 @@ impl Display for Type {
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List => write!(f, "list"),
|
||||
Type::ListOf(item_type) => write!(f, "list({item_type})"),
|
||||
Type::ListOf(item_type) => write!(f, "list({})", item_type.node),
|
||||
Type::ListExact(item_types) => {
|
||||
write!(f, "[")?;
|
||||
|
||||
for (index, item_type) in item_types.into_iter().enumerate() {
|
||||
if index == item_types.len() - 1 {
|
||||
write!(f, "{item_type}")?;
|
||||
write!(f, "{}", item_type.node)?;
|
||||
} else {
|
||||
write!(f, "{item_type}, ")?;
|
||||
write!(f, "{}, ", item_type.node)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,10 +174,10 @@ impl Display for Type {
|
||||
write!(f, "(")?;
|
||||
|
||||
for r#type in parameter_types {
|
||||
write!(f, "{} ", r#type)?;
|
||||
write!(f, "{} ", r#type.node)?;
|
||||
}
|
||||
|
||||
write!(f, ") : {return_type}")
|
||||
write!(f, ") : {}", return_type.node)
|
||||
}
|
||||
Type::Structure { name, .. } => write!(f, "{name}"),
|
||||
Type::Argument(_) => todo!(),
|
||||
@ -187,6 +187,8 @@ impl Display for Type {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::abstract_tree::WithPos;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
@ -197,12 +199,14 @@ mod tests {
|
||||
assert_eq!(Type::Integer.check(&Type::Integer), Ok(()));
|
||||
assert_eq!(Type::List.check(&Type::List), Ok(()));
|
||||
assert_eq!(
|
||||
Type::ListOf(Box::new(Type::Integer)).check(&Type::ListOf(Box::new(Type::Integer))),
|
||||
Type::ListOf(Box::new(Type::Integer.with_position((0, 0))))
|
||||
.check(&Type::ListOf(Box::new(Type::Integer.with_position((0, 0))))),
|
||||
Ok(())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Type::ListExact(vec![Type::Float]).check(&Type::ListExact(vec![Type::Float])),
|
||||
Type::ListExact(vec![Type::Float.with_position((0, 0))])
|
||||
.check(&Type::ListExact(vec![Type::Float.with_position((0, 0))])),
|
||||
Ok(())
|
||||
);
|
||||
assert_eq!(Type::Map.check(&Type::Map), Ok(()));
|
||||
@ -237,8 +241,8 @@ mod tests {
|
||||
Type::Float,
|
||||
Type::Integer,
|
||||
Type::List,
|
||||
Type::ListOf(Box::new(Type::Boolean)),
|
||||
Type::ListExact(vec![Type::Integer]),
|
||||
Type::ListOf(Box::new(Type::Boolean.with_position((0, 0)))),
|
||||
Type::ListExact(vec![Type::Integer.with_position((0, 0))]),
|
||||
Type::Map,
|
||||
Type::None,
|
||||
Type::Range,
|
||||
@ -263,8 +267,11 @@ mod tests {
|
||||
#[test]
|
||||
fn check_list_types() {
|
||||
let list = Type::List;
|
||||
let list_exact = Type::ListExact(vec![Type::Integer, Type::Integer]);
|
||||
let list_of = Type::ListOf(Box::new(Type::Integer));
|
||||
let list_exact = Type::ListExact(vec![
|
||||
Type::Integer.with_position((0, 0)),
|
||||
Type::Integer.with_position((0, 0)),
|
||||
]);
|
||||
let list_of = Type::ListOf(Box::new(Type::Integer.with_position((0, 0))));
|
||||
|
||||
assert_eq!(list.check(&list_exact), Ok(()));
|
||||
assert_eq!(list.check(&list_of), Ok(()));
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
Value,
|
||||
};
|
||||
|
||||
use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPosition};
|
||||
use super::{AbstractNode, Action, Block, Expression, Identifier, Type, WithPos, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ValueNode {
|
||||
@ -47,7 +47,12 @@ impl AbstractNode for ValueNode {
|
||||
let mut item_types = Vec::with_capacity(items.len());
|
||||
|
||||
for expression in items {
|
||||
item_types.push(expression.node.expected_type(context)?);
|
||||
item_types.push(
|
||||
expression
|
||||
.node
|
||||
.expected_type(context)?
|
||||
.with_position(expression.position),
|
||||
);
|
||||
}
|
||||
|
||||
Type::ListExact(item_types)
|
||||
@ -61,10 +66,10 @@ impl AbstractNode for ValueNode {
|
||||
..
|
||||
} => Type::Function {
|
||||
parameter_types: parameters
|
||||
.into_iter()
|
||||
.map(|(_, r#type)| r#type.node.clone())
|
||||
.iter()
|
||||
.map(|(_, r#type)| r#type.clone())
|
||||
.collect(),
|
||||
return_type: Box::new(return_type.node.clone()),
|
||||
return_type: Box::new(return_type.clone()),
|
||||
},
|
||||
ValueNode::Structure {
|
||||
name,
|
||||
@ -185,7 +190,10 @@ impl AbstractNode for ValueNode {
|
||||
for expression in expression_list {
|
||||
let action = expression.node.run(_context)?;
|
||||
let value = if let Action::Return(value) = action {
|
||||
value
|
||||
WithPosition {
|
||||
node: value,
|
||||
position: expression.position,
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::InterpreterExpectedReturn(expression.position),
|
||||
|
@ -74,7 +74,7 @@ impl AbstractNode for While {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::abstract_tree::{
|
||||
Assignment, AssignmentOperator, Block, Identifier, Logic, ValueNode,
|
||||
Assignment, AssignmentOperator, Block, Identifier, Logic, ValueNode, WithPos,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
@ -6,7 +6,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{Action, Type},
|
||||
abstract_tree::{Action, Type, WithPos},
|
||||
context::Context,
|
||||
error::RuntimeError,
|
||||
value::ValueInner,
|
||||
@ -36,8 +36,8 @@ impl BuiltInFunction {
|
||||
pub fn r#type(&self) -> Type {
|
||||
match self {
|
||||
BuiltInFunction::WriteLine => Type::Function {
|
||||
parameter_types: vec![Type::String],
|
||||
return_type: Box::new(Type::None),
|
||||
parameter_types: vec![Type::String.with_position((0, 0))],
|
||||
return_type: Box::new(Type::None.with_position((0, 0))),
|
||||
},
|
||||
_ => {
|
||||
todo!()
|
||||
|
@ -121,8 +121,8 @@ pub fn parser<'src>() -> impl Parser<
|
||||
}
|
||||
}),
|
||||
))
|
||||
})
|
||||
.map_with(|r#type, state| r#type.with_position(state.span()));
|
||||
.map_with(|r#type, state| r#type.with_position(state.span()))
|
||||
});
|
||||
|
||||
let type_argument = identifier
|
||||
.clone()
|
||||
@ -759,7 +759,10 @@ mod tests {
|
||||
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0].node,
|
||||
Statement::Assignment(Assignment::new(
|
||||
Identifier::new("foobar").with_position((0, 6)),
|
||||
Some(Type::ListOf(Box::new(Type::Boolean)).with_position((9, 19))),
|
||||
Some(
|
||||
Type::ListOf(Box::new(Type::Boolean.with_position((14, 18))))
|
||||
.with_position((9, 19))
|
||||
),
|
||||
AssignmentOperator::Assign,
|
||||
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value(
|
||||
ValueNode::Boolean(true)
|
||||
@ -776,7 +779,13 @@ mod tests {
|
||||
parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0],
|
||||
Statement::Assignment(Assignment::new(
|
||||
Identifier::new("foobar").with_position((0, 6)),
|
||||
Some(Type::ListExact(vec![Type::Boolean, Type::String]).with_position((9, 20))),
|
||||
Some(
|
||||
Type::ListExact(vec![
|
||||
Type::Boolean.with_position((10, 14)),
|
||||
Type::String.with_position((16, 19))
|
||||
])
|
||||
.with_position((9, 20))
|
||||
),
|
||||
AssignmentOperator::Assign,
|
||||
Statement::Expression(Expression::Value(ValueNode::List(vec![
|
||||
Expression::Value(ValueNode::Boolean(true)).with_position((24, 28)),
|
||||
@ -797,7 +806,7 @@ mod tests {
|
||||
Some(
|
||||
Type::Function {
|
||||
parameter_types: vec![],
|
||||
return_type: Box::new(Type::Any)
|
||||
return_type: Box::new(Type::Any.with_position((17, 20)))
|
||||
}
|
||||
.with_position((9, 20))
|
||||
),
|
||||
|
@ -13,7 +13,7 @@ use stanza::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPosition},
|
||||
abstract_tree::{AbstractNode, Action, Block, Identifier, Type, WithPos, WithPosition},
|
||||
built_in_functions::BuiltInFunction,
|
||||
context::Context,
|
||||
error::{RuntimeError, ValidationError},
|
||||
@ -39,7 +39,7 @@ impl Value {
|
||||
Value(Arc::new(ValueInner::Integer(integer)))
|
||||
}
|
||||
|
||||
pub fn list(list: Vec<Value>) -> Self {
|
||||
pub fn list(list: Vec<WithPosition<Value>>) -> Self {
|
||||
Value(Arc::new(ValueInner::List(list)))
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ impl Value {
|
||||
) -> Self {
|
||||
Value(Arc::new(ValueInner::Function(Function::Parsed(
|
||||
ParsedFunction {
|
||||
type_arguments,
|
||||
type_parameters: type_arguments,
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
@ -91,7 +91,7 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_list(&self) -> Option<&Vec<Value>> {
|
||||
pub fn as_list(&self) -> Option<&Vec<WithPosition<Value>>> {
|
||||
if let ValueInner::List(list) = self.inner().as_ref() {
|
||||
Some(list)
|
||||
} else {
|
||||
@ -122,7 +122,7 @@ impl Display for Value {
|
||||
let mut table = create_table();
|
||||
|
||||
for value in list {
|
||||
table = table.with_row([value.to_string()]);
|
||||
table = table.with_row([value.node.to_string()]);
|
||||
}
|
||||
|
||||
write!(f, "{}", Console::default().render(&table))
|
||||
@ -139,7 +139,7 @@ impl Display for Value {
|
||||
ValueInner::Range(_) => todo!(),
|
||||
ValueInner::String(string) => write!(f, "{string}"),
|
||||
ValueInner::Function(Function::Parsed(ParsedFunction {
|
||||
type_arguments,
|
||||
type_parameters: type_arguments,
|
||||
parameters,
|
||||
return_type,
|
||||
body,
|
||||
@ -202,7 +202,7 @@ pub enum ValueInner {
|
||||
Float(f64),
|
||||
Function(Function),
|
||||
Integer(i64),
|
||||
List(Vec<Value>),
|
||||
List(Vec<WithPosition<Value>>),
|
||||
Map(BTreeMap<Identifier, Value>),
|
||||
Range(Range<i64>),
|
||||
String(String),
|
||||
@ -222,7 +222,7 @@ impl ValueInner {
|
||||
let mut types = Vec::with_capacity(values.len());
|
||||
|
||||
for value in values {
|
||||
types.push(value.r#type(context)?);
|
||||
types.push(value.node.r#type(context)?.with_position(value.position));
|
||||
}
|
||||
|
||||
Type::ListExact(types)
|
||||
@ -235,9 +235,9 @@ impl ValueInner {
|
||||
parameter_types: parsed_function
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|(_, r#type)| r#type.node.clone())
|
||||
.map(|(_, r#type)| r#type.clone())
|
||||
.collect(),
|
||||
return_type: Box::new(parsed_function.return_type.node.clone()),
|
||||
return_type: Box::new(parsed_function.return_type.clone()),
|
||||
},
|
||||
Function::BuiltIn(built_in_function) => {
|
||||
built_in_function.clone().as_value().r#type(context)?
|
||||
@ -343,8 +343,8 @@ impl Function {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct ParsedFunction {
|
||||
type_arguments: Vec<WithPosition<Type>>,
|
||||
parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
return_type: WithPosition<Type>,
|
||||
body: WithPosition<Block>,
|
||||
pub type_parameters: Vec<WithPosition<Type>>,
|
||||
pub parameters: Vec<(Identifier, WithPosition<Type>)>,
|
||||
pub return_type: WithPosition<Type>,
|
||||
pub body: WithPosition<Block>,
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::{collections::BTreeMap, rc::Rc};
|
||||
|
||||
use dust_lang::{
|
||||
abstract_tree::{Identifier, Type},
|
||||
abstract_tree::{Identifier, Type, WithPos},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
*,
|
||||
};
|
||||
@ -100,9 +100,9 @@ fn list() {
|
||||
assert_eq!(
|
||||
interpret(Rc::new("test".to_string()), "[1, 2, 'foobar']"),
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(1),
|
||||
Value::integer(2),
|
||||
Value::string("foobar".to_string()),
|
||||
Value::integer(1).with_position((1, 2)),
|
||||
Value::integer(2).with_position((4, 5)),
|
||||
Value::string("foobar".to_string()).with_position((7, 15)),
|
||||
])))
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use dust_lang::{
|
||||
abstract_tree::{AbstractNode, Block, Expression, Identifier, Statement, Type},
|
||||
abstract_tree::{Block, Expression, Identifier, Statement, Type, WithPos},
|
||||
error::{Error, TypeConflict, ValidationError},
|
||||
*,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user