Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
ee30ae55a8 | |||
7f7772e654 | |||
4b22221322 |
@ -19,14 +19,13 @@ pub enum AssignmentOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Assignment {
|
impl AbstractTree for Assignment {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "assignment", node)?;
|
Error::expect_syntax_node(source, "assignment", node)?;
|
||||||
|
|
||||||
let child_count = node.child_count();
|
let child_count = node.child_count();
|
||||||
|
|
||||||
let identifier_node = node.child(0).unwrap();
|
let identifier_node = node.child(0).unwrap();
|
||||||
let identifier = Identifier::from_syntax_node(source, identifier_node, context)?;
|
let identifier = Identifier::from_syntax_node(source, identifier_node, context)?;
|
||||||
let identifier_type = identifier.expected_type(context)?;
|
|
||||||
|
|
||||||
let type_node = node.child(1).unwrap();
|
let type_node = node.child(1).unwrap();
|
||||||
let type_definition = if type_node.kind() == "type_definition" {
|
let type_definition = if type_node.kind() == "type_definition" {
|
||||||
@ -54,54 +53,17 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
let statement_node = node.child(child_count - 1).unwrap();
|
let statement_node = node.child(child_count - 1).unwrap();
|
||||||
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
||||||
let statement_type = statement.expected_type(context)?;
|
|
||||||
|
|
||||||
if let Some(type_definition) = &type_definition {
|
|
||||||
match operator {
|
|
||||||
AssignmentOperator::Equal => {
|
|
||||||
type_definition
|
|
||||||
.inner()
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
|
||||||
}
|
|
||||||
AssignmentOperator::PlusEqual => {
|
|
||||||
if let Type::List(item_type) = type_definition.inner() {
|
|
||||||
item_type
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
|
||||||
} else {
|
|
||||||
type_definition
|
|
||||||
.inner()
|
|
||||||
.check(&identifier_type)
|
|
||||||
.map_err(|error| error.at_node(identifier_node, source))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AssignmentOperator::MinusEqual => todo!(),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match operator {
|
|
||||||
AssignmentOperator::Equal => {}
|
|
||||||
AssignmentOperator::PlusEqual => {
|
|
||||||
if let Type::List(item_type) = identifier_type {
|
|
||||||
item_type
|
|
||||||
.check(&statement_type)
|
|
||||||
.map_err(|error| error.at_node(statement_node, source))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AssignmentOperator::MinusEqual => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let variable_key = identifier.inner().clone();
|
let variable_key = identifier.inner().clone();
|
||||||
let variable_type = if let Some(definition) = &type_definition {
|
let variable_type = if let Some(definition) = &type_definition {
|
||||||
definition.inner().clone()
|
definition.inner().clone()
|
||||||
} else if let Some((_, r#type)) = context.variables()?.get(identifier.inner()) {
|
} else if let Some((_, r#type)) = context.variables().get(identifier.inner()) {
|
||||||
r#type.clone()
|
r#type.clone()
|
||||||
} else {
|
} else {
|
||||||
statement_type
|
statement.expected_type(context)?
|
||||||
};
|
};
|
||||||
|
|
||||||
context.set(variable_key, Value::none(), Some(variable_type))?;
|
context.set(variable_key, Value::none(), Some(variable_type));
|
||||||
|
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
identifier,
|
identifier,
|
||||||
@ -111,13 +73,47 @@ impl AbstractTree for Assignment {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
let statement_type = self.statement.expected_type(context)?;
|
||||||
|
|
||||||
|
if let Some(type_definition) = &self.type_definition {
|
||||||
|
match self.operator {
|
||||||
|
AssignmentOperator::Equal => {
|
||||||
|
type_definition.inner().check(&statement_type)?;
|
||||||
|
}
|
||||||
|
AssignmentOperator::PlusEqual => {
|
||||||
|
if let Type::List(item_type) = type_definition.inner() {
|
||||||
|
item_type.check(&statement_type)?;
|
||||||
|
} else {
|
||||||
|
type_definition
|
||||||
|
.inner()
|
||||||
|
.check(&self.identifier.expected_type(context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssignmentOperator::MinusEqual => todo!(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match self.operator {
|
||||||
|
AssignmentOperator::Equal => {}
|
||||||
|
AssignmentOperator::PlusEqual => {
|
||||||
|
if let Type::List(item_type) = self.identifier.expected_type(context)? {
|
||||||
|
item_type.check(&statement_type)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AssignmentOperator::MinusEqual => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let key = self.identifier.inner();
|
let key = self.identifier.inner();
|
||||||
let value = self.statement.run(source, context)?;
|
let value = self.statement.run(source, 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() {
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -125,7 +121,7 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some((mut previous_value, _)) = context.variables()?.get(key).cloned() {
|
if let Some((mut previous_value, _)) = context.variables().get(key).cloned() {
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
} else {
|
} else {
|
||||||
@ -136,9 +132,9 @@ impl AbstractTree for Assignment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(type_defintion) = &self.type_definition {
|
if let Some(type_defintion) = &self.type_definition {
|
||||||
context.set(key.clone(), new_value, Some(type_defintion.inner().clone()))?;
|
context.set(key.clone(), new_value, Some(type_defintion.inner().clone()));
|
||||||
} else {
|
} else {
|
||||||
context.set(key.clone(), new_value, None)?;
|
context.set(key.clone(), new_value, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
|
@ -21,7 +21,7 @@ pub struct Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Block {
|
impl AbstractTree for Block {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "block", node)?;
|
Error::expect_syntax_node(source, "block", node)?;
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
let first_child = node.child(0).unwrap();
|
||||||
@ -50,16 +50,34 @@ impl AbstractTree for Block {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
for statement in &self.statements {
|
||||||
|
if let Statement::Return(inner_statement) = statement {
|
||||||
|
return inner_statement.check_type(_source, _context);
|
||||||
|
} else {
|
||||||
|
statement.check_type(_source, _context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
let statements = &self.statements;
|
let statements = &self.statements;
|
||||||
|
let context = RwLock::new(context);
|
||||||
let final_result = RwLock::new(Ok(Value::none()));
|
let final_result = RwLock::new(Ok(Value::none()));
|
||||||
|
|
||||||
statements
|
statements
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map_first(|(index, statement)| {
|
.find_map_first(|(index, statement)| {
|
||||||
let result = statement.run(source, context);
|
let mut context = match context.write() {
|
||||||
|
Ok(context) => context,
|
||||||
|
Err(error) => return Some(Err(error.into())),
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = statement.run(source, *context);
|
||||||
let is_last_statement = index == statements.len() - 1;
|
let is_last_statement = index == statements.len() - 1;
|
||||||
let is_return_statement = if let Statement::Return(_) = statement {
|
let is_return_statement = if let Statement::Return(_) = statement {
|
||||||
true
|
true
|
||||||
@ -70,9 +88,7 @@ impl AbstractTree for Block {
|
|||||||
if is_return_statement || result.is_err() {
|
if is_return_statement || result.is_err() {
|
||||||
Some(result)
|
Some(result)
|
||||||
} else if is_last_statement {
|
} else if is_last_statement {
|
||||||
let get_write_lock = final_result.write();
|
match final_result.write() {
|
||||||
|
|
||||||
match get_write_lock {
|
|
||||||
Ok(mut final_result) => {
|
Ok(mut final_result) => {
|
||||||
*final_result = result;
|
*final_result = result;
|
||||||
None
|
None
|
||||||
|
@ -51,39 +51,33 @@ impl BuiltInValue {
|
|||||||
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
|
||||||
}
|
}
|
||||||
BuiltInValue::Fs => FS.get_or_init(|| {
|
BuiltInValue::Fs => FS.get_or_init(|| {
|
||||||
let fs_context = Map::new();
|
let mut fs_context = Map::new();
|
||||||
|
|
||||||
fs_context
|
fs_context.set(
|
||||||
.set(
|
|
||||||
"read".to_string(),
|
"read".to_string(),
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)),
|
Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)),
|
||||||
None,
|
None,
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Value::Map(fs_context)
|
Value::Map(fs_context)
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Json => JSON.get_or_init(|| {
|
BuiltInValue::Json => JSON.get_or_init(|| {
|
||||||
let json_context = Map::new();
|
let mut json_context = Map::new();
|
||||||
|
|
||||||
json_context
|
json_context.set(
|
||||||
.set(
|
|
||||||
"parse".to_string(),
|
"parse".to_string(),
|
||||||
Value::Function(Function::BuiltIn(BuiltInFunction::JsonParse)),
|
Value::Function(Function::BuiltIn(BuiltInFunction::JsonParse)),
|
||||||
None,
|
None,
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
Value::Map(json_context)
|
Value::Map(json_context)
|
||||||
}),
|
}),
|
||||||
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
|
||||||
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
|
||||||
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
BuiltInValue::Random => RANDOM.get_or_init(|| {
|
||||||
let random_context = Map::new();
|
let mut random_context = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut variables = random_context.variables_mut().unwrap();
|
|
||||||
|
|
||||||
for built_in_function in [
|
for built_in_function in [
|
||||||
BuiltInFunction::RandomBoolean,
|
BuiltInFunction::RandomBoolean,
|
||||||
BuiltInFunction::RandomFloat,
|
BuiltInFunction::RandomFloat,
|
||||||
@ -94,18 +88,16 @@ impl BuiltInValue {
|
|||||||
let value = Value::Function(Function::BuiltIn(built_in_function));
|
let value = Value::Function(Function::BuiltIn(built_in_function));
|
||||||
let r#type = built_in_function.r#type();
|
let r#type = built_in_function.r#type();
|
||||||
|
|
||||||
variables.insert(key, (value, r#type));
|
random_context.set(key, value, Some(r#type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Value::Map(random_context)
|
Value::Map(random_context)
|
||||||
}),
|
}),
|
||||||
BuiltInValue::String => STRING.get_or_init(|| {
|
BuiltInValue::String => STRING.get_or_init(|| {
|
||||||
let string_context = Map::new();
|
let mut string_context = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut variables = string_context.variables_mut().unwrap();
|
|
||||||
|
|
||||||
for string_function in string_functions() {
|
for string_function in string_functions() {
|
||||||
let key = string_function.name().to_string();
|
let key = string_function.name().to_string();
|
||||||
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
|
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
|
||||||
@ -113,7 +105,7 @@ impl BuiltInValue {
|
|||||||
)));
|
)));
|
||||||
let r#type = string_function.r#type();
|
let r#type = string_function.r#type();
|
||||||
|
|
||||||
variables.insert(key, (value, r#type));
|
string_context.set(key, value, Some(r#type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +116,7 @@ impl BuiltInValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for BuiltInValue {
|
impl AbstractTree for BuiltInValue {
|
||||||
fn from_syntax_node(_source: &str, node: Node, _context: &Map) -> Result<Self> {
|
fn from_syntax_node(_source: &str, node: Node, _context: &mut Map) -> Result<Self> {
|
||||||
let built_in_value = match node.kind() {
|
let built_in_value = match node.kind() {
|
||||||
"args" => BuiltInValue::Args,
|
"args" => BuiltInValue::Args,
|
||||||
"assert_equal" => BuiltInValue::AssertEqual,
|
"assert_equal" => BuiltInValue::AssertEqual,
|
||||||
@ -140,7 +132,11 @@ impl AbstractTree for BuiltInValue {
|
|||||||
Ok(built_in_value)
|
Ok(built_in_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||||
Ok(self.get().clone())
|
Ok(self.get().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ pub enum Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Expression {
|
impl AbstractTree for Expression {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "expression", node)?;
|
Error::expect_syntax_node(source, "expression", node)?;
|
||||||
|
|
||||||
let child = if node.child(0).unwrap().is_named() {
|
let child = if node.child(0).unwrap().is_named() {
|
||||||
@ -65,27 +65,39 @@ impl AbstractTree for Expression {
|
|||||||
Ok(expression)
|
Ok(expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.run(source, context),
|
Expression::Value(value_node) => value_node.run(_source, _context),
|
||||||
Expression::Identifier(identifier) => identifier.run(source, context),
|
Expression::Identifier(identifier) => identifier.run(_source, _context),
|
||||||
Expression::Math(math) => math.run(source, context),
|
Expression::Math(math) => math.run(_source, _context),
|
||||||
Expression::Logic(logic) => logic.run(source, context),
|
Expression::Logic(logic) => logic.run(_source, _context),
|
||||||
Expression::FunctionCall(function_call) => function_call.run(source, context),
|
Expression::FunctionCall(function_call) => function_call.run(_source, _context),
|
||||||
Expression::Index(index) => index.run(source, context),
|
Expression::Index(index) => index.run(_source, _context),
|
||||||
Expression::Yield(r#yield) => r#yield.run(source, context),
|
Expression::Yield(r#yield) => r#yield.run(_source, _context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(value_node) => value_node.expected_type(context),
|
Expression::Value(value_node) => value_node.check_type(_source, _context),
|
||||||
Expression::Identifier(identifier) => identifier.expected_type(context),
|
Expression::Identifier(identifier) => identifier.check_type(_source, _context),
|
||||||
Expression::Math(math) => math.expected_type(context),
|
Expression::Math(math) => math.check_type(_source, _context),
|
||||||
Expression::Logic(logic) => logic.expected_type(context),
|
Expression::Logic(logic) => logic.check_type(_source, _context),
|
||||||
Expression::FunctionCall(function_call) => function_call.expected_type(context),
|
Expression::FunctionCall(function_call) => function_call.check_type(_source, _context),
|
||||||
Expression::Index(index) => index.expected_type(context),
|
Expression::Index(index) => index.check_type(_source, _context),
|
||||||
Expression::Yield(r#yield) => r#yield.expected_type(context),
|
Expression::Yield(r#yield) => r#yield.check_type(_source, _context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
|
match self {
|
||||||
|
Expression::Value(value_node) => value_node.expected_type(_context),
|
||||||
|
Expression::Identifier(identifier) => identifier.expected_type(_context),
|
||||||
|
Expression::Math(math) => math.expected_type(_context),
|
||||||
|
Expression::Logic(logic) => logic.expected_type(_context),
|
||||||
|
Expression::FunctionCall(function_call) => function_call.expected_type(_context),
|
||||||
|
Expression::Index(index) => index.expected_type(_context),
|
||||||
|
Expression::Yield(r#yield) => r#yield.expected_type(_context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
@ -14,7 +16,7 @@ pub struct For {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for For {
|
impl AbstractTree for For {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "for", node)?;
|
Error::expect_syntax_node(source, "for", node)?;
|
||||||
|
|
||||||
let for_node = node.child(0).unwrap();
|
let for_node = node.child(0).unwrap();
|
||||||
@ -48,32 +50,41 @@ impl AbstractTree for For {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let expression_run = self.collection.run(source, context)?;
|
let expression_run = self.collection.run(source, context)?;
|
||||||
let values = expression_run.as_list()?.items();
|
let values = expression_run.as_list()?.items();
|
||||||
let key = self.item_id.inner();
|
let key = self.item_id.inner();
|
||||||
|
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
|
let context = RwLock::new(context);
|
||||||
|
|
||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
let iter_context = Map::clone_from(context)?;
|
let mut context = match context.write() {
|
||||||
|
Ok(map) => map,
|
||||||
|
Err(error) => return Err(error.into()),
|
||||||
|
};
|
||||||
|
|
||||||
iter_context.set(key.clone(), value.clone(), None)?;
|
context.set(key.clone(), value.clone(), None);
|
||||||
|
self.block.run(source, &mut context).map(|_value| ())
|
||||||
self.block.run(source, &iter_context).map(|_value| ())
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
context.write()?.set(key.clone(), Value::none(), None);
|
||||||
} else {
|
} else {
|
||||||
let loop_context = Map::clone_from(context)?;
|
|
||||||
|
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
loop_context.set(key.clone(), value.clone(), None)?;
|
context.set(key.clone(), value.clone(), None);
|
||||||
|
self.block.run(source, context)?;
|
||||||
self.block.run(source, &loop_context)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.set(key.clone(), Value::none(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,13 @@ impl FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionCall {
|
impl AbstractTree for FunctionCall {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "function_call", node)?;
|
Error::expect_syntax_node(source, "function_call", node)?;
|
||||||
|
|
||||||
let function_node = node.child(0).unwrap();
|
let function_node = node.child(0).unwrap();
|
||||||
let function_expression =
|
let function_expression =
|
||||||
FunctionExpression::from_syntax_node(source, function_node, context)?;
|
FunctionExpression::from_syntax_node(source, function_node, context)?;
|
||||||
let function_type = function_expression.expected_type(context)?;
|
|
||||||
|
|
||||||
let mut minimum_parameter_count = 0;
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
for index in 2..node.child_count() - 1 {
|
for index in 2..node.child_count() - 1 {
|
||||||
@ -35,53 +33,58 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
if child.is_named() {
|
if child.is_named() {
|
||||||
let expression = Expression::from_syntax_node(source, child, context)?;
|
let expression = Expression::from_syntax_node(source, child, context)?;
|
||||||
let expression_type = expression.expected_type(context)?;
|
|
||||||
let argument_index = arguments.len();
|
|
||||||
|
|
||||||
if let Type::Function {
|
|
||||||
parameter_types, ..
|
|
||||||
} = &function_type
|
|
||||||
{
|
|
||||||
if let Some(r#type) = parameter_types.get(argument_index) {
|
|
||||||
if let Type::Option(_) = r#type {
|
|
||||||
} else {
|
|
||||||
minimum_parameter_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
r#type
|
|
||||||
.check(&expression_type)
|
|
||||||
.map_err(|error| error.at_node(child, source))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arguments.push(expression);
|
arguments.push(expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Type::Function {
|
|
||||||
parameter_types: _, ..
|
|
||||||
} = &function_type
|
|
||||||
{
|
|
||||||
if arguments.len() < minimum_parameter_count {
|
|
||||||
return Err(Error::ExpectedFunctionArgumentMinimum {
|
|
||||||
source: source[function_node.byte_range()].to_string(),
|
|
||||||
minumum_expected: minimum_parameter_count,
|
|
||||||
actual: arguments.len(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(FunctionCall {
|
Ok(FunctionCall {
|
||||||
function_expression,
|
function_expression,
|
||||||
arguments,
|
arguments,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
let function_type = self.function_expression.expected_type(context)?;
|
||||||
|
let mut minimum_parameter_count = 0;
|
||||||
|
|
||||||
|
for (index, expression) in self.arguments.iter().enumerate() {
|
||||||
|
if let Type::Function {
|
||||||
|
parameter_types, ..
|
||||||
|
} = &function_type
|
||||||
|
{
|
||||||
|
if let Some(r#type) = parameter_types.get(index) {
|
||||||
|
if let Type::Option(_) = r#type {
|
||||||
|
} else {
|
||||||
|
minimum_parameter_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r#type.check(&expression.expected_type(context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Type::Function {
|
||||||
|
parameter_types: _, ..
|
||||||
|
} = &function_type
|
||||||
|
{
|
||||||
|
if self.arguments.len() < minimum_parameter_count {
|
||||||
|
return Err(Error::ExpectedFunctionArgumentMinimum {
|
||||||
|
source: "TODO".to_string(),
|
||||||
|
minumum_expected: minimum_parameter_count,
|
||||||
|
actual: self.arguments.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let (name, value) = match &self.function_expression {
|
let (name, value) = match &self.function_expression {
|
||||||
FunctionExpression::Identifier(identifier) => {
|
FunctionExpression::Identifier(identifier) => {
|
||||||
let key = identifier.inner();
|
let key = identifier.inner();
|
||||||
let variables = context.variables()?;
|
let variables = context.variables();
|
||||||
|
|
||||||
if let Some((value, _)) = variables.get(key) {
|
if let Some((value, _)) = variables.get(key) {
|
||||||
(Some(key.clone()), value.clone())
|
(Some(key.clone()), value.clone())
|
||||||
@ -108,7 +111,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = &name {
|
if let Some(name) = &name {
|
||||||
context.set(name.to_string(), value.clone(), None)?;
|
context.set(name.to_string(), value.clone(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
value
|
value
|
||||||
|
@ -16,7 +16,7 @@ pub enum FunctionExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for FunctionExpression {
|
impl AbstractTree for FunctionExpression {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "function_expression", node)?;
|
Error::expect_syntax_node(source, "function_expression", node)?;
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
let first_child = node.child(0).unwrap();
|
||||||
@ -54,7 +54,7 @@ impl AbstractTree for FunctionExpression {
|
|||||||
Ok(function_expression)
|
Ok(function_expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
FunctionExpression::Identifier(identifier) => identifier.run(source, context),
|
FunctionExpression::Identifier(identifier) => identifier.run(source, context),
|
||||||
FunctionExpression::FunctionCall(function_call) => function_call.run(source, context),
|
FunctionExpression::FunctionCall(function_call) => function_call.run(source, context),
|
||||||
@ -64,6 +64,10 @@ impl AbstractTree for FunctionExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match self {
|
match self {
|
||||||
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),
|
FunctionExpression::Identifier(identifier) => identifier.expected_type(context),
|
||||||
|
@ -25,7 +25,7 @@ impl Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Identifier {
|
impl AbstractTree for Identifier {
|
||||||
fn from_syntax_node(source: &str, node: Node, _context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, _context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "identifier", node)?;
|
Error::expect_syntax_node(source, "identifier", node)?;
|
||||||
|
|
||||||
let text = &source[node.byte_range()];
|
let text = &source[node.byte_range()];
|
||||||
@ -35,8 +35,12 @@ impl AbstractTree for Identifier {
|
|||||||
Ok(Identifier(text.to_string()))
|
Ok(Identifier(text.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
if let Some((value, _)) = context.variables()?.get(&self.0) {
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, context: &mut Map) -> Result<Value> {
|
||||||
|
if let Some((value, _)) = context.variables().get(&self.0) {
|
||||||
Ok(value.clone())
|
Ok(value.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
Err(Error::VariableIdentifierNotFound(self.inner().clone()))
|
||||||
@ -44,7 +48,7 @@ impl AbstractTree for Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
if let Some((_value, r#type)) = context.variables()?.get(&self.0) {
|
if let Some((_value, r#type)) = context.variables().get(&self.0) {
|
||||||
Ok(r#type.clone())
|
Ok(r#type.clone())
|
||||||
} else {
|
} else {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
|
@ -13,7 +13,7 @@ pub struct IfElse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IfElse {
|
impl AbstractTree for IfElse {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
let if_expression_node = node.child(0).unwrap().child(1).unwrap();
|
let if_expression_node = node.child(0).unwrap().child(1).unwrap();
|
||||||
let if_expression = Expression::from_syntax_node(source, if_expression_node, context)?;
|
let if_expression = Expression::from_syntax_node(source, if_expression_node, context)?;
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ impl AbstractTree for IfElse {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
let if_boolean = self.if_expression.run(source, context)?.as_boolean()?;
|
||||||
|
|
||||||
if if_boolean {
|
if if_boolean {
|
||||||
@ -81,6 +81,10 @@ impl AbstractTree for IfElse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.if_block.expected_type(context)
|
self.if_block.expected_type(context)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub struct Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Index {
|
impl AbstractTree for Index {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "index", node)?;
|
Error::expect_syntax_node(source, "index", node)?;
|
||||||
|
|
||||||
let collection_node = node.child(0).unwrap();
|
let collection_node = node.child(0).unwrap();
|
||||||
@ -41,7 +41,7 @@ impl AbstractTree for Index {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let collection = self.collection.run(source, context)?;
|
let collection = self.collection.run(source, context)?;
|
||||||
|
|
||||||
match collection {
|
match collection {
|
||||||
@ -63,7 +63,7 @@ impl AbstractTree for Index {
|
|||||||
let value = if let IndexExpression::Identifier(identifier) = &self.index {
|
let value = if let IndexExpression::Identifier(identifier) = &self.index {
|
||||||
let key = identifier.inner();
|
let key = identifier.inner();
|
||||||
|
|
||||||
map.variables()?
|
map.variables()
|
||||||
.get(key)
|
.get(key)
|
||||||
.map(|(value, _)| value.clone())
|
.map(|(value, _)| value.clone())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
@ -71,7 +71,7 @@ impl AbstractTree for Index {
|
|||||||
let value = self.index.run(source, context)?;
|
let value = self.index.run(source, context)?;
|
||||||
let key = value.as_string()?;
|
let key = value.as_string()?;
|
||||||
|
|
||||||
map.variables()?
|
map.variables()
|
||||||
.get(key.as_str())
|
.get(key.as_str())
|
||||||
.map(|(value, _)| value.clone())
|
.map(|(value, _)| value.clone())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
@ -89,6 +89,10 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
match self.collection.expected_type(context)? {
|
match self.collection.expected_type(context)? {
|
||||||
Type::List(item_type) => Ok(*item_type.clone()),
|
Type::List(item_type) => Ok(*item_type.clone()),
|
||||||
|
@ -18,7 +18,7 @@ pub enum AssignmentOperator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IndexAssignment {
|
impl AbstractTree for IndexAssignment {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "index_assignment", node)?;
|
Error::expect_syntax_node(source, "index_assignment", node)?;
|
||||||
|
|
||||||
let index_node = node.child(0).unwrap();
|
let index_node = node.child(0).unwrap();
|
||||||
@ -49,9 +49,16 @@ impl AbstractTree for IndexAssignment {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let index_collection = self.index.collection.run(source, context)?;
|
let index_collection = self.index.collection.run(source, context)?;
|
||||||
let index_context = index_collection.as_map().unwrap_or(context);
|
let value = self.statement.run(source, context)?;
|
||||||
|
let mut index_context = if let Value::Map(map) = index_collection {
|
||||||
|
map
|
||||||
|
} else {
|
||||||
|
return Err(Error::ExpectedCollection {
|
||||||
|
actual: index_collection,
|
||||||
|
});
|
||||||
|
};
|
||||||
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
let index_key = if let IndexExpression::Identifier(identifier) = &self.index.index {
|
||||||
identifier.inner()
|
identifier.inner()
|
||||||
} else {
|
} else {
|
||||||
@ -60,12 +67,10 @@ impl AbstractTree for IndexAssignment {
|
|||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = self.statement.run(source, context)?;
|
|
||||||
|
|
||||||
let new_value = match self.operator {
|
let new_value = match self.operator {
|
||||||
AssignmentOperator::PlusEqual => {
|
AssignmentOperator::PlusEqual => {
|
||||||
if let Some((mut previous_value, _)) =
|
if let Some((mut previous_value, _)) =
|
||||||
index_context.variables()?.get(index_key).cloned()
|
index_context.variables().get(index_key).cloned()
|
||||||
{
|
{
|
||||||
previous_value += value;
|
previous_value += value;
|
||||||
previous_value
|
previous_value
|
||||||
@ -75,7 +80,7 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => {
|
AssignmentOperator::MinusEqual => {
|
||||||
if let Some((mut previous_value, _)) =
|
if let Some((mut previous_value, _)) =
|
||||||
index_context.variables()?.get(index_key).cloned()
|
index_context.variables().get(index_key).cloned()
|
||||||
{
|
{
|
||||||
previous_value -= value;
|
previous_value -= value;
|
||||||
previous_value
|
previous_value
|
||||||
@ -86,11 +91,15 @@ impl AbstractTree for IndexAssignment {
|
|||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
|
|
||||||
index_context.set(index_key.clone(), new_value, None)?;
|
index_context.set(index_key.clone(), new_value, None);
|
||||||
|
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ pub enum IndexExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for IndexExpression {
|
impl AbstractTree for IndexExpression {
|
||||||
fn from_syntax_node(source: &str, node: tree_sitter::Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: tree_sitter::Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "index_expression", node)?;
|
Error::expect_syntax_node(source, "index_expression", node)?;
|
||||||
|
|
||||||
let first_child = node.child(0).unwrap();
|
let first_child = node.child(0).unwrap();
|
||||||
@ -48,7 +48,11 @@ impl AbstractTree for IndexExpression {
|
|||||||
Ok(abstract_node)
|
Ok(abstract_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
IndexExpression::Value(value_node) => value_node.run(source, context),
|
IndexExpression::Value(value_node) => value_node.run(source, context),
|
||||||
IndexExpression::Identifier(identifier) => identifier.run(source, context),
|
IndexExpression::Identifier(identifier) => identifier.run(source, context),
|
||||||
|
@ -12,7 +12,7 @@ pub struct Logic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Logic {
|
impl AbstractTree for Logic {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "logic", node)?;
|
Error::expect_syntax_node(source, "logic", node)?;
|
||||||
|
|
||||||
let first_node = node.child(0).unwrap();
|
let first_node = node.child(0).unwrap();
|
||||||
@ -59,7 +59,7 @@ impl AbstractTree for Logic {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
let result = match self.operator {
|
let result = match self.operator {
|
||||||
@ -88,6 +88,10 @@ impl AbstractTree for Logic {
|
|||||||
Ok(Value::Boolean(result))
|
Ok(Value::Boolean(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
||||||
Ok(Type::Boolean)
|
Ok(Type::Boolean)
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ pub struct Match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Match {
|
impl AbstractTree for Match {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "match", node)?;
|
Error::expect_syntax_node(source, "match", node)?;
|
||||||
|
|
||||||
let matcher_node = node.child(1).unwrap();
|
let matcher_node = node.child(1).unwrap();
|
||||||
@ -58,7 +58,7 @@ impl AbstractTree for Match {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let matcher_value = self.matcher.run(source, context)?;
|
let matcher_value = self.matcher.run(source, context)?;
|
||||||
|
|
||||||
for (expression, statement) in &self.options {
|
for (expression, statement) in &self.options {
|
||||||
@ -76,6 +76,10 @@ impl AbstractTree for Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
let (_, first_statement) = self.options.first().unwrap();
|
let (_, first_statement) = self.options.first().unwrap();
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ pub struct Math {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Math {
|
impl AbstractTree for Math {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "math", node)?;
|
Error::expect_syntax_node(source, "math", node)?;
|
||||||
|
|
||||||
let left_node = node.child(0).unwrap();
|
let left_node = node.child(0).unwrap();
|
||||||
@ -48,7 +48,7 @@ impl AbstractTree for Math {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let left = self.left.run(source, context)?;
|
let left = self.left.run(source, context)?;
|
||||||
let right = self.right.run(source, context)?;
|
let right = self.right.run(source, context)?;
|
||||||
let value = match self.operator {
|
let value = match self.operator {
|
||||||
@ -62,6 +62,10 @@ impl AbstractTree for Math {
|
|||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.left.expected_type(context)
|
self.left.expected_type(context)
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ pub struct Root {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Root {
|
impl AbstractTree for Root {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "root", node)?;
|
Error::expect_syntax_node(source, "root", node)?;
|
||||||
|
|
||||||
let statement_count = node.child_count();
|
let statement_count = node.child_count();
|
||||||
@ -59,7 +59,19 @@ impl AbstractTree for Root {
|
|||||||
Ok(Root { statements })
|
Ok(Root { statements })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
for statement in &self.statements {
|
||||||
|
if let Statement::Return(inner_statement) = statement {
|
||||||
|
return inner_statement.check_type(_source, _context);
|
||||||
|
} else {
|
||||||
|
statement.check_type(_source, _context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let mut value = Value::none();
|
let mut value = Value::none();
|
||||||
|
|
||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
@ -90,10 +102,13 @@ pub trait AbstractTree: Sized {
|
|||||||
///
|
///
|
||||||
/// If necessary, the source code can be accessed directly by getting the
|
/// If necessary, the source code can be accessed directly by getting the
|
||||||
/// node's byte range.
|
/// node's byte range.
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self>;
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self>;
|
||||||
|
|
||||||
/// 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: &mut Map) -> Result<Value>;
|
||||||
|
|
||||||
|
/// Verify the type compatibility of this node.
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()>;
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type>;
|
fn expected_type(&self, context: &Map) -> Result<Type>;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ pub enum Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Statement {
|
impl AbstractTree for Statement {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "statement", node)?;
|
Error::expect_syntax_node(source, "statement", node)?;
|
||||||
|
|
||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
@ -66,7 +66,7 @@ impl AbstractTree for Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(assignment) => assignment.run(source, context),
|
Statement::Assignment(assignment) => assignment.run(source, context),
|
||||||
Statement::Expression(expression) => expression.run(source, context),
|
Statement::Expression(expression) => expression.run(source, context),
|
||||||
@ -80,6 +80,22 @@ impl AbstractTree for Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Statement::Assignment(assignment) => assignment.check_type(_source, _context),
|
||||||
|
Statement::Expression(expression) => expression.check_type(_source, _context),
|
||||||
|
Statement::IfElse(if_else) => if_else.check_type(_source, _context),
|
||||||
|
Statement::Match(r#match) => r#match.check_type(_source, _context),
|
||||||
|
Statement::While(r#while) => r#while.check_type(_source, _context),
|
||||||
|
Statement::Block(block) => block.check_type(_source, _context),
|
||||||
|
Statement::For(r#for) => r#for.check_type(_source, _context),
|
||||||
|
Statement::IndexAssignment(index_assignment) => {
|
||||||
|
index_assignment.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
Statement::Return(statement) => statement.check_type(_source, _context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
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),
|
||||||
|
@ -25,7 +25,7 @@ impl TypeDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for TypeDefinition {
|
impl AbstractTree for TypeDefinition {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "type_definition", node)?;
|
Error::expect_syntax_node(source, "type_definition", node)?;
|
||||||
|
|
||||||
let type_node = node.child(1).unwrap();
|
let type_node = node.child(1).unwrap();
|
||||||
@ -34,10 +34,14 @@ impl AbstractTree for TypeDefinition {
|
|||||||
Ok(TypeDefinition { r#type })
|
Ok(TypeDefinition { r#type })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
self.r#type.run(source, context)
|
self.r#type.run(source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
self.r#type.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.r#type.expected_type(context)
|
self.r#type.expected_type(context)
|
||||||
}
|
}
|
||||||
@ -172,7 +176,7 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Type {
|
impl AbstractTree for Type {
|
||||||
fn from_syntax_node(source: &str, node: Node, _context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, _context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "type", node)?;
|
Error::expect_syntax_node(source, "type", node)?;
|
||||||
|
|
||||||
let type_node = node.child(0).unwrap();
|
let type_node = node.child(0).unwrap();
|
||||||
@ -239,7 +243,11 @@ impl AbstractTree for Type {
|
|||||||
Ok(r#type)
|
Ok(r#type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,12 +17,12 @@ pub enum ValueNode {
|
|||||||
String(String),
|
String(String),
|
||||||
List(Vec<Expression>),
|
List(Vec<Expression>),
|
||||||
Option(Option<Box<Expression>>),
|
Option(Option<Box<Expression>>),
|
||||||
Map(BTreeMap<String, (Statement, Option<Type>)>),
|
Map(BTreeMap<Identifier, (Statement, Option<TypeDefinition>)>),
|
||||||
BuiltInValue(BuiltInValue),
|
BuiltInValue(BuiltInValue),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for ValueNode {
|
impl AbstractTree for ValueNode {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "value", node)?;
|
Error::expect_syntax_node(source, "value", node)?;
|
||||||
|
|
||||||
let child = node.child(0).unwrap();
|
let child = node.child(0).unwrap();
|
||||||
@ -53,35 +53,37 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
"map" => {
|
"map" => {
|
||||||
let mut child_nodes = BTreeMap::new();
|
let mut child_nodes = BTreeMap::new();
|
||||||
let mut current_key = "".to_string();
|
let mut current_identifier = None;
|
||||||
let mut current_type = None;
|
let mut current_type = None;
|
||||||
|
|
||||||
for index in 0..child.child_count() - 1 {
|
for index in 0..child.child_count() - 1 {
|
||||||
let child_syntax_node = child.child(index).unwrap();
|
let child_syntax_node = child.child(index).unwrap();
|
||||||
|
|
||||||
if child_syntax_node.kind() == "identifier" {
|
if child_syntax_node.kind() == "identifier" {
|
||||||
current_key =
|
current_identifier = Some(Identifier::from_syntax_node(
|
||||||
Identifier::from_syntax_node(source, child_syntax_node, context)?
|
source,
|
||||||
.take_inner();
|
child_syntax_node,
|
||||||
|
context,
|
||||||
|
)?);
|
||||||
current_type = None;
|
current_type = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if child_syntax_node.kind() == "type_definition" {
|
if child_syntax_node.kind() == "type_definition" {
|
||||||
current_type = Some(
|
current_type = Some(TypeDefinition::from_syntax_node(
|
||||||
TypeDefinition::from_syntax_node(source, child_syntax_node, context)?
|
source,
|
||||||
.take_inner(),
|
child_syntax_node,
|
||||||
);
|
context,
|
||||||
|
)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
if child_syntax_node.kind() == "statement" {
|
if child_syntax_node.kind() == "statement" {
|
||||||
let statement =
|
let statement =
|
||||||
Statement::from_syntax_node(source, child_syntax_node, context)?;
|
Statement::from_syntax_node(source, child_syntax_node, context)?;
|
||||||
|
|
||||||
if let Some(type_definition) = ¤t_type {
|
if let Some(identifier) = ¤t_identifier {
|
||||||
type_definition.check(&statement.expected_type(context)?)?;
|
child_nodes
|
||||||
|
.insert(identifier.clone(), (statement, current_type.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
child_nodes.insert(current_key.clone(), (statement, current_type.clone()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +124,41 @@ impl AbstractTree for ValueNode {
|
|||||||
Ok(value_node)
|
Ok(value_node)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
ValueNode::Function(function) => function.check_type(_source, context)?,
|
||||||
|
ValueNode::List(expression_list) => {
|
||||||
|
for expression in expression_list {
|
||||||
|
expression.check_type(_source, context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueNode::BuiltInValue(built_in_value) => {
|
||||||
|
built_in_value.check_type(_source, context)?
|
||||||
|
}
|
||||||
|
ValueNode::Map(map) => {
|
||||||
|
for (_, (statement, r#type)) in map {
|
||||||
|
statement.check_type(_source, context)?;
|
||||||
|
|
||||||
|
if let Some(type_definition) = r#type {
|
||||||
|
let r#type = type_definition.inner();
|
||||||
|
|
||||||
|
r#type.check_type(_source, context)?;
|
||||||
|
r#type.check(&statement.expected_type(context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ValueNode::Option(option) => {
|
||||||
|
if let Some(expression) = option {
|
||||||
|
expression.check_type(_source, context)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
ValueNode::Boolean(value_source) => Value::Boolean(value_source.parse().unwrap()),
|
||||||
ValueNode::Float(value_source) => Value::Float(value_source.parse().unwrap()),
|
ValueNode::Float(value_source) => Value::Float(value_source.parse().unwrap()),
|
||||||
@ -149,14 +185,17 @@ impl AbstractTree for ValueNode {
|
|||||||
|
|
||||||
Value::Option(option_value)
|
Value::Option(option_value)
|
||||||
}
|
}
|
||||||
ValueNode::Map(key_statement_pairs) => {
|
ValueNode::Map(map_node) => {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
for (key, (statement, r#type)) in key_statement_pairs {
|
for (identifier, (statement, type_definition_option)) in map_node.iter() {
|
||||||
let value = statement.run(source, context)?;
|
let value = statement.run(source, context)?;
|
||||||
|
let type_option = type_definition_option
|
||||||
|
.as_ref()
|
||||||
|
.map(|definition| definition.inner().clone());
|
||||||
|
|
||||||
map.set(key.clone(), value, r#type.clone())?;
|
map.set(identifier.inner().clone(), value, type_option);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ pub struct While {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for While {
|
impl AbstractTree for While {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> crate::Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> crate::Result<Self> {
|
||||||
Error::expect_syntax_node(source, "while", node)?;
|
Error::expect_syntax_node(source, "while", node)?;
|
||||||
|
|
||||||
let expression_node = node.child(1).unwrap();
|
let expression_node = node.child(1).unwrap();
|
||||||
@ -25,7 +25,12 @@ impl AbstractTree for While {
|
|||||||
Ok(While { expression, block })
|
Ok(While { expression, block })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
self.expression.check_type(_source, _context)?;
|
||||||
|
self.block.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
while self.expression.run(source, context)?.as_boolean()? {
|
while self.expression.run(source, context)?.as_boolean()? {
|
||||||
self.block.run(source, context)?;
|
self.block.run(source, context)?;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ pub struct Yield {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Yield {
|
impl AbstractTree for Yield {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "yield", node)?;
|
Error::expect_syntax_node(source, "yield", node)?;
|
||||||
|
|
||||||
let input_node = node.child(0).unwrap();
|
let input_node = node.child(0).unwrap();
|
||||||
@ -44,7 +44,11 @@ impl AbstractTree for Yield {
|
|||||||
Ok(Yield { call })
|
Ok(Yield { call })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, _context: &Map) -> Result<()> {
|
||||||
|
self.call.check_type(_source, _context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
self.call.run(source, context)
|
self.call.run(source, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,21 +6,21 @@ use egui_extras::{Column, TableBuilder};
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct App {
|
pub struct App<'c> {
|
||||||
path: String,
|
path: String,
|
||||||
source: String,
|
source: String,
|
||||||
context: Map,
|
context: Map,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
interpreter: Interpreter,
|
interpreter: Interpreter<'c>,
|
||||||
output: Result<Value>,
|
output: Result<Value>,
|
||||||
error: Option<String>,
|
error: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl<'c> App<'c> {
|
||||||
pub fn new(cc: &eframe::CreationContext<'_>, path: PathBuf) -> Self {
|
pub fn new(cc: &eframe::CreationContext<'_>, path: PathBuf) -> Self {
|
||||||
fn create_app(path: PathBuf) -> App {
|
fn create_app<'c>(path: PathBuf) -> App<'c> {
|
||||||
let context = Map::new();
|
let context = Map::new();
|
||||||
let mut interpreter = Interpreter::new(context.clone());
|
let mut interpreter = Interpreter::new(&mut context);
|
||||||
let read_source = read_to_string(&path);
|
let read_source = read_to_string(&path);
|
||||||
let source = if let Ok(source) = read_source {
|
let source = if let Ok(source) = read_source {
|
||||||
source
|
source
|
||||||
@ -54,7 +54,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl eframe::App for App {
|
impl<'c> eframe::App for App<'c> {
|
||||||
/// Called by the frame work to save state before shutdown.
|
/// Called by the frame work to save state before shutdown.
|
||||||
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
||||||
eframe::set_value(storage, eframe::APP_KEY, self);
|
eframe::set_value(storage, eframe::APP_KEY, self);
|
||||||
@ -171,7 +171,7 @@ fn display_value(value: &Value, ui: &mut egui::Ui) {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.body(|mut body| {
|
.body(|mut body| {
|
||||||
for (key, (value, _)) in map.variables().unwrap().iter() {
|
for (key, (value, _)) in map.variables().iter() {
|
||||||
body.row(20.0, |mut row| {
|
body.row(20.0, |mut row| {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label(key);
|
ui.label(key);
|
||||||
|
@ -87,7 +87,7 @@ impl BuiltInFunction {
|
|||||||
let length = if let Ok(list) = value.as_list() {
|
let length = if let Ok(list) = value.as_list() {
|
||||||
list.items().len()
|
list.items().len()
|
||||||
} else if let Ok(map) = value.as_map() {
|
} else if let Ok(map) = value.as_map() {
|
||||||
map.variables()?.len()
|
map.variables().len()
|
||||||
} else if let Ok(str) = value.as_string() {
|
} else if let Ok(str) = value.as_string() {
|
||||||
str.chars().count()
|
str.chars().count()
|
||||||
} else {
|
} else {
|
||||||
|
@ -18,7 +18,7 @@ use crate::{language, AbstractTree, Error, Map, Result, Root, Value};
|
|||||||
/// assert_eq!(interpret("1 + 2 + 3"), Ok(Value::Integer(6)));
|
/// assert_eq!(interpret("1 + 2 + 3"), Ok(Value::Integer(6)));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn interpret(source: &str) -> Result<Value> {
|
pub fn interpret(source: &str) -> Result<Value> {
|
||||||
interpret_with_context(source, Map::new())
|
interpret_with_context(source, &mut Map::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interpret the given source code with the given context.
|
/// Interpret the given source code with the given context.
|
||||||
@ -27,7 +27,7 @@ pub fn interpret(source: &str) -> Result<Value> {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use dust_lang::*;
|
/// # use dust_lang::*;
|
||||||
/// let context = Map::new();
|
/// let mut context = Map::new();
|
||||||
///
|
///
|
||||||
/// context.set("one".into(), 1.into(), None);
|
/// context.set("one".into(), 1.into(), None);
|
||||||
/// context.set("two".into(), 2.into(), None);
|
/// context.set("two".into(), 2.into(), None);
|
||||||
@ -40,7 +40,7 @@ pub fn interpret(source: &str) -> Result<Value> {
|
|||||||
/// Ok(Value::Integer(10))
|
/// Ok(Value::Integer(10))
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
pub fn interpret_with_context(source: &str, context: Map) -> Result<Value> {
|
pub fn interpret_with_context(source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let mut interpreter = Interpreter::new(context);
|
let mut interpreter = Interpreter::new(context);
|
||||||
let value = interpreter.run(source)?;
|
let value = interpreter.run(source)?;
|
||||||
|
|
||||||
@ -48,15 +48,15 @@ pub fn interpret_with_context(source: &str, context: Map) -> Result<Value> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A source code interpreter for the Dust language.
|
/// A source code interpreter for the Dust language.
|
||||||
pub struct Interpreter {
|
pub struct Interpreter<'c> {
|
||||||
parser: Parser,
|
parser: Parser,
|
||||||
context: Map,
|
context: &'c mut Map,
|
||||||
syntax_tree: Option<TSTree>,
|
syntax_tree: Option<TSTree>,
|
||||||
abstract_tree: Option<Root>,
|
abstract_tree: Option<Root>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interpreter {
|
impl<'c> Interpreter<'c> {
|
||||||
pub fn new(context: Map) -> Self {
|
pub fn new(context: &'c mut Map) -> Self {
|
||||||
let mut parser = Parser::new();
|
let mut parser = Parser::new();
|
||||||
|
|
||||||
parser
|
parser
|
||||||
@ -71,6 +71,14 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn context(&self) -> &Map {
|
||||||
|
&self.context
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn context_mut(&mut self) -> &mut Map {
|
||||||
|
&mut self.context
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self, source: &str) -> Result<()> {
|
pub fn parse(&mut self, source: &str) -> Result<()> {
|
||||||
fn check_for_error(source: &str, node: Node, cursor: &mut TreeCursor) -> Result<()> {
|
fn check_for_error(source: &str, node: Node, cursor: &mut TreeCursor) -> Result<()> {
|
||||||
if node.is_error() {
|
if node.is_error() {
|
||||||
@ -101,21 +109,22 @@ impl Interpreter {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&mut self, source: &str) -> Result<Value> {
|
pub fn run(&'c mut self, source: &str) -> Result<Value> {
|
||||||
self.parse(source)?;
|
self.parse(source)?;
|
||||||
|
|
||||||
self.abstract_tree = if let Some(syntax_tree) = &self.syntax_tree {
|
self.abstract_tree = if let Some(syntax_tree) = &self.syntax_tree {
|
||||||
Some(Root::from_syntax_node(
|
Some(Root::from_syntax_node(
|
||||||
source,
|
source,
|
||||||
syntax_tree.root_node(),
|
syntax_tree.root_node(),
|
||||||
&self.context,
|
self.context,
|
||||||
)?)
|
)?)
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::ParserCancelled);
|
return Err(Error::ParserCancelled);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(abstract_tree) = &self.abstract_tree {
|
if let Some(abstract_tree) = &self.abstract_tree {
|
||||||
abstract_tree.run(source, &self.context)
|
abstract_tree.check_type(source, &self.context)?;
|
||||||
|
abstract_tree.run(source, &mut self.context)
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::none())
|
Ok(Value::none())
|
||||||
}
|
}
|
||||||
@ -129,9 +138,3 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Interpreter {
|
|
||||||
fn default() -> Self {
|
|
||||||
Interpreter::new(Map::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -53,7 +53,7 @@ fn main() {
|
|||||||
"".to_string()
|
"".to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
let context = Map::new();
|
let mut context = Map::new();
|
||||||
|
|
||||||
if let Some(input) = args.input {
|
if let Some(input) = args.input {
|
||||||
context
|
context
|
||||||
@ -72,7 +72,7 @@ fn main() {
|
|||||||
let mut parser = TSParser::new();
|
let mut parser = TSParser::new();
|
||||||
parser.set_language(language()).unwrap();
|
parser.set_language(language()).unwrap();
|
||||||
|
|
||||||
let mut interpreter = Interpreter::new(context);
|
let mut interpreter = Interpreter::new(&mut context);
|
||||||
|
|
||||||
if args.show_syntax_tree {
|
if args.show_syntax_tree {
|
||||||
interpreter.parse(&source).unwrap();
|
interpreter.parse(&source).unwrap();
|
||||||
@ -168,7 +168,7 @@ impl Highlighter for DustReadline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_cli_shell() {
|
fn run_cli_shell() {
|
||||||
let context = Map::new();
|
let mut context = Map::new();
|
||||||
let mut rl: Editor<DustReadline, DefaultHistory> = Editor::new().unwrap();
|
let mut rl: Editor<DustReadline, DefaultHistory> = Editor::new().unwrap();
|
||||||
|
|
||||||
rl.set_helper(Some(DustReadline::new()));
|
rl.set_helper(Some(DustReadline::new()));
|
||||||
@ -185,7 +185,7 @@ fn run_cli_shell() {
|
|||||||
|
|
||||||
rl.add_history_entry(line).unwrap();
|
rl.add_history_entry(line).unwrap();
|
||||||
|
|
||||||
let eval_result = interpret_with_context(line, context.clone());
|
let eval_result = interpret_with_context(line, &mut context);
|
||||||
|
|
||||||
match eval_result {
|
match eval_result {
|
||||||
Ok(value) => println!("{value}"),
|
Ok(value) => println!("{value}"),
|
||||||
|
@ -54,7 +54,7 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Function {
|
impl AbstractTree for Function {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &mut Map) -> Result<Self> {
|
||||||
Error::expect_syntax_node(source, "function", node)?;
|
Error::expect_syntax_node(source, "function", node)?;
|
||||||
|
|
||||||
let child_count = node.child_count();
|
let child_count = node.child_count();
|
||||||
@ -77,26 +77,21 @@ impl AbstractTree for Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let function_context = Map::clone_from(context)?;
|
let mut function_context = Map::clone_from(context)?;
|
||||||
|
|
||||||
for (parameter_name, parameter_type) in parameters.iter().zip(parameter_types.iter()) {
|
for (parameter_name, parameter_type) in parameters.iter().zip(parameter_types.iter()) {
|
||||||
function_context.set(
|
function_context.set(
|
||||||
parameter_name.inner().clone(),
|
parameter_name.inner().clone(),
|
||||||
Value::none(),
|
Value::none(),
|
||||||
Some(parameter_type.clone()),
|
Some(parameter_type.clone()),
|
||||||
)?;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_type_node = node.child(child_count - 2).unwrap();
|
let return_type_node = node.child(child_count - 2).unwrap();
|
||||||
let return_type = TypeDefinition::from_syntax_node(source, return_type_node, context)?;
|
let return_type = TypeDefinition::from_syntax_node(source, return_type_node, context)?;
|
||||||
|
|
||||||
let body_node = node.child(child_count - 1).unwrap();
|
let body_node = node.child(child_count - 1).unwrap();
|
||||||
let body = Block::from_syntax_node(source, body_node, &function_context)?;
|
let body = Block::from_syntax_node(source, body_node, &mut function_context)?;
|
||||||
|
|
||||||
return_type
|
|
||||||
.inner()
|
|
||||||
.check(&body.expected_type(&function_context)?)
|
|
||||||
.map_err(|error| error.at_node(body_node, source))?;
|
|
||||||
|
|
||||||
let r#type = Type::function(parameter_types, return_type.take_inner());
|
let r#type = Type::function(parameter_types, return_type.take_inner());
|
||||||
|
|
||||||
@ -105,7 +100,20 @@ impl AbstractTree for Function {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
fn check_type(&self, _source: &str, context: &Map) -> Result<()> {
|
||||||
|
match self {
|
||||||
|
Function::BuiltIn(_built_in_function) => {}
|
||||||
|
Function::ContextDefined(function) => {
|
||||||
|
function
|
||||||
|
.return_type()
|
||||||
|
.check(&function.body.expected_type(&context)?)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&self, _source: &str, _context: &mut Map) -> Result<Value> {
|
||||||
Ok(Value::Function(self.clone()))
|
Ok(Value::Function(self.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,12 +171,12 @@ impl ContextDefinedFunction {
|
|||||||
outer_context: &Map,
|
outer_context: &Map,
|
||||||
) -> Result<Value> {
|
) -> Result<Value> {
|
||||||
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
|
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
|
||||||
let function_context = Map::clone_from(outer_context)?;
|
let mut function_context = Map::clone_from(outer_context)?;
|
||||||
|
|
||||||
for (identifier, value) in parameter_argument_pairs {
|
for (identifier, value) in parameter_argument_pairs {
|
||||||
let key = identifier.inner().clone();
|
let key = identifier.inner().clone();
|
||||||
|
|
||||||
function_context.set(key, value.clone(), None)?;
|
function_context.set(key, value.clone(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
@ -176,10 +184,10 @@ impl ContextDefinedFunction {
|
|||||||
name,
|
name,
|
||||||
Value::Function(Function::ContextDefined(self.clone())),
|
Value::Function(Function::ContextDefined(self.clone())),
|
||||||
None,
|
None,
|
||||||
)?;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = self.body.run(source, &function_context)?;
|
let return_value = self.body.run(source, &mut function_context)?;
|
||||||
|
|
||||||
Ok(return_value)
|
Ok(return_value)
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct List(Arc<RwLock<Vec<Value>>>);
|
pub struct List(Vec<Value>);
|
||||||
|
|
||||||
impl Default for List {
|
impl Default for List {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -17,23 +16,23 @@ impl Default for List {
|
|||||||
|
|
||||||
impl List {
|
impl List {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
List(Arc::new(RwLock::new(Vec::new())))
|
List(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
List(Arc::new(RwLock::new(Vec::with_capacity(capacity))))
|
List(Vec::with_capacity(capacity))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_items(items: Vec<Value>) -> Self {
|
pub fn with_items(items: Vec<Value>) -> Self {
|
||||||
List(Arc::new(RwLock::new(items)))
|
List(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items(&self) -> RwLockReadGuard<'_, Vec<Value>> {
|
pub fn items(&self) -> &Vec<Value> {
|
||||||
self.0.read().unwrap()
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn items_mut(&self) -> RwLockWriteGuard<'_, Vec<Value>> {
|
pub fn items_mut(&mut self) -> &mut Vec<Value> {
|
||||||
self.0.write().unwrap()
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,19 +40,13 @@ impl Eq for List {}
|
|||||||
|
|
||||||
impl PartialEq for List {
|
impl PartialEq for List {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
let left = self.0.read().unwrap().clone().into_iter();
|
self.0.eq(&other.0)
|
||||||
let right = other.0.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.eq(right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for List {
|
impl Ord for List {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
let left = self.0.read().unwrap().clone().into_iter();
|
self.0.cmp(&other.0)
|
||||||
let right = other.0.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.cmp(right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ use std::{
|
|||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{value::Value, Result, Type};
|
use crate::{value::Value, Result, Type};
|
||||||
@ -19,62 +18,52 @@ use crate::{value::Value, Result, Type};
|
|||||||
/// to one another.
|
/// to one another.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
variables: Arc<RwLock<BTreeMap<String, (Value, Type)>>>,
|
variables: BTreeMap<String, (Value, Type)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map {
|
||||||
/// Creates a new instace.
|
/// Creates a new instace.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Map {
|
Map {
|
||||||
variables: Arc::new(RwLock::new(BTreeMap::new())),
|
variables: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_from(other: &Self) -> Result<Self> {
|
pub fn clone_from(other: &Self) -> Result<Self> {
|
||||||
let mut new_map = BTreeMap::new();
|
let mut variables = BTreeMap::new();
|
||||||
|
|
||||||
for (key, (value, r#type)) in other.variables()?.iter() {
|
for (key, (value, r#type)) in other.variables() {
|
||||||
new_map.insert(key.clone(), (value.clone(), r#type.clone()));
|
variables.insert(key.clone(), (value.clone(), r#type.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Map {
|
Ok(Map { variables })
|
||||||
variables: Arc::new(RwLock::new(new_map)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variables(&self) -> Result<RwLockReadGuard<BTreeMap<String, (Value, Type)>>> {
|
pub fn variables(&self) -> &BTreeMap<String, (Value, Type)> {
|
||||||
Ok(self.variables.read()?)
|
&self.variables
|
||||||
}
|
|
||||||
|
|
||||||
pub fn variables_mut(&self) -> Result<RwLockWriteGuard<BTreeMap<String, (Value, Type)>>> {
|
|
||||||
Ok(self.variables.write()?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(
|
pub fn set(
|
||||||
&self,
|
&mut self,
|
||||||
key: String,
|
key: String,
|
||||||
value: Value,
|
value: Value,
|
||||||
r#type: Option<Type>,
|
r#type: Option<Type>,
|
||||||
) -> Result<Option<(Value, Type)>> {
|
) -> Option<(Value, Type)> {
|
||||||
let value_type = r#type.unwrap_or(value.r#type());
|
let value_type = r#type.unwrap_or(value.r#type());
|
||||||
let previous = self
|
|
||||||
.variables
|
|
||||||
.write()?
|
|
||||||
.insert(key, (value, value_type.clone()));
|
|
||||||
|
|
||||||
Ok(previous)
|
self.variables.insert(key, (value, value_type.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unset_all(&self) -> Result<()> {
|
pub fn unset_all(&mut self) -> Result<()> {
|
||||||
for (_key, (value, r#_type)) in self.variables.write()?.iter_mut() {
|
for (_key, (value, r#_type)) in self.variables.iter_mut() {
|
||||||
*value = Value::none();
|
*value = Value::none();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&self) -> Result<()> {
|
pub fn clear(&mut self) -> Result<()> {
|
||||||
self.variables.write()?.clear();
|
self.variables.clear();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -90,19 +79,13 @@ impl Eq for Map {}
|
|||||||
|
|
||||||
impl PartialEq for Map {
|
impl PartialEq for Map {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
let left = self.variables.read().unwrap().clone().into_iter();
|
self.variables.eq(&other.variables)
|
||||||
let right = other.variables.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.eq(right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Map {
|
impl Ord for Map {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
let left = self.variables.read().unwrap().clone().into_iter();
|
self.variables.cmp(&other.variables)
|
||||||
let right = other.variables.read().unwrap().clone().into_iter();
|
|
||||||
|
|
||||||
left.cmp(right)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,9 +99,7 @@ impl Display for Map {
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f, "{{")?;
|
writeln!(f, "{{")?;
|
||||||
|
|
||||||
let variables = self.variables.read().unwrap().clone().into_iter();
|
for (key, (value, _)) in &self.variables {
|
||||||
|
|
||||||
for (key, (value, _)) in variables {
|
|
||||||
writeln!(f, " {key} = {value}")?;
|
writeln!(f, " {key} = {value}")?;
|
||||||
}
|
}
|
||||||
write!(f, "}}")
|
write!(f, "}}")
|
||||||
@ -130,11 +111,10 @@ impl Serialize for Map {
|
|||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let variables = self.variables.read().unwrap();
|
let mut map = serializer.serialize_map(Some(self.variables.len()))?;
|
||||||
let mut map = serializer.serialize_map(Some(variables.len()))?;
|
|
||||||
|
|
||||||
for (key, (value, _type)) in variables.iter() {
|
for (key, (value, _type)) in &self.variables {
|
||||||
map.serialize_entry(key, value)?;
|
map.serialize_entry(&key, &value)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.end()
|
map.end()
|
||||||
@ -157,14 +137,14 @@ impl<'de> Visitor<'de> for MapVisitor {
|
|||||||
type Value = Map;
|
type Value = Map;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
formatter.write_str("Any valid whale data.")
|
formatter.write_str("Valid map data.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<M>(self, mut access: M) -> std::result::Result<Map, M::Error>
|
fn visit_map<M>(self, mut access: M) -> std::result::Result<Map, M::Error>
|
||||||
where
|
where
|
||||||
M: MapAccess<'de>,
|
M: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
||||||
|
@ -226,7 +226,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the value stored in `self` as `Vec<Value>`, or returns `Err` if `self` is not a `Value::Map`.
|
/// Borrows the value stored in `self` as `&Map`, or returns `Err` if `self` is not a `Value::Map`.
|
||||||
pub fn as_map(&self) -> Result<&Map> {
|
pub fn as_map(&self) -> Result<&Map> {
|
||||||
match self {
|
match self {
|
||||||
Value::Map(map) => Ok(map),
|
Value::Map(map) => Ok(map),
|
||||||
@ -236,7 +236,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Borrows the value stored in `self` as `Function`, or returns `Err` if
|
/// Borrows the value stored in `self` as `&Function`, or returns `Err` if
|
||||||
/// `self` is not a `Value::Function`.
|
/// `self` is not a `Value::Function`.
|
||||||
pub fn as_function(&self) -> Result<&Function> {
|
pub fn as_function(&self) -> Result<&Function> {
|
||||||
match self {
|
match self {
|
||||||
@ -841,10 +841,10 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||||||
where
|
where
|
||||||
M: MapAccess<'de>,
|
M: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
||||||
map.set(key, value, None).unwrap();
|
map.set(key, value, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(map))
|
Ok(Value::Map(map))
|
||||||
|
@ -76,6 +76,19 @@ mod for_loop {
|
|||||||
result
|
result
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn async_modify_value() {
|
||||||
|
let result = interpret(
|
||||||
|
"
|
||||||
|
list = []
|
||||||
|
async for i in [1 2 3] { list += i }
|
||||||
|
length(list)
|
||||||
|
",
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(Ok(Value::Integer(3)), result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod logic {
|
mod logic {
|
||||||
@ -140,27 +153,24 @@ mod value {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map() {
|
fn map() {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("x".to_string(), Value::Integer(1), None).unwrap();
|
map.set("x".to_string(), Value::Integer(1), None);
|
||||||
map.set("foo".to_string(), Value::string("bar".to_string()), None)
|
map.set("foo".to_string(), Value::string("bar".to_string()), None);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
assert_eq!(interpret("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map_types() {
|
fn map_types() {
|
||||||
let map = Map::new();
|
let mut map = Map::new();
|
||||||
|
|
||||||
map.set("x".to_string(), Value::Integer(1), Some(Type::Integer))
|
map.set("x".to_string(), Value::Integer(1), Some(Type::Integer));
|
||||||
.unwrap();
|
|
||||||
map.set(
|
map.set(
|
||||||
"foo".to_string(),
|
"foo".to_string(),
|
||||||
Value::string("bar".to_string()),
|
Value::string("bar".to_string()),
|
||||||
Some(Type::String),
|
Some(Type::String),
|
||||||
)
|
);
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
interpret("{ x <int> = 1, foo <str> = 'bar' }"),
|
interpret("{ x <int> = 1, foo <str> = 'bar' }"),
|
||||||
|
Loading…
Reference in New Issue
Block a user