Add type argument syntax
This commit is contained in:
parent
a5f3127bcf
commit
0805b96809
@ -37,9 +37,9 @@ impl AbstractTree for As {
|
||||
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||
let initial_type = self.expression.expected_type(context)?;
|
||||
|
||||
if let Type::List(item_type) = &self.r#type {
|
||||
if let Type::ListOf(item_type) = &self.r#type {
|
||||
match &initial_type {
|
||||
Type::List(expected_item_type) => {
|
||||
Type::ListOf(expected_item_type) => {
|
||||
if !item_type.accepts(&expected_item_type) {
|
||||
return Err(ValidationError::TypeCheck {
|
||||
expected: self.r#type.clone(),
|
||||
@ -77,7 +77,7 @@ impl AbstractTree for As {
|
||||
|
||||
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
let value = self.expression.run(source, context)?;
|
||||
let converted_value = if let Type::List(_) = self.r#type {
|
||||
let converted_value = if let Type::ListOf(_) = self.r#type {
|
||||
match value {
|
||||
Value::List(list) => Value::List(list),
|
||||
Value::String(string) => {
|
||||
|
@ -78,7 +78,7 @@ impl AbstractTree for Assignment {
|
||||
}
|
||||
}
|
||||
AssignmentOperator::PlusEqual => {
|
||||
if let Type::List(expected) = type_specification.inner() {
|
||||
if let Type::ListOf(expected) = type_specification.inner() {
|
||||
let actual = self.identifier.expected_type(context)?;
|
||||
|
||||
if !expected.accepts(&actual) {
|
||||
@ -107,7 +107,7 @@ impl AbstractTree for Assignment {
|
||||
match self.operator {
|
||||
AssignmentOperator::Equal => {}
|
||||
AssignmentOperator::PlusEqual => {
|
||||
if let Type::List(expected) = self.identifier.expected_type(context)? {
|
||||
if let Type::ListOf(expected) = self.identifier.expected_type(context)? {
|
||||
let actual = self.statement.expected_type(context)?;
|
||||
|
||||
if !expected.accepts(&actual) {
|
||||
|
@ -9,11 +9,11 @@ use crate::{
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct EnumDefinition {
|
||||
identifier: Identifier,
|
||||
variants: Vec<(Identifier, Option<Type>)>,
|
||||
variants: Vec<(Identifier, Vec<Type>)>,
|
||||
}
|
||||
|
||||
impl EnumDefinition {
|
||||
pub fn new(identifier: Identifier, variants: Vec<(Identifier, Option<Type>)>) -> Self {
|
||||
pub fn new(identifier: Identifier, variants: Vec<(Identifier, Vec<Type>)>) -> Self {
|
||||
Self {
|
||||
identifier,
|
||||
variants,
|
||||
@ -27,6 +27,10 @@ impl EnumDefinition {
|
||||
pub fn identifier(&self) -> &Identifier {
|
||||
&self.identifier
|
||||
}
|
||||
|
||||
pub fn variants(&self) -> &Vec<(Identifier, Vec<Type>)> {
|
||||
&self.variants
|
||||
}
|
||||
}
|
||||
|
||||
impl AbstractTree for EnumDefinition {
|
||||
@ -37,21 +41,25 @@ impl AbstractTree for EnumDefinition {
|
||||
let identifier = Identifier::from_syntax(identifier_node, source, context)?;
|
||||
|
||||
let mut variants = Vec::new();
|
||||
let mut current_identifier = None;
|
||||
let mut current_identifier: Option<Identifier> = None;
|
||||
let mut types = Vec::new();
|
||||
|
||||
for index in 3..node.child_count() - 1 {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.kind() == "identifier" {
|
||||
if let Some(identifier) = ¤t_identifier {
|
||||
variants.push((identifier.clone(), types));
|
||||
}
|
||||
|
||||
current_identifier = Some(Identifier::from_syntax(child, source, context)?);
|
||||
types = Vec::new();
|
||||
}
|
||||
|
||||
if let Some(identifier) = ¤t_identifier {
|
||||
if child.kind() == "type" {
|
||||
let r#type = Type::from_syntax(child, source, context)?;
|
||||
if child.kind() == "type" {
|
||||
let r#type = Type::from_syntax(child, source, context)?;
|
||||
|
||||
variants.push((identifier.clone(), Some(r#type)));
|
||||
}
|
||||
types.push(r#type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,13 +73,14 @@ impl AbstractTree for EnumDefinition {
|
||||
Ok(Type::None)
|
||||
}
|
||||
|
||||
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
|
||||
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
|
||||
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
|
||||
self.identifier.validate(_source, context)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
|
||||
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
|
||||
|
||||
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
|
||||
Ok(Value::none())
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ impl AbstractTree for For {
|
||||
self.collection.validate(_source, context)?;
|
||||
|
||||
let collection_type = self.collection.expected_type(context)?;
|
||||
let item_type = if let Type::List(item_type) = collection_type {
|
||||
let item_type = if let Type::ListOf(item_type) = collection_type {
|
||||
item_type.as_ref().clone()
|
||||
} else if let Type::Range = collection_type {
|
||||
Type::Integer
|
||||
|
@ -35,7 +35,7 @@ impl AbstractTree for Index {
|
||||
|
||||
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
|
||||
match self.collection.expected_type(context)? {
|
||||
Type::List(item_type) => Ok(*item_type.clone()),
|
||||
Type::ListOf(item_type) => Ok(*item_type.clone()),
|
||||
Type::Map(map_types_option) => {
|
||||
if let (Some(map_type), IndexExpression::Identifier(identifier)) =
|
||||
(map_types_option, &self.index)
|
||||
|
@ -19,7 +19,7 @@ pub enum Type {
|
||||
Collection,
|
||||
Custom {
|
||||
name: Identifier,
|
||||
argument: Option<Box<Type>>,
|
||||
arguments: Vec<Type>,
|
||||
},
|
||||
Float,
|
||||
Function {
|
||||
@ -27,20 +27,19 @@ pub enum Type {
|
||||
return_type: Box<Type>,
|
||||
},
|
||||
Integer,
|
||||
List(Box<Type>),
|
||||
List,
|
||||
ListOf(Box<Type>),
|
||||
ListExact(Vec<Type>),
|
||||
Map(Option<BTreeMap<Identifier, Type>>),
|
||||
None,
|
||||
Number,
|
||||
String,
|
||||
Range,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn custom(name: Identifier, argument: Option<Type>) -> Self {
|
||||
Type::Custom {
|
||||
name,
|
||||
argument: argument.map(|r#type| Box::new(r#type)),
|
||||
}
|
||||
pub fn custom(name: Identifier, arguments: Vec<Type>) -> Self {
|
||||
Type::Custom { name, arguments }
|
||||
}
|
||||
|
||||
pub fn option(inner_type: Option<Type>) -> Self {
|
||||
@ -48,7 +47,7 @@ impl Type {
|
||||
}
|
||||
|
||||
pub fn list(item_type: Type) -> Self {
|
||||
Type::List(Box::new(item_type))
|
||||
Type::ListOf(Box::new(item_type))
|
||||
}
|
||||
|
||||
pub fn function(parameter_types: Vec<Type>, return_type: Type) -> Self {
|
||||
@ -70,14 +69,15 @@ impl Type {
|
||||
| (_, Type::Any)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
| (Type::Collection, Type::Collection)
|
||||
| (Type::Collection, Type::List(_))
|
||||
| (Type::List(_), Type::Collection)
|
||||
| (Type::Collection, Type::ListOf(_))
|
||||
| (Type::ListOf(_), Type::Collection)
|
||||
| (Type::Collection, Type::Map(_))
|
||||
| (Type::Map(_), Type::Collection)
|
||||
| (Type::Collection, Type::String)
|
||||
| (Type::String, Type::Collection)
|
||||
| (Type::Float, Type::Float)
|
||||
| (Type::Integer, Type::Integer)
|
||||
| (Type::List, Type::List)
|
||||
| (Type::Map(None), Type::Map(None))
|
||||
| (Type::Number, Type::Number)
|
||||
| (Type::Number, Type::Integer)
|
||||
@ -90,22 +90,25 @@ impl Type {
|
||||
(
|
||||
Type::Custom {
|
||||
name: left_name,
|
||||
argument: left_argument,
|
||||
arguments: left_arguments,
|
||||
},
|
||||
Type::Custom {
|
||||
name: right_name,
|
||||
argument: right_argument,
|
||||
arguments: right_arguments,
|
||||
},
|
||||
) => {
|
||||
if left_name != right_name {
|
||||
false
|
||||
} else {
|
||||
left_argument == right_argument
|
||||
}
|
||||
}
|
||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
||||
) => left_name == right_name && left_arguments == right_arguments,
|
||||
(Type::ListOf(self_item_type), Type::ListOf(other_item_type)) => {
|
||||
self_item_type.accepts(&other_item_type)
|
||||
}
|
||||
(Type::ListExact(self_types), Type::ListExact(other_types)) => {
|
||||
for (left, right) in self_types.iter().zip(other_types.iter()) {
|
||||
if !left.accepts(right) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
(
|
||||
Type::Function {
|
||||
parameter_types: self_parameter_types,
|
||||
@ -137,7 +140,7 @@ impl Type {
|
||||
}
|
||||
|
||||
pub fn is_list(&self) -> bool {
|
||||
matches!(self, Type::List(_))
|
||||
matches!(self, Type::ListOf(_))
|
||||
}
|
||||
|
||||
pub fn is_map(&self) -> bool {
|
||||
@ -158,13 +161,19 @@ impl AbstractTree for Type {
|
||||
let r#type = match type_node.kind() {
|
||||
"identifier" => {
|
||||
let name = Identifier::from_syntax(type_node, _source, context)?;
|
||||
let argument = if let Some(child) = node.child(2) {
|
||||
Some(Type::from_syntax(child, _source, context)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut arguments = Vec::new();
|
||||
|
||||
Type::custom(name, argument)
|
||||
for index in 2..node.child_count() - 1 {
|
||||
let child = node.child(index).unwrap();
|
||||
|
||||
if child.is_named() {
|
||||
let r#type = Type::from_syntax(child, _source, context)?;
|
||||
|
||||
arguments.push(r#type);
|
||||
}
|
||||
}
|
||||
|
||||
Type::custom(name, arguments)
|
||||
}
|
||||
"{" => {
|
||||
let mut type_map = BTreeMap::new();
|
||||
@ -191,7 +200,7 @@ impl AbstractTree for Type {
|
||||
let item_type_node = node.child(1).unwrap();
|
||||
let item_type = Type::from_syntax(item_type_node, _source, context)?;
|
||||
|
||||
Type::List(Box::new(item_type))
|
||||
Type::ListOf(Box::new(item_type))
|
||||
}
|
||||
"any" => Type::Any,
|
||||
"bool" => Type::Boolean,
|
||||
@ -261,7 +270,7 @@ impl Format for Type {
|
||||
Type::Collection => output.push_str("collection"),
|
||||
Type::Custom {
|
||||
name: _,
|
||||
argument: _,
|
||||
arguments: _,
|
||||
} => todo!(),
|
||||
Type::Float => output.push_str("float"),
|
||||
Type::Function {
|
||||
@ -282,11 +291,13 @@ impl Format for Type {
|
||||
return_type.format(output, indent_level);
|
||||
}
|
||||
Type::Integer => output.push_str("int"),
|
||||
Type::List(item_type) => {
|
||||
Type::List => todo!(),
|
||||
Type::ListOf(item_type) => {
|
||||
output.push('[');
|
||||
item_type.format(output, indent_level);
|
||||
output.push(']');
|
||||
}
|
||||
Type::ListExact(_) => todo!(),
|
||||
Type::Map(_) => {
|
||||
output.push_str("map");
|
||||
}
|
||||
@ -304,9 +315,19 @@ impl Display for Type {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Collection => write!(f, "collection"),
|
||||
Type::Custom { name, argument } => {
|
||||
if let Some(argument) = argument {
|
||||
write!(f, "{name}<{argument}>")
|
||||
Type::Custom { name, arguments } => {
|
||||
if !arguments.is_empty() {
|
||||
write!(f, "<")?;
|
||||
|
||||
for (index, r#type) in arguments.into_iter().enumerate() {
|
||||
if index == arguments.len() - 1 {
|
||||
write!(f, "{}", r#type)?;
|
||||
} else {
|
||||
write!(f, "{}, ", r#type)?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, ">")
|
||||
} else {
|
||||
write!(f, "{name}")
|
||||
}
|
||||
@ -330,7 +351,21 @@ impl Display for Type {
|
||||
write!(f, " -> {return_type}")
|
||||
}
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List(item_type) => write!(f, "[{item_type}]"),
|
||||
Type::List => write!(f, "list"),
|
||||
Type::ListOf(item_type) => write!(f, "[{item_type}]"),
|
||||
Type::ListExact(types) => {
|
||||
write!(f, "[")?;
|
||||
|
||||
for (index, r#type) in types.into_iter().enumerate() {
|
||||
if index == types.len() - 1 {
|
||||
write!(f, "{}", r#type)?;
|
||||
} else {
|
||||
write!(f, "{}, ", r#type)?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
}
|
||||
Type::Map(_) => write!(f, "map"),
|
||||
Type::Number => write!(f, "num"),
|
||||
Type::None => write!(f, "none"),
|
||||
|
@ -124,43 +124,47 @@ impl AbstractTree for ValueNode {
|
||||
ValueNode::Integer(_) => Type::Integer,
|
||||
ValueNode::String(_) => Type::String,
|
||||
ValueNode::List(expressions) => {
|
||||
let mut previous_type = None;
|
||||
let mut item_types = Vec::new();
|
||||
|
||||
for expression in expressions {
|
||||
let expression_type = expression.expected_type(context)?;
|
||||
|
||||
if let Some(previous) = previous_type {
|
||||
if expression_type != previous {
|
||||
return Ok(Type::List(Box::new(Type::Any)));
|
||||
}
|
||||
}
|
||||
|
||||
previous_type = Some(expression_type);
|
||||
item_types.push(expression_type);
|
||||
}
|
||||
|
||||
if let Some(previous) = previous_type {
|
||||
Type::List(Box::new(previous))
|
||||
} else {
|
||||
Type::List(Box::new(Type::Any))
|
||||
}
|
||||
Type::ListExact(item_types)
|
||||
}
|
||||
ValueNode::Map(map_node) => map_node.expected_type(context)?,
|
||||
ValueNode::Struct { name, .. } => {
|
||||
Type::Custom { name: name.clone(), argument: None }
|
||||
Type::custom(name.clone(), Vec::with_capacity(0))
|
||||
}
|
||||
ValueNode::Range(_) => Type::Range,
|
||||
ValueNode::Enum { name, variant: _, expression } => {
|
||||
if let Some(expression) = expression {
|
||||
Type::Custom {
|
||||
name: name.clone(),
|
||||
argument: Some(Box::new(expression.expected_type(context)?))
|
||||
ValueNode::Enum { name, variant, expression: _ } => {
|
||||
let types: Vec<Type> = if let Some(type_definition) = context.get_definition(name)? {
|
||||
if let TypeDefinition::Enum(enum_definition) = type_definition {
|
||||
let types = enum_definition.variants().into_iter().find_map(|(identifier, types)| {
|
||||
if identifier == variant {
|
||||
Some(types.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(types) = types {
|
||||
types
|
||||
} else {
|
||||
return Err(ValidationError::VariableIdentifierNotFound(variant.clone()));
|
||||
}
|
||||
|
||||
} else {
|
||||
return Err(ValidationError::ExpectedEnumDefintion { actual: type_definition.clone() });
|
||||
}
|
||||
} else {
|
||||
Type::Custom{
|
||||
name: name.clone(),
|
||||
argument: None,
|
||||
}
|
||||
}
|
||||
return Err(ValidationError::VariableIdentifierNotFound(name.clone()));
|
||||
};
|
||||
|
||||
Type::custom(name.clone(), types.clone())
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -73,13 +73,7 @@ impl Callable for BuiltInFunction {
|
||||
|
||||
fn r#type(&self) -> Type {
|
||||
match self {
|
||||
BuiltInFunction::AssertEqual => Type::function(
|
||||
vec![Type::Any, Type::Any],
|
||||
Type::Custom {
|
||||
name: Identifier::new("Result"),
|
||||
argument: None,
|
||||
},
|
||||
),
|
||||
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
|
||||
BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
|
||||
BuiltInFunction::Json(json_function) => json_function.r#type(),
|
||||
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
|
||||
|
@ -33,8 +33,8 @@ impl BuiltInTypeDefinition {
|
||||
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||
Identifier::new(self.name()),
|
||||
vec![
|
||||
(Identifier::new("Some"), Some(Type::Any)),
|
||||
(Identifier::new("None"), None),
|
||||
(Identifier::new("Some"), vec![Type::Any]),
|
||||
(Identifier::new("None"), Vec::with_capacity(0)),
|
||||
],
|
||||
));
|
||||
|
||||
@ -44,8 +44,8 @@ impl BuiltInTypeDefinition {
|
||||
let definition = TypeDefinition::Enum(EnumDefinition::new(
|
||||
Identifier::new(self.name()),
|
||||
vec![
|
||||
(Identifier::new("Ok"), Some(Type::Any)),
|
||||
(Identifier::new("Err"), Some(Type::Any)),
|
||||
(Identifier::new("Ok"), vec![Type::Any]),
|
||||
(Identifier::new("Error"), vec![Type::Any]),
|
||||
],
|
||||
));
|
||||
|
||||
|
@ -19,15 +19,9 @@ impl BuiltInType {
|
||||
match self {
|
||||
BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
|
||||
if let Some(content_type) = content_type {
|
||||
Type::Custom {
|
||||
name: Identifier::new("Option"),
|
||||
argument: Some(Box::new(content_type.clone())),
|
||||
}
|
||||
Type::custom(Identifier::new("Option"), vec![content_type.clone()])
|
||||
} else {
|
||||
Type::Custom {
|
||||
name: Identifier::new("Option"),
|
||||
argument: None,
|
||||
}
|
||||
Type::custom(Identifier::new("Option"), Vec::with_capacity(0))
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ impl Context {
|
||||
let old_data = map.remove(&key);
|
||||
|
||||
if let Some((_, old_counter)) = old_data {
|
||||
map.insert(key, (ValueData::Value(value), old_counter.clone()));
|
||||
map.insert(key, (ValueData::Value(value), old_counter));
|
||||
} else {
|
||||
map.insert(key, (ValueData::Value(value), UsageCounter::new()));
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use tree_sitter::LanguageError;
|
||||
|
||||
use std::fmt::{self, Formatter};
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Error {
|
||||
Syntax(SyntaxError),
|
||||
|
||||
@ -95,12 +95,6 @@ impl From<LanguageError> for Error {
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
use Error::*;
|
||||
|
@ -74,25 +74,15 @@ impl Value {
|
||||
pub fn r#type(&self) -> Result<Type, RwLockError> {
|
||||
let r#type = match self {
|
||||
Value::List(list) => {
|
||||
let mut previous_type = None;
|
||||
let mut item_types = Vec::new();
|
||||
|
||||
for value in list.items()?.iter() {
|
||||
let value_type = value.r#type();
|
||||
let r#type = value.r#type()?;
|
||||
|
||||
if let Some(previous) = &previous_type {
|
||||
if &value_type != previous {
|
||||
return Ok(Type::List(Box::new(Type::Any)));
|
||||
}
|
||||
}
|
||||
|
||||
previous_type = Some(value_type);
|
||||
item_types.push(r#type);
|
||||
}
|
||||
|
||||
if let Some(previous) = previous_type {
|
||||
Type::List(Box::new(previous?))
|
||||
} else {
|
||||
Type::List(Box::new(Type::Any))
|
||||
}
|
||||
Type::ListExact(item_types)
|
||||
}
|
||||
Value::Map(map) => {
|
||||
if map.inner().is_empty() {
|
||||
|
@ -24,7 +24,7 @@ fn string_as_list_error() {
|
||||
interpret("'foobar' as [float]"),
|
||||
Err(Error::Validation(ValidationError::ConversionImpossible {
|
||||
initial_type: Type::String,
|
||||
target_type: Type::List(Box::new(Type::Float))
|
||||
target_type: Type::ListOf(Box::new(Type::Float))
|
||||
}))
|
||||
)
|
||||
}
|
||||
@ -39,7 +39,7 @@ fn conversion_runtime_error() {
|
||||
interpret(&format!("json:parse('{JSON}') as [map]")),
|
||||
Err(Error::Runtime(RuntimeError::ConversionImpossible {
|
||||
from: json_value.r#type().unwrap(),
|
||||
to: Type::List(Box::new(Type::Map(None))),
|
||||
to: Type::ListOf(Box::new(Type::Map(None))),
|
||||
position: SourcePosition {
|
||||
start_byte: 0,
|
||||
end_byte: 33,
|
||||
|
@ -1,5 +1,26 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn override_built_ins() {
|
||||
assert_eq!(
|
||||
interpret(
|
||||
"
|
||||
enum Option {
|
||||
Some<str>
|
||||
None
|
||||
}
|
||||
|
||||
my_option <Option> = Option::Some('foo')
|
||||
"
|
||||
),
|
||||
Ok(Value::Enum(EnumInstance::new(
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("Some"),
|
||||
Some(Value::String("foo".to_string())),
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn option() {
|
||||
assert_eq!(
|
||||
@ -13,14 +34,12 @@ fn option() {
|
||||
assert_eq!(
|
||||
interpret(
|
||||
"
|
||||
opt <Option<int>> = Option::Some(1);
|
||||
|
||||
opt
|
||||
Option::Some(1)
|
||||
"
|
||||
),
|
||||
Ok(Value::Enum(EnumInstance::new(
|
||||
Identifier::new("Option"),
|
||||
Identifier::new("None"),
|
||||
Identifier::new("Some"),
|
||||
Some(Value::Integer(1)),
|
||||
)))
|
||||
);
|
||||
@ -39,8 +58,7 @@ fn result() {
|
||||
assert_eq!(
|
||||
interpret(
|
||||
"
|
||||
result <Result<int, str>> = Result::Error('uh-oh!')
|
||||
result
|
||||
Result::Error('uh-oh!')
|
||||
"
|
||||
),
|
||||
Ok(Value::Enum(EnumInstance::new(
|
||||
|
@ -1,4 +1,4 @@
|
||||
use dust_lang::*;
|
||||
use dust_lang::{error::RuntimeError, *};
|
||||
|
||||
#[test]
|
||||
fn args() {
|
||||
@ -23,10 +23,9 @@ fn assert_equal() {
|
||||
);
|
||||
assert_eq!(
|
||||
interpret("assert_equal(true, false)"),
|
||||
Ok(Value::Enum(EnumInstance::new(
|
||||
Identifier::new("Result"),
|
||||
Identifier::new("Error"),
|
||||
Some(Value::none()),
|
||||
)))
|
||||
Err(Error::Runtime(RuntimeError::AssertEqualFailed {
|
||||
left: true.into(),
|
||||
right: false.into()
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
@ -19,15 +19,12 @@ enum Foobar {
|
||||
(identifier))))))
|
||||
|
||||
================================================================================
|
||||
Nested Enum
|
||||
Enum with Arguments
|
||||
================================================================================
|
||||
|
||||
enum Foobar {
|
||||
Foo(str),
|
||||
Bar(enum BazBuff {
|
||||
Baz,
|
||||
Buff,
|
||||
})
|
||||
enum Foobar<T, U> {
|
||||
Foo<T>,
|
||||
Bar<U>,
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@ -38,15 +35,56 @@ enum Foobar {
|
||||
(type_definition
|
||||
(enum_definition
|
||||
(identifier)
|
||||
(type_arguments
|
||||
(type
|
||||
(identifier))
|
||||
(type
|
||||
(identifier)))
|
||||
(identifier)
|
||||
(type)
|
||||
(type_arguments
|
||||
(type
|
||||
(identifier)))
|
||||
(identifier)
|
||||
(type_definition
|
||||
(enum_definition
|
||||
(identifier)
|
||||
(identifier)
|
||||
(type_arguments
|
||||
(type
|
||||
(identifier))))))))
|
||||
|
||||
================================================================================
|
||||
Complex Enum
|
||||
================================================================================
|
||||
|
||||
enum Foobar<T> {
|
||||
Foo<Foo>,
|
||||
Bar<int, float>,
|
||||
Baz<Option<T>>
|
||||
}
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(statement_kind
|
||||
(type_definition
|
||||
(enum_definition
|
||||
(identifier)
|
||||
(type_arguments
|
||||
(type
|
||||
(identifier)))
|
||||
(identifier)
|
||||
(type_arguments
|
||||
(type
|
||||
(identifier)))
|
||||
(identifier)
|
||||
(type_arguments
|
||||
(type)
|
||||
(type))
|
||||
(identifier)
|
||||
(type_arguments
|
||||
(type
|
||||
(identifier)
|
||||
(type
|
||||
(identifier)))))))))
|
||||
|
||||
================================================================================
|
||||
Simple Enum Instance
|
||||
================================================================================
|
||||
|
@ -28,3 +28,69 @@ x <{ y <int> }> = { y = 2 }
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))))))))
|
||||
|
||||
================================================================================
|
||||
List Of
|
||||
================================================================================
|
||||
|
||||
x <list<str>> = ['foo', 'bar', 'baz']
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(statement_kind
|
||||
(assignment
|
||||
(identifier)
|
||||
(type_specification
|
||||
(type
|
||||
(type)))
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(statement_kind
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(string)))
|
||||
(expression
|
||||
(value
|
||||
(string))))))))))))
|
||||
|
||||
================================================================================
|
||||
Exact List
|
||||
================================================================================
|
||||
|
||||
foo <[int, float, int]> = [1, 2.0, 3]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
(root
|
||||
(statement
|
||||
(statement_kind
|
||||
(assignment
|
||||
(identifier)
|
||||
(type_specification
|
||||
(type
|
||||
(type)
|
||||
(type)
|
||||
(type)))
|
||||
(assignment_operator)
|
||||
(statement
|
||||
(statement_kind
|
||||
(expression
|
||||
(value
|
||||
(list
|
||||
(expression
|
||||
(value
|
||||
(integer)))
|
||||
(expression
|
||||
(value
|
||||
(float)))
|
||||
(expression
|
||||
(value
|
||||
(integer))))))))))))
|
||||
|
@ -354,21 +354,15 @@ module.exports = grammar({
|
||||
'collection',
|
||||
'float',
|
||||
'int',
|
||||
'list',
|
||||
'map',
|
||||
seq(
|
||||
'{',
|
||||
repeat1(
|
||||
seq(
|
||||
$.identifier,
|
||||
$.type_specification,
|
||||
),
|
||||
),
|
||||
'}',
|
||||
),
|
||||
'none',
|
||||
'num',
|
||||
'str',
|
||||
// Custom type
|
||||
$.identifier,
|
||||
|
||||
// Custom type with arguments
|
||||
seq(
|
||||
$.identifier,
|
||||
'<',
|
||||
@ -380,7 +374,35 @@ module.exports = grammar({
|
||||
),
|
||||
'>',
|
||||
),
|
||||
seq('[', $.type, ']'),
|
||||
|
||||
// Map with exact fields
|
||||
seq(
|
||||
'{',
|
||||
repeat1(
|
||||
seq(
|
||||
$.identifier,
|
||||
$.type_specification,
|
||||
),
|
||||
),
|
||||
'}',
|
||||
),
|
||||
|
||||
// List of
|
||||
seq('list', '<', $.type, '>'),
|
||||
|
||||
// Exact list
|
||||
seq(
|
||||
'[',
|
||||
repeat(
|
||||
seq(
|
||||
$.type,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
']',
|
||||
),
|
||||
|
||||
// Function
|
||||
seq(
|
||||
'(',
|
||||
repeat(
|
||||
@ -447,27 +469,31 @@ module.exports = grammar({
|
||||
$.struct_definition,
|
||||
),
|
||||
|
||||
type_arguments: $ =>
|
||||
seq(
|
||||
'<',
|
||||
repeat1(
|
||||
seq(
|
||||
$.type,
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
'>',
|
||||
),
|
||||
|
||||
enum_definition: $ =>
|
||||
prec.right(
|
||||
seq(
|
||||
'enum',
|
||||
$.identifier,
|
||||
optional($.type_arguments),
|
||||
repeat(
|
||||
seq(
|
||||
'{',
|
||||
repeat1(
|
||||
seq(
|
||||
$.identifier,
|
||||
optional(
|
||||
seq(
|
||||
'(',
|
||||
choice(
|
||||
$.type,
|
||||
$.type_definition,
|
||||
),
|
||||
')',
|
||||
),
|
||||
),
|
||||
optional($.type_arguments),
|
||||
optional(','),
|
||||
),
|
||||
),
|
||||
|
@ -1074,36 +1074,11 @@
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "map"
|
||||
"value": "list"
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "{"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT1",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type_specification"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "}"
|
||||
}
|
||||
]
|
||||
"type": "STRING",
|
||||
"value": "map"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
@ -1167,12 +1142,82 @@
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "["
|
||||
"value": "{"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT1",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type_specification"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "list"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "<"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "["
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ","
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "]"
|
||||
@ -1386,6 +1431,43 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"type_arguments": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "<"
|
||||
},
|
||||
{
|
||||
"type": "REPEAT1",
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ","
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ">"
|
||||
}
|
||||
]
|
||||
},
|
||||
"enum_definition": {
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
@ -1400,6 +1482,18 @@
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type_arguments"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
"content": {
|
||||
@ -1422,30 +1516,8 @@
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "("
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "type_definition"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ")"
|
||||
}
|
||||
]
|
||||
"type": "SYMBOL",
|
||||
"name": "type_arguments"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
|
@ -141,11 +141,7 @@
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "type_definition",
|
||||
"type": "type_arguments",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
@ -738,6 +734,21 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "type_arguments",
|
||||
"named": true,
|
||||
"fields": {},
|
||||
"children": {
|
||||
"multiple": true,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "type",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "type_definition",
|
||||
"named": true,
|
||||
@ -1030,6 +1041,10 @@
|
||||
"type": "integer",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "list",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "map",
|
||||
"named": false
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user