1
0

Add type argument syntax

This commit is contained in:
Jeff 2024-02-18 15:07:53 -05:00
parent a5f3127bcf
commit 0805b96809
22 changed files with 23448 additions and 21860 deletions

View File

@ -37,9 +37,9 @@ impl AbstractTree for As {
fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> { fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> {
let initial_type = self.expression.expected_type(context)?; 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 { match &initial_type {
Type::List(expected_item_type) => { Type::ListOf(expected_item_type) => {
if !item_type.accepts(&expected_item_type) { if !item_type.accepts(&expected_item_type) {
return Err(ValidationError::TypeCheck { return Err(ValidationError::TypeCheck {
expected: self.r#type.clone(), expected: self.r#type.clone(),
@ -77,7 +77,7 @@ impl AbstractTree for As {
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> { fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
let value = self.expression.run(source, context)?; 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 { match value {
Value::List(list) => Value::List(list), Value::List(list) => Value::List(list),
Value::String(string) => { Value::String(string) => {

View File

@ -78,7 +78,7 @@ impl AbstractTree for Assignment {
} }
} }
AssignmentOperator::PlusEqual => { 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)?; let actual = self.identifier.expected_type(context)?;
if !expected.accepts(&actual) { if !expected.accepts(&actual) {
@ -107,7 +107,7 @@ impl AbstractTree for Assignment {
match self.operator { match self.operator {
AssignmentOperator::Equal => {} AssignmentOperator::Equal => {}
AssignmentOperator::PlusEqual => { 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)?; let actual = self.statement.expected_type(context)?;
if !expected.accepts(&actual) { if !expected.accepts(&actual) {

View File

@ -9,11 +9,11 @@ use crate::{
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct EnumDefinition { pub struct EnumDefinition {
identifier: Identifier, identifier: Identifier,
variants: Vec<(Identifier, Option<Type>)>, variants: Vec<(Identifier, Vec<Type>)>,
} }
impl EnumDefinition { 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 { Self {
identifier, identifier,
variants, variants,
@ -27,6 +27,10 @@ impl EnumDefinition {
pub fn identifier(&self) -> &Identifier { pub fn identifier(&self) -> &Identifier {
&self.identifier &self.identifier
} }
pub fn variants(&self) -> &Vec<(Identifier, Vec<Type>)> {
&self.variants
}
} }
impl AbstractTree for EnumDefinition { impl AbstractTree for EnumDefinition {
@ -37,21 +41,25 @@ impl AbstractTree for EnumDefinition {
let identifier = Identifier::from_syntax(identifier_node, source, context)?; let identifier = Identifier::from_syntax(identifier_node, source, context)?;
let mut variants = Vec::new(); 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 { for index in 3..node.child_count() - 1 {
let child = node.child(index).unwrap(); let child = node.child(index).unwrap();
if child.kind() == "identifier" { if child.kind() == "identifier" {
current_identifier = Some(Identifier::from_syntax(child, source, context)?); if let Some(identifier) = &current_identifier {
variants.push((identifier.clone(), types));
}
current_identifier = Some(Identifier::from_syntax(child, source, context)?);
types = Vec::new();
} }
if let Some(identifier) = &current_identifier {
if child.kind() == "type" { if child.kind() == "type" {
let r#type = Type::from_syntax(child, source, context)?; 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) 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(()) Ok(())
} }
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> { fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?;
Ok(Value::none()) Ok(Value::none())
} }
} }

View File

@ -66,7 +66,7 @@ impl AbstractTree for For {
self.collection.validate(_source, context)?; self.collection.validate(_source, context)?;
let collection_type = self.collection.expected_type(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() item_type.as_ref().clone()
} else if let Type::Range = collection_type { } else if let Type::Range = collection_type {
Type::Integer Type::Integer

View File

@ -35,7 +35,7 @@ impl AbstractTree for Index {
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
match self.collection.expected_type(context)? { 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) => { Type::Map(map_types_option) => {
if let (Some(map_type), IndexExpression::Identifier(identifier)) = if let (Some(map_type), IndexExpression::Identifier(identifier)) =
(map_types_option, &self.index) (map_types_option, &self.index)

View File

@ -19,7 +19,7 @@ pub enum Type {
Collection, Collection,
Custom { Custom {
name: Identifier, name: Identifier,
argument: Option<Box<Type>>, arguments: Vec<Type>,
}, },
Float, Float,
Function { Function {
@ -27,20 +27,19 @@ pub enum Type {
return_type: Box<Type>, return_type: Box<Type>,
}, },
Integer, Integer,
List(Box<Type>), List,
ListOf(Box<Type>),
ListExact(Vec<Type>),
Map(Option<BTreeMap<Identifier, Type>>), Map(Option<BTreeMap<Identifier, Type>>),
None,
Number, Number,
String, String,
Range, Range,
None,
} }
impl Type { impl Type {
pub fn custom(name: Identifier, argument: Option<Type>) -> Self { pub fn custom(name: Identifier, arguments: Vec<Type>) -> Self {
Type::Custom { Type::Custom { name, arguments }
name,
argument: argument.map(|r#type| Box::new(r#type)),
}
} }
pub fn option(inner_type: Option<Type>) -> Self { pub fn option(inner_type: Option<Type>) -> Self {
@ -48,7 +47,7 @@ impl Type {
} }
pub fn list(item_type: Type) -> Self { 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 { pub fn function(parameter_types: Vec<Type>, return_type: Type) -> Self {
@ -70,14 +69,15 @@ impl Type {
| (_, Type::Any) | (_, Type::Any)
| (Type::Boolean, Type::Boolean) | (Type::Boolean, Type::Boolean)
| (Type::Collection, Type::Collection) | (Type::Collection, Type::Collection)
| (Type::Collection, Type::List(_)) | (Type::Collection, Type::ListOf(_))
| (Type::List(_), Type::Collection) | (Type::ListOf(_), Type::Collection)
| (Type::Collection, Type::Map(_)) | (Type::Collection, Type::Map(_))
| (Type::Map(_), Type::Collection) | (Type::Map(_), Type::Collection)
| (Type::Collection, Type::String) | (Type::Collection, Type::String)
| (Type::String, Type::Collection) | (Type::String, Type::Collection)
| (Type::Float, Type::Float) | (Type::Float, Type::Float)
| (Type::Integer, Type::Integer) | (Type::Integer, Type::Integer)
| (Type::List, Type::List)
| (Type::Map(None), Type::Map(None)) | (Type::Map(None), Type::Map(None))
| (Type::Number, Type::Number) | (Type::Number, Type::Number)
| (Type::Number, Type::Integer) | (Type::Number, Type::Integer)
@ -90,22 +90,25 @@ impl Type {
( (
Type::Custom { Type::Custom {
name: left_name, name: left_name,
argument: left_argument, arguments: left_arguments,
}, },
Type::Custom { Type::Custom {
name: right_name, name: right_name,
argument: right_argument, arguments: right_arguments,
}, },
) => { ) => left_name == right_name && left_arguments == right_arguments,
if left_name != right_name { (Type::ListOf(self_item_type), Type::ListOf(other_item_type)) => {
false
} else {
left_argument == right_argument
}
}
(Type::List(self_item_type), Type::List(other_item_type)) => {
self_item_type.accepts(&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 { Type::Function {
parameter_types: self_parameter_types, parameter_types: self_parameter_types,
@ -137,7 +140,7 @@ impl Type {
} }
pub fn is_list(&self) -> bool { pub fn is_list(&self) -> bool {
matches!(self, Type::List(_)) matches!(self, Type::ListOf(_))
} }
pub fn is_map(&self) -> bool { pub fn is_map(&self) -> bool {
@ -158,13 +161,19 @@ impl AbstractTree for Type {
let r#type = match type_node.kind() { let r#type = match type_node.kind() {
"identifier" => { "identifier" => {
let name = Identifier::from_syntax(type_node, _source, context)?; let name = Identifier::from_syntax(type_node, _source, context)?;
let argument = if let Some(child) = node.child(2) { let mut arguments = Vec::new();
Some(Type::from_syntax(child, _source, context)?)
} else {
None
};
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(); 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_node = node.child(1).unwrap();
let item_type = Type::from_syntax(item_type_node, _source, context)?; 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, "any" => Type::Any,
"bool" => Type::Boolean, "bool" => Type::Boolean,
@ -261,7 +270,7 @@ impl Format for Type {
Type::Collection => output.push_str("collection"), Type::Collection => output.push_str("collection"),
Type::Custom { Type::Custom {
name: _, name: _,
argument: _, arguments: _,
} => todo!(), } => todo!(),
Type::Float => output.push_str("float"), Type::Float => output.push_str("float"),
Type::Function { Type::Function {
@ -282,11 +291,13 @@ impl Format for Type {
return_type.format(output, indent_level); return_type.format(output, indent_level);
} }
Type::Integer => output.push_str("int"), Type::Integer => output.push_str("int"),
Type::List(item_type) => { Type::List => todo!(),
Type::ListOf(item_type) => {
output.push('['); output.push('[');
item_type.format(output, indent_level); item_type.format(output, indent_level);
output.push(']'); output.push(']');
} }
Type::ListExact(_) => todo!(),
Type::Map(_) => { Type::Map(_) => {
output.push_str("map"); output.push_str("map");
} }
@ -304,9 +315,19 @@ impl Display for Type {
Type::Any => write!(f, "any"), Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"), Type::Boolean => write!(f, "bool"),
Type::Collection => write!(f, "collection"), Type::Collection => write!(f, "collection"),
Type::Custom { name, argument } => { Type::Custom { name, arguments } => {
if let Some(argument) = argument { if !arguments.is_empty() {
write!(f, "{name}<{argument}>") 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 { } else {
write!(f, "{name}") write!(f, "{name}")
} }
@ -330,7 +351,21 @@ impl Display for Type {
write!(f, " -> {return_type}") write!(f, " -> {return_type}")
} }
Type::Integer => write!(f, "int"), 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::Map(_) => write!(f, "map"),
Type::Number => write!(f, "num"), Type::Number => write!(f, "num"),
Type::None => write!(f, "none"), Type::None => write!(f, "none"),

View File

@ -124,43 +124,47 @@ impl AbstractTree for ValueNode {
ValueNode::Integer(_) => Type::Integer, ValueNode::Integer(_) => Type::Integer,
ValueNode::String(_) => Type::String, ValueNode::String(_) => Type::String,
ValueNode::List(expressions) => { ValueNode::List(expressions) => {
let mut previous_type = None; let mut item_types = Vec::new();
for expression in expressions { for expression in expressions {
let expression_type = expression.expected_type(context)?; let expression_type = expression.expected_type(context)?;
if let Some(previous) = previous_type { item_types.push(expression_type);
if expression_type != previous {
return Ok(Type::List(Box::new(Type::Any)));
}
} }
previous_type = Some(expression_type); Type::ListExact(item_types)
}
if let Some(previous) = previous_type {
Type::List(Box::new(previous))
} else {
Type::List(Box::new(Type::Any))
}
} }
ValueNode::Map(map_node) => map_node.expected_type(context)?, ValueNode::Map(map_node) => map_node.expected_type(context)?,
ValueNode::Struct { name, .. } => { ValueNode::Struct { name, .. } => {
Type::Custom { name: name.clone(), argument: None } Type::custom(name.clone(), Vec::with_capacity(0))
} }
ValueNode::Range(_) => Type::Range, ValueNode::Range(_) => Type::Range,
ValueNode::Enum { name, variant: _, expression } => { ValueNode::Enum { name, variant, expression: _ } => {
if let Some(expression) = expression { let types: Vec<Type> = if let Some(type_definition) = context.get_definition(name)? {
Type::Custom { if let TypeDefinition::Enum(enum_definition) = type_definition {
name: name.clone(), let types = enum_definition.variants().into_iter().find_map(|(identifier, types)| {
argument: Some(Box::new(expression.expected_type(context)?)) 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 { } else {
Type::Custom{ return Err(ValidationError::VariableIdentifierNotFound(name.clone()));
name: name.clone(), };
argument: None,
} Type::custom(name.clone(), types.clone())
}
}, },
}; };

View File

@ -73,13 +73,7 @@ impl Callable for BuiltInFunction {
fn r#type(&self) -> Type { fn r#type(&self) -> Type {
match self { match self {
BuiltInFunction::AssertEqual => Type::function( BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
vec![Type::Any, Type::Any],
Type::Custom {
name: Identifier::new("Result"),
argument: None,
},
),
BuiltInFunction::Fs(fs_function) => fs_function.r#type(), BuiltInFunction::Fs(fs_function) => fs_function.r#type(),
BuiltInFunction::Json(json_function) => json_function.r#type(), BuiltInFunction::Json(json_function) => json_function.r#type(),
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer), BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),

View File

@ -33,8 +33,8 @@ impl BuiltInTypeDefinition {
let definition = TypeDefinition::Enum(EnumDefinition::new( let definition = TypeDefinition::Enum(EnumDefinition::new(
Identifier::new(self.name()), Identifier::new(self.name()),
vec![ vec![
(Identifier::new("Some"), Some(Type::Any)), (Identifier::new("Some"), vec![Type::Any]),
(Identifier::new("None"), None), (Identifier::new("None"), Vec::with_capacity(0)),
], ],
)); ));
@ -44,8 +44,8 @@ impl BuiltInTypeDefinition {
let definition = TypeDefinition::Enum(EnumDefinition::new( let definition = TypeDefinition::Enum(EnumDefinition::new(
Identifier::new(self.name()), Identifier::new(self.name()),
vec![ vec![
(Identifier::new("Ok"), Some(Type::Any)), (Identifier::new("Ok"), vec![Type::Any]),
(Identifier::new("Err"), Some(Type::Any)), (Identifier::new("Error"), vec![Type::Any]),
], ],
)); ));

View File

@ -19,15 +19,9 @@ impl BuiltInType {
match self { match self {
BuiltInType::Option(content_type) => OPTION.get_or_init(|| { BuiltInType::Option(content_type) => OPTION.get_or_init(|| {
if let Some(content_type) = content_type { if let Some(content_type) = content_type {
Type::Custom { Type::custom(Identifier::new("Option"), vec![content_type.clone()])
name: Identifier::new("Option"),
argument: Some(Box::new(content_type.clone())),
}
} else { } else {
Type::Custom { Type::custom(Identifier::new("Option"), Vec::with_capacity(0))
name: Identifier::new("Option"),
argument: None,
}
} }
}), }),
} }

View File

@ -270,7 +270,7 @@ impl Context {
let old_data = map.remove(&key); let old_data = map.remove(&key);
if let Some((_, old_counter)) = old_data { 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 { } else {
map.insert(key, (ValueData::Value(value), UsageCounter::new())); map.insert(key, (ValueData::Value(value), UsageCounter::new()));
} }

View File

@ -16,7 +16,7 @@ use tree_sitter::LanguageError;
use std::fmt::{self, Formatter}; use std::fmt::{self, Formatter};
#[derive(PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
Syntax(SyntaxError), Syntax(SyntaxError),
@ -95,12 +95,6 @@ impl From<LanguageError> for Error {
impl std::error::Error 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 { impl fmt::Display for Error {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
use Error::*; use Error::*;

View File

@ -74,25 +74,15 @@ impl Value {
pub fn r#type(&self) -> Result<Type, RwLockError> { pub fn r#type(&self) -> Result<Type, RwLockError> {
let r#type = match self { let r#type = match self {
Value::List(list) => { Value::List(list) => {
let mut previous_type = None; let mut item_types = Vec::new();
for value in list.items()?.iter() { for value in list.items()?.iter() {
let value_type = value.r#type(); let r#type = value.r#type()?;
if let Some(previous) = &previous_type { item_types.push(r#type);
if &value_type != previous {
return Ok(Type::List(Box::new(Type::Any)));
}
} }
previous_type = Some(value_type); Type::ListExact(item_types)
}
if let Some(previous) = previous_type {
Type::List(Box::new(previous?))
} else {
Type::List(Box::new(Type::Any))
}
} }
Value::Map(map) => { Value::Map(map) => {
if map.inner().is_empty() { if map.inner().is_empty() {

View File

@ -24,7 +24,7 @@ fn string_as_list_error() {
interpret("'foobar' as [float]"), interpret("'foobar' as [float]"),
Err(Error::Validation(ValidationError::ConversionImpossible { Err(Error::Validation(ValidationError::ConversionImpossible {
initial_type: Type::String, 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]")), interpret(&format!("json:parse('{JSON}') as [map]")),
Err(Error::Runtime(RuntimeError::ConversionImpossible { Err(Error::Runtime(RuntimeError::ConversionImpossible {
from: json_value.r#type().unwrap(), from: json_value.r#type().unwrap(),
to: Type::List(Box::new(Type::Map(None))), to: Type::ListOf(Box::new(Type::Map(None))),
position: SourcePosition { position: SourcePosition {
start_byte: 0, start_byte: 0,
end_byte: 33, end_byte: 33,

View File

@ -1,5 +1,26 @@
use dust_lang::*; 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] #[test]
fn option() { fn option() {
assert_eq!( assert_eq!(
@ -13,14 +34,12 @@ fn option() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
opt <Option<int>> = Option::Some(1); Option::Some(1)
opt
" "
), ),
Ok(Value::Enum(EnumInstance::new( Ok(Value::Enum(EnumInstance::new(
Identifier::new("Option"), Identifier::new("Option"),
Identifier::new("None"), Identifier::new("Some"),
Some(Value::Integer(1)), Some(Value::Integer(1)),
))) )))
); );
@ -39,8 +58,7 @@ fn result() {
assert_eq!( assert_eq!(
interpret( interpret(
" "
result <Result<int, str>> = Result::Error('uh-oh!') Result::Error('uh-oh!')
result
" "
), ),
Ok(Value::Enum(EnumInstance::new( Ok(Value::Enum(EnumInstance::new(

View File

@ -1,4 +1,4 @@
use dust_lang::*; use dust_lang::{error::RuntimeError, *};
#[test] #[test]
fn args() { fn args() {
@ -23,10 +23,9 @@ fn assert_equal() {
); );
assert_eq!( assert_eq!(
interpret("assert_equal(true, false)"), interpret("assert_equal(true, false)"),
Ok(Value::Enum(EnumInstance::new( Err(Error::Runtime(RuntimeError::AssertEqualFailed {
Identifier::new("Result"), left: true.into(),
Identifier::new("Error"), right: false.into()
Some(Value::none()), }))
)))
); );
} }

View File

@ -19,15 +19,12 @@ enum Foobar {
(identifier)))))) (identifier))))))
================================================================================ ================================================================================
Nested Enum Enum with Arguments
================================================================================ ================================================================================
enum Foobar { enum Foobar<T, U> {
Foo(str), Foo<T>,
Bar(enum BazBuff { Bar<U>,
Baz,
Buff,
})
} }
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -38,14 +35,55 @@ enum Foobar {
(type_definition (type_definition
(enum_definition (enum_definition
(identifier) (identifier)
(type_arguments
(type
(identifier))
(type
(identifier)))
(identifier) (identifier)
(type) (type_arguments
(type
(identifier)))
(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 (type_definition
(enum_definition (enum_definition
(identifier) (identifier)
(type_arguments
(type
(identifier)))
(identifier) (identifier)
(identifier)))))))) (type_arguments
(type
(identifier)))
(identifier)
(type_arguments
(type)
(type))
(identifier)
(type_arguments
(type
(identifier)
(type
(identifier)))))))))
================================================================================ ================================================================================
Simple Enum Instance Simple Enum Instance

View File

@ -28,3 +28,69 @@ x <{ y <int> }> = { y = 2 }
(expression (expression
(value (value
(integer)))))))))))))) (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))))))))))))

View File

@ -354,21 +354,15 @@ module.exports = grammar({
'collection', 'collection',
'float', 'float',
'int', 'int',
'list',
'map', 'map',
seq(
'{',
repeat1(
seq(
$.identifier,
$.type_specification,
),
),
'}',
),
'none', 'none',
'num', 'num',
'str', 'str',
// Custom type
$.identifier, $.identifier,
// Custom type with arguments
seq( seq(
$.identifier, $.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( seq(
'(', '(',
repeat( repeat(
@ -447,27 +469,31 @@ module.exports = grammar({
$.struct_definition, $.struct_definition,
), ),
type_arguments: $ =>
seq(
'<',
repeat1(
seq(
$.type,
optional(','),
),
),
'>',
),
enum_definition: $ => enum_definition: $ =>
prec.right( prec.right(
seq( seq(
'enum', 'enum',
$.identifier, $.identifier,
optional($.type_arguments),
repeat( repeat(
seq( seq(
'{', '{',
repeat1( repeat1(
seq( seq(
$.identifier, $.identifier,
optional( optional($.type_arguments),
seq(
'(',
choice(
$.type,
$.type_definition,
),
')',
),
),
optional(','), optional(','),
), ),
), ),

View File

@ -1072,39 +1072,14 @@
"type": "STRING", "type": "STRING",
"value": "int" "value": "int"
}, },
{
"type": "STRING",
"value": "list"
},
{ {
"type": "STRING", "type": "STRING",
"value": "map" "value": "map"
}, },
{
"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", "type": "STRING",
"value": "none" "value": "none"
@ -1167,12 +1142,82 @@
"members": [ "members": [
{ {
"type": "STRING", "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", "type": "SYMBOL",
"name": "type" "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", "type": "STRING",
"value": "]" "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": { "enum_definition": {
"type": "PREC_RIGHT", "type": "PREC_RIGHT",
"value": 0, "value": 0,
@ -1400,6 +1482,18 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "identifier" "name": "identifier"
}, },
{
"type": "CHOICE",
"members": [
{
"type": "SYMBOL",
"name": "type_arguments"
},
{
"type": "BLANK"
}
]
},
{ {
"type": "REPEAT", "type": "REPEAT",
"content": { "content": {
@ -1418,34 +1512,12 @@
"type": "SYMBOL", "type": "SYMBOL",
"name": "identifier" "name": "identifier"
}, },
{
"type": "CHOICE",
"members": [
{
"type": "SEQ",
"members": [
{
"type": "STRING",
"value": "("
},
{ {
"type": "CHOICE", "type": "CHOICE",
"members": [ "members": [
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "type" "name": "type_arguments"
},
{
"type": "SYMBOL",
"name": "type_definition"
}
]
},
{
"type": "STRING",
"value": ")"
}
]
}, },
{ {
"type": "BLANK" "type": "BLANK"

View File

@ -141,11 +141,7 @@
"named": true "named": true
}, },
{ {
"type": "type", "type": "type_arguments",
"named": true
},
{
"type": "type_definition",
"named": true "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", "type": "type_definition",
"named": true, "named": true,
@ -1030,6 +1041,10 @@
"type": "integer", "type": "integer",
"named": true "named": true
}, },
{
"type": "list",
"named": false
},
{ {
"type": "map", "type": "map",
"named": false "named": false

File diff suppressed because it is too large Load Diff