Continue type check implementation
This commit is contained in:
parent
bc2615a1ed
commit
081d349783
@ -1,4 +1,4 @@
|
|||||||
fib = |i <int>| <int> {
|
fib <fn int -> int> = |i| {
|
||||||
if i <= 1 {
|
if i <= 1 {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
|
8
scripts/build_debug.fish
Executable file
8
scripts/build_debug.fish
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/fish
|
||||||
|
# Build the project in debug mode.
|
||||||
|
|
||||||
|
cd tree-sitter-dust/
|
||||||
|
tree-sitter generate --debug-build --no-bindings
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
cargo build
|
8
scripts/build_release.fish
Executable file
8
scripts/build_release.fish
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/fish
|
||||||
|
# Build the project in debug mode.
|
||||||
|
|
||||||
|
cd tree-sitter-dust/
|
||||||
|
tree-sitter generate --no-bindings
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
cargo build --release
|
@ -1,12 +1,12 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Identifier, Map, Result, Statement, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Identifier, Map, Result, Statement, Type, TypeDefintion, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Assignment {
|
pub struct Assignment {
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
r#type: Option<TypeDefinition>,
|
type_definition: Option<TypeDefintion>,
|
||||||
operator: AssignmentOperator,
|
operator: AssignmentOperator,
|
||||||
statement: Statement,
|
statement: Statement,
|
||||||
}
|
}
|
||||||
@ -26,8 +26,8 @@ impl AbstractTree for Assignment {
|
|||||||
let identifier = Identifier::from_syntax_node(source, identifier_node)?;
|
let identifier = Identifier::from_syntax_node(source, identifier_node)?;
|
||||||
|
|
||||||
let type_node = node.child_by_field_name("type");
|
let type_node = node.child_by_field_name("type");
|
||||||
let r#type = if let Some(type_node) = type_node {
|
let type_definition = if let Some(type_node) = type_node {
|
||||||
Some(TypeDefinition::from_syntax_node(source, type_node)?)
|
Some(TypeDefintion::from_syntax_node(source, type_node)?)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@ -56,7 +56,7 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
identifier,
|
identifier,
|
||||||
r#type,
|
type_definition,
|
||||||
operator,
|
operator,
|
||||||
statement,
|
statement,
|
||||||
})
|
})
|
||||||
@ -66,6 +66,10 @@ impl AbstractTree for Assignment {
|
|||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
let value = self.statement.run(source, context)?;
|
let value = self.statement.run(source, context)?;
|
||||||
|
|
||||||
|
if let Some(type_definition) = &self.type_definition {
|
||||||
|
type_definition.check(&value, context)?;
|
||||||
|
}
|
||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
|
if let Some(mut previous_value) = context.variables()?.get(key).cloned() {
|
||||||
@ -91,7 +95,7 @@ impl AbstractTree for Assignment {
|
|||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Empty)
|
Ok(Type::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use rayon::prelude::*;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Map, Result, Statement, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Map, Result, Statement, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
@ -82,7 +82,7 @@ impl AbstractTree for Block {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.statements.last().unwrap().expected_type(context)
|
self.statements.last().unwrap().expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, TypeDefinition,
|
value_node::ValueNode, AbstractTree, Error, Identifier, Index, Map, Result, Type, Value, Yield,
|
||||||
Value, Yield,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
use super::{function_call::FunctionCall, logic::Logic, math::Math};
|
||||||
@ -64,7 +63,7 @@ impl AbstractTree for Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.expected_type(context),
|
Expression::Value(value_node) => value_node.expected_type(context),
|
||||||
Expression::Identifier(identifier) => identifier.expected_type(context),
|
Expression::Identifier(identifier) => identifier.expected_type(context),
|
||||||
|
@ -2,9 +2,7 @@ use rayon::prelude::*;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{
|
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Type, Value};
|
||||||
AbstractTree, Block, Error, Expression, Identifier, Map, Result, TypeDefinition, Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct For {
|
pub struct For {
|
||||||
@ -79,7 +77,7 @@ impl AbstractTree for For {
|
|||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Empty)
|
Ok(Type::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Map, Result, TypeDefinition, Value, BUILT_IN_FUNCTIONS};
|
use crate::{AbstractTree, Error, Map, Result, Type, Value, BUILT_IN_FUNCTIONS};
|
||||||
|
|
||||||
use super::expression::Expression;
|
use super::expression::Expression;
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
function.run(source, &mut function_context)
|
function.run(source, &mut function_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.function.expected_type(context)
|
self.function.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Identifier(String);
|
pub struct Identifier(String);
|
||||||
@ -37,11 +37,11 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
if let Some(value) = context.variables()?.get(&self.0) {
|
if let Some(value) = context.variables()?.get(&self.0) {
|
||||||
Ok(value.r#type(context)?)
|
Ok(value.r#type(context)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(TypeDefinition::Empty)
|
Ok(Type::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Block, Expression, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Block, Expression, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct IfElse {
|
pub struct IfElse {
|
||||||
@ -81,7 +81,7 @@ impl AbstractTree for IfElse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.if_block.expected_type(context)
|
self.if_block.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Expression, List, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Expression, List, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Index {
|
pub struct Index {
|
||||||
@ -74,7 +74,7 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.collection.expected_type(context)
|
self.collection.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn evaluate_complex_index() {
|
fn evaluate_complex_index() {
|
||||||
let test = evaluate("x = [1 2 3]; y = || <int> { 0 } x:((y))").unwrap();
|
let test = evaluate("x = [1 2 3]; y = || { 0 } x:((y))").unwrap();
|
||||||
|
|
||||||
assert_eq!(Value::Integer(1), test);
|
assert_eq!(Value::Integer(1), test);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Index, Map, Result, Statement, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Index, Map, Result, Statement, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct IndexAssignment {
|
pub struct IndexAssignment {
|
||||||
@ -91,7 +91,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Empty)
|
Ok(Type::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Expression, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Logic {
|
pub struct Logic {
|
||||||
@ -74,8 +74,8 @@ impl AbstractTree for Logic {
|
|||||||
Ok(Value::Boolean(result))
|
Ok(Value::Boolean(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Boolean)
|
Ok(Type::Boolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Match {}
|
pub struct Match {}
|
||||||
@ -20,7 +20,7 @@ impl AbstractTree for Match {
|
|||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Expression, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Error, Expression, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Math {
|
pub struct Math {
|
||||||
@ -56,8 +56,8 @@ impl AbstractTree for Math {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Number)
|
Ok(Type::Number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ impl AbstractTree for Root {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.statements.last().unwrap().expected_type(context)
|
self.statements.last().unwrap().expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,5 +88,5 @@ pub trait AbstractTree: Sized {
|
|||||||
/// Execute dust code by traversing the tree.
|
/// Execute dust code by traversing the tree.
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value>;
|
fn run(&self, source: &str, context: &Map) -> Result<Value>;
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition>;
|
fn expected_type(&self, context: &Map) -> Result<Type>;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use tree_sitter::Node;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Assignment, Block, Error, Expression, For, IfElse, IndexAssignment, Map, Match,
|
AbstractTree, Assignment, Block, Error, Expression, For, IfElse, IndexAssignment, Map, Match,
|
||||||
Result, TypeDefinition, Use, Value, While,
|
Result, Type, Use, Value, While,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Abstract representation of a statement.
|
/// Abstract representation of a statement.
|
||||||
@ -82,7 +82,7 @@ impl AbstractTree for Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.expected_type(context),
|
Statement::Assignment(assignment) => assignment.expected_type(context),
|
||||||
Statement::Return(expression) => expression.expected_type(context),
|
Statement::Return(expression) => expression.expected_type(context),
|
||||||
|
@ -6,129 +6,171 @@ use tree_sitter::Node;
|
|||||||
use crate::{AbstractTree, Error, Map, Result, Value};
|
use crate::{AbstractTree, Error, Map, Result, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum TypeDefinition {
|
pub struct TypeDefintion {
|
||||||
|
r#type: Type,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AbstractTree for TypeDefintion {
|
||||||
|
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||||
|
Error::expect_syntax_node(source, "type_definition", node)?;
|
||||||
|
|
||||||
|
let type_node = node.child(1).unwrap();
|
||||||
|
let r#type = Type::from_syntax_node(source, type_node)?;
|
||||||
|
|
||||||
|
Ok(TypeDefintion { r#type })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
|
self.r#type.run(source, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
|
self.r#type.expected_type(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
|
pub enum Type {
|
||||||
Any,
|
Any,
|
||||||
Boolean,
|
Boolean,
|
||||||
Empty,
|
Empty,
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
parameter_types: Vec<TypeDefinition>,
|
parameter_types: Vec<Type>,
|
||||||
return_type: Box<TypeDefinition>,
|
return_type: Box<Type>,
|
||||||
},
|
},
|
||||||
Integer,
|
Integer,
|
||||||
List(Box<TypeDefinition>),
|
List(Box<Type>),
|
||||||
Map,
|
Map,
|
||||||
Number,
|
Number,
|
||||||
String,
|
String,
|
||||||
Table,
|
Table,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeDefinition {
|
impl TypeDefintion {
|
||||||
// pub fn check(&self, value: &Value) -> Result<()> {
|
pub fn check(&self, value: &Value, context: &Map) -> Result<()> {
|
||||||
// match (self, value.r#type()?) {
|
match (&self.r#type, value) {
|
||||||
// (Type::Any, _)
|
(Type::Any, _)
|
||||||
// | (Type::Boolean, Type::Boolean)
|
| (Type::Boolean, Value::Boolean(_))
|
||||||
// | (Type::Empty, Type::Empty)
|
| (Type::Empty, Value::Empty)
|
||||||
// | (Type::Float, Type::Float)
|
| (Type::Float, Value::Float(_))
|
||||||
// | (Type::Integer, Type::Integer)
|
| (Type::Integer, Value::Integer(_))
|
||||||
// | (Type::Map, Type::Map)
|
| (Type::Map, Value::Map(_))
|
||||||
// | (Type::Number, Type::Number)
|
| (Type::Number, Value::Integer(_))
|
||||||
// | (Type::Number, Type::Integer)
|
| (Type::Number, Value::Float(_))
|
||||||
// | (Type::Number, Type::Float)
|
| (Type::String, Value::String(_))
|
||||||
// | (Type::Integer, Type::Number)
|
| (Type::Table, Value::Table(_)) => Ok(()),
|
||||||
// | (Type::Float, Type::Number)
|
(Type::List(_), Value::List(list)) => {
|
||||||
// | (Type::String, Type::String)
|
if let Some(first) = list.items().first() {
|
||||||
// | (Type::Table, Type::Table) => Ok(()),
|
self.check(first, context)
|
||||||
// (Type::List(expected), Type::List(actual)) => {
|
} else {
|
||||||
// if expected != &actual {
|
Ok(())
|
||||||
// Err(Error::TypeCheck {
|
}
|
||||||
// expected: Type::List(expected.clone()),
|
}
|
||||||
// actual: value.clone(),
|
(
|
||||||
// })
|
Type::Function {
|
||||||
// } else {
|
parameter_types,
|
||||||
// Ok(())
|
return_type,
|
||||||
// }
|
},
|
||||||
// }
|
Value::Function(function),
|
||||||
// (
|
) => {
|
||||||
// Type::Function {
|
let parameter_type_count = parameter_types.len();
|
||||||
// parameter_types: left_parameters,
|
let parameter_count = function.parameters().len();
|
||||||
// return_type: left_return,
|
|
||||||
// },
|
if parameter_type_count != parameter_count
|
||||||
// Type::Function {
|
|| return_type.as_ref() != &function.body().expected_type(context)?
|
||||||
// parameter_types: right_parameters,
|
{
|
||||||
// return_type: right_return,
|
return Err(Error::TypeCheck {
|
||||||
// },
|
expected: self.r#type.clone(),
|
||||||
// ) => {
|
actual: value.clone(),
|
||||||
// if left_parameters != &right_parameters || left_return != &right_return {
|
});
|
||||||
// Err(Error::TypeCheck {
|
}
|
||||||
// expected: Type::Function {
|
|
||||||
// parameter_types: left_parameters.clone(),
|
Ok(())
|
||||||
// return_type: left_return.clone(),
|
}
|
||||||
// },
|
(Type::Boolean, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::Boolean,
|
||||||
// })
|
actual: value.clone(),
|
||||||
// } else {
|
}),
|
||||||
// Ok(())
|
(Type::Empty, _) => Err(Error::TypeCheck {
|
||||||
// }
|
expected: Type::Empty,
|
||||||
// }
|
actual: value.clone(),
|
||||||
// (Type::Boolean, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::Boolean,
|
(Type::Float, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::Float,
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (Type::Empty, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::Empty,
|
(Type::Function { .. }, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: self.r#type.clone(),
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (Type::Float, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::Float,
|
(Type::Integer, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::Integer,
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (expected, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: expected.clone(),
|
(Type::List(_), _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: self.r#type.clone(),
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (Type::Integer, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::Integer,
|
(Type::Map, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::Map,
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (expected, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: expected.clone(),
|
(Type::Number, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::Number,
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (Type::Map, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::Map,
|
(Type::String, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::String,
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (Type::String, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::String,
|
(Type::Table, _) => Err(Error::TypeCheck {
|
||||||
// actual: value.clone(),
|
expected: Type::Table,
|
||||||
// }),
|
actual: value.clone(),
|
||||||
// (Type::Table, _) => Err(Error::TypeCheck {
|
}),
|
||||||
// expected: Type::Table,
|
}
|
||||||
// actual: value.clone(),
|
}
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for TypeDefinition {
|
impl AbstractTree for Type {
|
||||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "type_definition", node)?;
|
Error::expect_syntax_node(source, "type", node)?;
|
||||||
|
|
||||||
let type_node = node.child(1).unwrap();
|
let type_node = node.child(0).unwrap();
|
||||||
let type_symbol = &source[type_node.byte_range()];
|
|
||||||
|
|
||||||
let r#type = match type_symbol {
|
let r#type = match type_node.kind() {
|
||||||
"any" => TypeDefinition::Any,
|
"any" => Type::Any,
|
||||||
"bool" => TypeDefinition::Boolean,
|
"bool" => Type::Boolean,
|
||||||
"float" => TypeDefinition::Float,
|
"float" => Type::Float,
|
||||||
"fn" => {
|
"fn" => {
|
||||||
todo!()
|
let child_count = node.child_count();
|
||||||
|
let mut parameter_types = Vec::new();
|
||||||
|
|
||||||
|
for index in 1..child_count - 2 {
|
||||||
|
let parameter_type_node = node.child(index).unwrap();
|
||||||
|
let parameter_type = Type::from_syntax_node(source, parameter_type_node)?;
|
||||||
|
|
||||||
|
parameter_types.push(parameter_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
let return_type_node = node.child(child_count - 1).unwrap();
|
||||||
|
let return_type = Type::from_syntax_node(source, return_type_node)?;
|
||||||
|
|
||||||
|
Type::Function {
|
||||||
|
parameter_types,
|
||||||
|
return_type: Box::new(return_type),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"int" => TypeDefinition::Integer,
|
"int" => Type::Integer,
|
||||||
"map" => TypeDefinition::Map,
|
"list" => {
|
||||||
"str" => TypeDefinition::String,
|
let item_type_node = node.child(1).unwrap();
|
||||||
"table" => TypeDefinition::Table,
|
let item_type = Type::from_syntax_node(source, item_type_node)?;
|
||||||
|
|
||||||
|
Type::List(Box::new(item_type))
|
||||||
|
}
|
||||||
|
"map" => Type::Map,
|
||||||
|
"str" => Type::String,
|
||||||
|
"table" => Type::Table,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "any, bool, float, fn, int, list, map, str or table",
|
expected: "any, bool, float, fn, int, list, map, str or table",
|
||||||
@ -146,25 +188,25 @@ impl AbstractTree for TypeDefinition {
|
|||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Empty)
|
Ok(Type::Empty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TypeDefinition {
|
impl Display for Type {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TypeDefinition::Any => write!(f, "any"),
|
Type::Any => write!(f, "any"),
|
||||||
TypeDefinition::Boolean => write!(f, "bool"),
|
Type::Boolean => write!(f, "bool"),
|
||||||
TypeDefinition::Empty => write!(f, "empty"),
|
Type::Empty => write!(f, "empty"),
|
||||||
TypeDefinition::Float => write!(f, "float"),
|
Type::Float => write!(f, "float"),
|
||||||
TypeDefinition::Function { .. } => write!(f, "function"),
|
Type::Function { .. } => write!(f, "function"),
|
||||||
TypeDefinition::Integer => write!(f, "integer"),
|
Type::Integer => write!(f, "integer"),
|
||||||
TypeDefinition::List(_) => write!(f, "list"),
|
Type::List(_) => write!(f, "list"),
|
||||||
TypeDefinition::Map => write!(f, "map"),
|
Type::Map => write!(f, "map"),
|
||||||
TypeDefinition::Number => write!(f, "number"),
|
Type::Number => write!(f, "number"),
|
||||||
TypeDefinition::String => write!(f, "string"),
|
Type::String => write!(f, "string"),
|
||||||
TypeDefinition::Table => write!(f, "table"),
|
Type::Table => write!(f, "table"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::fs::read_to_string;
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, TypeDefinition, Value};
|
use crate::{evaluate_with_context, AbstractTree, Error, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Use {
|
pub struct Use {
|
||||||
@ -30,7 +30,7 @@ impl AbstractTree for Use {
|
|||||||
Ok(Value::Map(file_context))
|
Ok(Value::Map(file_context))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(TypeDefinition::Map)
|
Ok(Type::Map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ use tree_sitter::Node;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
|
AbstractTree, Error, Expression, Function, Identifier, List, Map, Result, Statement, Table,
|
||||||
TypeDefinition, Value,
|
Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
@ -177,27 +177,27 @@ impl AbstractTree for ValueNode {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
ValueNode::Boolean(_) => TypeDefinition::Boolean,
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
ValueNode::Float(_) => TypeDefinition::Float,
|
ValueNode::Float(_) => Type::Float,
|
||||||
ValueNode::Integer(_) => TypeDefinition::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::String(_) => TypeDefinition::String,
|
ValueNode::String(_) => Type::String,
|
||||||
ValueNode::List(expressions) => {
|
ValueNode::List(expressions) => {
|
||||||
let first_expression_type = if let Some(first) = expressions.first() {
|
let first_expression_type = if let Some(first) = expressions.first() {
|
||||||
first.expected_type(context)?
|
first.expected_type(context)?
|
||||||
} else {
|
} else {
|
||||||
TypeDefinition::Empty
|
Type::Empty
|
||||||
};
|
};
|
||||||
|
|
||||||
TypeDefinition::List(Box::new(first_expression_type))
|
Type::List(Box::new(first_expression_type))
|
||||||
}
|
}
|
||||||
ValueNode::Empty => TypeDefinition::Any,
|
ValueNode::Empty => Type::Any,
|
||||||
ValueNode::Map(_) => TypeDefinition::Map,
|
ValueNode::Map(_) => Type::Map,
|
||||||
ValueNode::Table {
|
ValueNode::Table {
|
||||||
column_names: _,
|
column_names: _,
|
||||||
rows: _,
|
rows: _,
|
||||||
} => TypeDefinition::Table,
|
} => Type::Table,
|
||||||
ValueNode::Function(function) => function.expected_type(context)?,
|
ValueNode::Function(function) => function.expected_type(context)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Block, Expression, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Block, Expression, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct While {
|
pub struct While {
|
||||||
@ -30,7 +30,7 @@ impl AbstractTree for While {
|
|||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.block.expected_type(context)
|
self.block.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Expression, FunctionCall, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Expression, FunctionCall, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Yield {
|
pub struct Yield {
|
||||||
@ -39,7 +39,7 @@ impl AbstractTree for Yield {
|
|||||||
self.call.run(source, context)
|
self.call.run(source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.call.expected_type(context)
|
self.call.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use tree_sitter::{Node, Point};
|
use tree_sitter::{Node, Point};
|
||||||
|
|
||||||
use crate::{value::Value, Identifier, TypeDefinition};
|
use crate::{value::Value, Identifier, Type};
|
||||||
|
|
||||||
use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time};
|
use std::{fmt, io, num::ParseFloatError, string::FromUtf8Error, sync::PoisonError, time};
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ pub enum Error {
|
|||||||
},
|
},
|
||||||
|
|
||||||
TypeCheck {
|
TypeCheck {
|
||||||
expected: TypeDefinition,
|
expected: Type,
|
||||||
actual: Value,
|
actual: Value,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ struct Args {
|
|||||||
show_syntax_tree: bool,
|
show_syntax_tree: bool,
|
||||||
|
|
||||||
/// Launch in interactive mode.
|
/// Launch in interactive mode.
|
||||||
#[arg(short, long)]
|
#[arg(short = 'n', long)]
|
||||||
interactive: bool,
|
interactive: bool,
|
||||||
|
|
||||||
/// Location of the file to run.
|
/// Location of the file to run.
|
||||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Block, Error, Identifier, Map, Result, TypeDefinition, Value};
|
use crate::{AbstractTree, Block, Error, Identifier, Map, Result, Type, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
@ -28,7 +28,7 @@ impl AbstractTree for Function {
|
|||||||
let child_count = node.child_count();
|
let child_count = node.child_count();
|
||||||
let mut parameters = Vec::new();
|
let mut parameters = Vec::new();
|
||||||
|
|
||||||
for index in 0..child_count {
|
for index in 1..child_count - 2 {
|
||||||
let child = node.child(index).unwrap();
|
let child = node.child(index).unwrap();
|
||||||
|
|
||||||
if child.is_named() {
|
if child.is_named() {
|
||||||
@ -49,7 +49,7 @@ impl AbstractTree for Function {
|
|||||||
Ok(return_value)
|
Ok(return_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.body.expected_type(context)
|
self.body.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Types that represent runtime values.
|
//! Types that represent runtime values.
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
AbstractTree, Function, List, Map, Table, TypeDefinition,
|
AbstractTree, Function, List, Map, Table, Type,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
@ -43,19 +43,19 @@ pub enum Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
pub fn r#type(&self, context: &Map) -> Result<TypeDefinition> {
|
pub fn r#type(&self, context: &Map) -> Result<Type> {
|
||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
let first_item_type = if let Some(first) = list.items().first() {
|
let first_item_type = if let Some(first) = list.items().first() {
|
||||||
first.r#type(context)?
|
first.r#type(context)?
|
||||||
} else {
|
} else {
|
||||||
TypeDefinition::Empty
|
Type::Empty
|
||||||
};
|
};
|
||||||
|
|
||||||
TypeDefinition::List(Box::new(first_item_type))
|
Type::List(Box::new(first_item_type))
|
||||||
}
|
}
|
||||||
Value::Map(_) => TypeDefinition::Map,
|
Value::Map(_) => Type::Map,
|
||||||
Value::Table(_) => TypeDefinition::Table,
|
Value::Table(_) => Type::Table,
|
||||||
Value::Function(function) => {
|
Value::Function(function) => {
|
||||||
let parameter_types = Vec::new();
|
let parameter_types = Vec::new();
|
||||||
|
|
||||||
@ -65,16 +65,16 @@ impl Value {
|
|||||||
|
|
||||||
let return_type = function.body().expected_type(context)?;
|
let return_type = function.body().expected_type(context)?;
|
||||||
|
|
||||||
TypeDefinition::Function {
|
Type::Function {
|
||||||
parameter_types,
|
parameter_types,
|
||||||
return_type: Box::new(return_type),
|
return_type: Box::new(return_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::String(_) => TypeDefinition::String,
|
Value::String(_) => Type::String,
|
||||||
Value::Float(_) => TypeDefinition::Float,
|
Value::Float(_) => Type::Float,
|
||||||
Value::Integer(_) => TypeDefinition::Integer,
|
Value::Integer(_) => Type::Integer,
|
||||||
Value::Boolean(_) => TypeDefinition::Boolean,
|
Value::Boolean(_) => Type::Boolean,
|
||||||
Value::Empty => TypeDefinition::Empty,
|
Value::Empty => Type::Empty,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
find = |list function| => {
|
|
||||||
for i in list {
|
|
||||||
if (function i) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
map = |list function| => {
|
|
||||||
new_list = []
|
|
||||||
|
|
||||||
for i in list {
|
|
||||||
new_list += (function i)
|
|
||||||
}
|
|
||||||
|
|
||||||
new_list
|
|
||||||
}
|
|
||||||
|
|
||||||
[0 1 2] -> (map |i| => { i - 1})
|
|
||||||
-> (find |i| => { i == 1 })
|
|
@ -1080,8 +1080,25 @@
|
|||||||
{
|
{
|
||||||
"type": "REPEAT",
|
"type": "REPEAT",
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SYMBOL",
|
"type": "SEQ",
|
||||||
"name": "type"
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "type"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ","
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user