Clean up; Complete async
This commit is contained in:
parent
cedf0a8c65
commit
a3db9cb9f2
@ -137,8 +137,6 @@ list = [ 1, 2, 3 ]
|
|||||||
for number in list {
|
for number in list {
|
||||||
(output number + 1)
|
(output number + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
# The original list is left unchanged.
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To create a new list, use a **transform** loop, which modifies the values into a new list without changing the original.
|
To create a new list, use a **transform** loop, which modifies the values into a new list without changing the original.
|
||||||
@ -150,6 +148,10 @@ new_list = transform number in list {
|
|||||||
number - 1
|
number - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list
|
||||||
|
-> filter()
|
||||||
|
-> ()
|
||||||
|
|
||||||
(output new_list)
|
(output new_list)
|
||||||
# Output: [ 0 1 2 ]
|
# Output: [ 0 1 2 ]
|
||||||
|
|
||||||
|
11
examples/async_download.ds
Normal file
11
examples/async_download.ds
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
data = async { {
|
||||||
|
cast = (download "https://api.sampleapis.com/futurama/cast")
|
||||||
|
characters = (download "https://api.sampleapis.com/futurama/characters")
|
||||||
|
episodes = (download "https://api.sampleapis.com/futurama/episodes")
|
||||||
|
} }
|
||||||
|
|
||||||
|
cast_len = (length (from_json data:cast))
|
||||||
|
characters_len = (length (from_json data:characters))
|
||||||
|
episodes_len = (length (from_json data:episodes))
|
||||||
|
|
||||||
|
(output [cast_len, characters_len, episodes_len ])
|
@ -1,44 +1,63 @@
|
|||||||
rooms = ['Library' 'Kitchen']
|
all_rooms = ['Library' 'Kitchen']
|
||||||
suspects = ['White' 'Green']
|
all_suspects = ['White' 'Green']
|
||||||
weapons = ['Rope' 'Lead_Pipe']
|
all_weapons = ['Rope' 'Lead_Pipe']
|
||||||
cards = [rooms suspects weapons]
|
|
||||||
|
|
||||||
take_turn = |current_room opponent_card| => {
|
is_ready_to_solve = |state| => {
|
||||||
(remove_card opponent_card)
|
((length state:suspects) == 1)
|
||||||
(make_guess current_room)
|
&& ((length state:rooms) == 1)
|
||||||
|
&& ((length state:weapons) == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_card = |opponent_card| => {
|
take_turn = |opponent_card state| => {
|
||||||
for card_list in cards {
|
state = (remove_card state opponent_card)
|
||||||
removed = remove card from card_list
|
(make_guess state)
|
||||||
card == opponent_card
|
state
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_card = |state opponent_card| => {
|
||||||
|
rooms = filter card in state:rooms {
|
||||||
|
card != opponent_card
|
||||||
|
}
|
||||||
|
suspects = filter card in state:suspects {
|
||||||
|
card != opponent_card
|
||||||
|
}
|
||||||
|
weapons = filter card in state:weapons {
|
||||||
|
card != opponent_card
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type removed) == 'empty'
|
{
|
||||||
output 'Card not found.'
|
current_room = state:current_room
|
||||||
|
rooms = rooms
|
||||||
|
suspects = suspects
|
||||||
|
weapons = weapons
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
make_guess = |current_room| => {
|
make_guess = |state| => {
|
||||||
if ((length suspects) == 1)
|
if (is_ready_to_solve state) {
|
||||||
&& ((length rooms) == 1)
|
|
||||||
&& ((length weapons) == 1)
|
|
||||||
{
|
|
||||||
(output 'It was '
|
(output 'It was '
|
||||||
+ suspects:0
|
+ state:suspects:0
|
||||||
+ ' in the '
|
+ ' in the '
|
||||||
+ rooms:0
|
+ state:rooms:0
|
||||||
+ ' with the '
|
+ ' with the '
|
||||||
+ weapons:0
|
+ state:weapons:0
|
||||||
+ '!')
|
+ '!')
|
||||||
} else {
|
} else {
|
||||||
(output 'I accuse '
|
(output 'I accuse '
|
||||||
+ (random suspects)
|
+ (random state:suspects)
|
||||||
+ ' in the '
|
+ ' in the '
|
||||||
+ current_room
|
# + state:current_room
|
||||||
+ ' with the '
|
+ ' with the '
|
||||||
+ (random weapons)
|
+ (random state:weapons)
|
||||||
+ '!')
|
+ '!')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(make_guess 'Library')
|
init_state = {
|
||||||
|
current_room = 'Library'
|
||||||
|
rooms = all_rooms
|
||||||
|
suspects = all_suspects
|
||||||
|
weapons = all_weapons
|
||||||
|
}
|
||||||
|
|
||||||
|
(take_turn 'Green' (take_turn 'Kitchen' (take_turn 'Rope' init_state)))
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
numbers = (from_json input)
|
|
||||||
flip_count = 0
|
|
||||||
checksum = 0
|
|
||||||
|
|
||||||
while numbers.0 != 1 {
|
|
||||||
(reverse numbers 0 numbers.0)
|
|
||||||
|
|
||||||
if flip_count % 2 == 0 {
|
|
||||||
checksum += flip_count
|
|
||||||
} else {
|
|
||||||
checksum -= flip_count
|
|
||||||
}
|
|
||||||
|
|
||||||
checksum += flip_count * 1
|
|
||||||
|
|
||||||
flip_count += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
(output numbers)
|
|
||||||
(output flip_count)
|
|
||||||
(output checksum)
|
|
15
examples/select.ds
Normal file
15
examples/select.ds
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
my_table = table |text number bool| [
|
||||||
|
["a", 1, true]
|
||||||
|
["b", 2, true]
|
||||||
|
["a", 3, true]
|
||||||
|
]
|
||||||
|
|
||||||
|
test_table = table |text bool| [
|
||||||
|
["a", true]
|
||||||
|
["b", true]
|
||||||
|
["a", true]
|
||||||
|
]
|
||||||
|
|
||||||
|
test_select = select |text bool| from my_table;
|
||||||
|
|
||||||
|
(assert_equal test_select, test_table)
|
@ -10,11 +10,11 @@ test_table = table |text bool| [
|
|||||||
["a", true]
|
["a", true]
|
||||||
]
|
]
|
||||||
|
|
||||||
test_select = select |text bool| from my_table
|
test_select = select |text bool| from my_table;
|
||||||
|
|
||||||
(assert_equal test_select, test_table)
|
(assert_equal test_select, test_table)
|
||||||
|
|
||||||
test_table = table |text number bool| [
|
test_table = table |number bool| [
|
||||||
[1, true]
|
[1, true]
|
||||||
[3, true]
|
[3, true]
|
||||||
]
|
]
|
||||||
|
@ -29,7 +29,6 @@ impl AbstractTree for Async {
|
|||||||
let mut context = context.clone();
|
let mut context = context.clone();
|
||||||
let result = statement.run(source, &mut context);
|
let result = statement.run(source, &mut context);
|
||||||
|
|
||||||
result.clone().unwrap();
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
Some(result)
|
Some(result)
|
||||||
} else if index == statements.len() - 1 {
|
} else if index == statements.len() - 1 {
|
||||||
|
@ -5,7 +5,7 @@ use crate::{AbstractTree, Result, Statement};
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
|
@ -572,11 +572,8 @@ impl AbstractTree for BuiltInFunction {
|
|||||||
let value = expressions[0].run(source, context)?;
|
let value = expressions[0].run(source, context)?;
|
||||||
let list = value.as_list()?.items();
|
let list = value.as_list()?.items();
|
||||||
|
|
||||||
if list.len() < 2 {
|
if list.len() == 1 {
|
||||||
return Err(Error::ExpectedMinLengthList {
|
return Ok(list.first().cloned().unwrap());
|
||||||
minimum_len: 2,
|
|
||||||
actual_len: list.len(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let range = 0..list.len();
|
let range = 0..list.len();
|
||||||
|
@ -19,13 +19,13 @@ impl AbstractTree for Filter {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let item_id_node = node.child(1).unwrap();
|
let item_id_node = node.child_by_field_name("item_id").unwrap();
|
||||||
let item_id = Identifier::from_syntax_node(source, item_id_node)?;
|
let item_id = Identifier::from_syntax_node(source, item_id_node)?;
|
||||||
|
|
||||||
let collection_node = node.child(3).unwrap();
|
let collection_node = node.child_by_field_name("collection").unwrap();
|
||||||
let collection = Expression::from_syntax_node(source, collection_node)?;
|
let collection = Expression::from_syntax_node(source, collection_node)?;
|
||||||
|
|
||||||
let predicate_node = node.child(5).unwrap();
|
let predicate_node = node.child_by_field_name("predicate").unwrap();
|
||||||
let predicate = Block::from_syntax_node(source, predicate_node)?;
|
let predicate = Block::from_syntax_node(source, predicate_node)?;
|
||||||
|
|
||||||
Ok(Filter {
|
Ok(Filter {
|
||||||
@ -45,6 +45,7 @@ impl AbstractTree for Filter {
|
|||||||
Some(expression) => Some(expression.run(source, context)?.as_integer()? as usize),
|
Some(expression) => Some(expression.run(source, context)?.as_integer()? as usize),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
let loop_context = Map::clone_from(context);
|
||||||
|
|
||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
if let Some(max) = count {
|
if let Some(max) = count {
|
||||||
@ -53,11 +54,16 @@ impl AbstractTree for Filter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut context = Map::new();
|
let mut iter_context = loop_context.clone();
|
||||||
|
|
||||||
context.variables_mut().insert(key.clone(), value.clone());
|
iter_context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(key.clone(), value.clone());
|
||||||
|
|
||||||
let should_include = self.predicate.run(source, &mut context)?.as_boolean()?;
|
let should_include = self
|
||||||
|
.predicate
|
||||||
|
.run(source, &mut iter_context)?
|
||||||
|
.as_boolean()?;
|
||||||
|
|
||||||
if should_include {
|
if should_include {
|
||||||
new_values.items_mut().push(value.clone());
|
new_values.items_mut().push(value.clone());
|
||||||
|
@ -7,9 +7,9 @@ use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Val
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct For {
|
pub struct For {
|
||||||
is_async: bool,
|
is_async: bool,
|
||||||
identifier: Identifier,
|
item_id: Identifier,
|
||||||
expression: Expression,
|
collection: Expression,
|
||||||
item: Block,
|
block: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for For {
|
impl AbstractTree for For {
|
||||||
@ -17,9 +17,10 @@ impl AbstractTree for For {
|
|||||||
let for_node = node.child(0).unwrap();
|
let for_node = node.child(0).unwrap();
|
||||||
let is_async = match for_node.kind() {
|
let is_async = match for_node.kind() {
|
||||||
"for" => false,
|
"for" => false,
|
||||||
|
"async for" => true,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
return Err(Error::UnexpectedSyntaxNode {
|
||||||
expected: "for",
|
expected: "for or async for",
|
||||||
actual: for_node.kind(),
|
actual: for_node.kind(),
|
||||||
location: for_node.start_position(),
|
location: for_node.start_position(),
|
||||||
relevant_source: source[for_node.byte_range()].to_string(),
|
relevant_source: source[for_node.byte_range()].to_string(),
|
||||||
@ -38,32 +39,35 @@ impl AbstractTree for For {
|
|||||||
|
|
||||||
Ok(For {
|
Ok(For {
|
||||||
is_async,
|
is_async,
|
||||||
identifier,
|
item_id: identifier,
|
||||||
expression,
|
collection: expression,
|
||||||
item,
|
block: item,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let expression_run = self.expression.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.identifier.inner();
|
let key = self.item_id.inner();
|
||||||
|
let mut loop_context = Map::clone_from(context);
|
||||||
|
|
||||||
if self.is_async {
|
if self.is_async {
|
||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
let mut iter_context = Map::new();
|
let mut iter_context = loop_context.clone();
|
||||||
|
|
||||||
iter_context
|
iter_context
|
||||||
.variables_mut()
|
.variables_mut()
|
||||||
.insert(key.clone(), value.clone());
|
.insert(key.clone(), value.clone());
|
||||||
|
|
||||||
self.item.run(source, &mut iter_context).map(|_value| ())
|
self.block.run(source, &mut iter_context).map(|_value| ())
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else {
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
context.variables_mut().insert(key.clone(), value.clone());
|
loop_context
|
||||||
|
.variables_mut()
|
||||||
|
.insert(key.clone(), value.clone());
|
||||||
|
|
||||||
self.item.run(source, context)?;
|
self.block.run(source, &mut loop_context)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ impl AbstractTree for FunctionCall {
|
|||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
for index in 1..node.child_count() {
|
for index in 1..node.child_count() {
|
||||||
let child = node.child(index).unwrap();
|
let node = node.child(index).unwrap();
|
||||||
|
|
||||||
if child.is_named() {
|
if node.is_named() {
|
||||||
let expression = Expression::from_syntax_node(source, child)?;
|
let expression = Expression::from_syntax_node(source, node)?;
|
||||||
|
|
||||||
arguments.push(expression);
|
arguments.push(expression);
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,53 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
|
||||||
use crate::{AbstractTree, Block, Expression, Identifier, Map, Result, Value};
|
use crate::{AbstractTree, Block, Error, Expression, Identifier, Map, Result, Value};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Remove {
|
pub struct Remove {
|
||||||
identifier: Identifier,
|
item_id: Identifier,
|
||||||
expression: Expression,
|
collection: Expression,
|
||||||
item: Block,
|
predicate: Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Remove {
|
impl AbstractTree for Remove {
|
||||||
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node) -> Result<Self> {
|
||||||
let identifier_node = node.child(1).unwrap();
|
let identifier_node = node.child(1).unwrap();
|
||||||
let identifier = Identifier::from_syntax_node(source, identifier_node)?;
|
let item_id = Identifier::from_syntax_node(source, identifier_node)?;
|
||||||
|
|
||||||
let expression_node = node.child(3).unwrap();
|
let expression_node = node.child(3).unwrap();
|
||||||
let expression = Expression::from_syntax_node(source, expression_node)?;
|
let collection = Expression::from_syntax_node(source, expression_node)?;
|
||||||
|
|
||||||
let item_node = node.child(4).unwrap();
|
let block_node = node.child(4).unwrap();
|
||||||
let item = Block::from_syntax_node(source, item_node)?;
|
let predicate = Block::from_syntax_node(source, block_node)?;
|
||||||
|
|
||||||
Ok(Remove {
|
Ok(Remove {
|
||||||
identifier,
|
item_id,
|
||||||
expression,
|
collection,
|
||||||
item,
|
predicate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
|
||||||
let expression_run = self.expression.run(source, context)?;
|
let value = self.collection.run(source, context)?;
|
||||||
let values = expression_run.into_inner_list()?;
|
let mut values = value.as_list()?.items_mut();
|
||||||
let key = self.identifier.inner();
|
let key = self.item_id.inner();
|
||||||
let mut sub_context = context.clone();
|
|
||||||
let mut should_remove_index = None;
|
let mut should_remove_index = None;
|
||||||
|
|
||||||
for (index, value) in values.items().iter().enumerate() {
|
values.iter().enumerate().try_for_each(|(index, value)| {
|
||||||
sub_context
|
context.variables_mut().insert(key.clone(), value.clone());
|
||||||
.variables_mut()
|
|
||||||
.insert(key.clone(), value.clone());
|
|
||||||
|
|
||||||
let should_remove = self.item.run(source, &mut sub_context)?.as_boolean()?;
|
let should_remove = self.predicate.run(source, context)?.as_boolean()?;
|
||||||
|
|
||||||
if should_remove {
|
if should_remove {
|
||||||
should_remove_index = Some(index);
|
should_remove_index = Some(index);
|
||||||
|
}
|
||||||
|
|
||||||
match &self.expression {
|
Ok::<(), Error>(())
|
||||||
Expression::Identifier(identifier) => {
|
})?;
|
||||||
sub_context
|
|
||||||
.variables_mut()
|
|
||||||
.insert(identifier.inner().clone(), Value::List(values.clone()));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(index) = should_remove_index {
|
if let Some(index) = should_remove_index {
|
||||||
Ok(values.items_mut().remove(index))
|
Ok(values.remove(index))
|
||||||
} else {
|
} else {
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use crate::{AbstractTree, Block, Expression, Identifier, Map, Result, Table, Val
|
|||||||
pub struct Select {
|
pub struct Select {
|
||||||
identifiers: Vec<Identifier>,
|
identifiers: Vec<Identifier>,
|
||||||
expression: Expression,
|
expression: Expression,
|
||||||
item: Option<Block>,
|
predicate: Option<Block>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for Select {
|
impl AbstractTree for Select {
|
||||||
@ -15,41 +15,32 @@ impl AbstractTree for Select {
|
|||||||
let child_count = node.child_count();
|
let child_count = node.child_count();
|
||||||
let mut identifiers = Vec::new();
|
let mut identifiers = Vec::new();
|
||||||
|
|
||||||
for index in 2..child_count - 4 {
|
let identifier_list = node.child(1).unwrap();
|
||||||
let node = node.child(index).unwrap();
|
|
||||||
|
|
||||||
if node.kind() == "identifier" {
|
for index in 1..identifier_list.child_count() - 1 {
|
||||||
|
let node = identifier_list.child(index).unwrap();
|
||||||
|
|
||||||
|
if node.is_named() {
|
||||||
let identifier = Identifier::from_syntax_node(source, node)?;
|
let identifier = Identifier::from_syntax_node(source, node)?;
|
||||||
identifiers.push(identifier);
|
identifiers.push(identifier);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if node.kind() == ">" {
|
let expression_node = node.child(3).unwrap();
|
||||||
break;
|
let expression = Expression::from_syntax_node(source, expression_node)?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let final_node = node.child(child_count - 1).unwrap();
|
let final_node = node.child(child_count - 1).unwrap();
|
||||||
|
|
||||||
let item = if final_node.kind() == "}" {
|
let predicate = if final_node.kind() == "block" {
|
||||||
let item_node = node.child(child_count - 2).unwrap();
|
Some(Block::from_syntax_node(source, final_node)?)
|
||||||
|
|
||||||
Some(Block::from_syntax_node(source, item_node)?)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let expression_node = if item.is_some() {
|
|
||||||
node.child(child_count - 4).unwrap()
|
|
||||||
} else {
|
|
||||||
node.child(child_count - 1).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let expression = Expression::from_syntax_node(source, expression_node)?;
|
|
||||||
|
|
||||||
Ok(Select {
|
Ok(Select {
|
||||||
identifiers,
|
identifiers,
|
||||||
expression,
|
expression,
|
||||||
item,
|
predicate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +51,7 @@ impl AbstractTree for Select {
|
|||||||
self.identifiers
|
self.identifiers
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|identifierier| identifierier.take_inner())
|
.map(|identifier| identifier.take_inner())
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
old_table.headers().clone()
|
old_table.headers().clone()
|
||||||
@ -99,7 +90,7 @@ impl AbstractTree for Select {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(where_clause) = &self.item {
|
if let Some(where_clause) = &self.predicate {
|
||||||
let should_include = where_clause.run(source, &mut row_context)?.as_boolean()?;
|
let should_include = where_clause.run(source, &mut row_context)?.as_boolean()?;
|
||||||
|
|
||||||
if should_include {
|
if should_include {
|
||||||
|
@ -33,9 +33,13 @@ pub fn evaluate(source: &str) -> Result<Value> {
|
|||||||
/// # use dust_lang::*;
|
/// # use dust_lang::*;
|
||||||
/// let mut context = Map::new();
|
/// let mut context = Map::new();
|
||||||
///
|
///
|
||||||
/// context.set_value("one".into(), 1.into());
|
/// {
|
||||||
/// context.set_value("two".into(), 2.into());
|
/// let mut variables = context.variables_mut();
|
||||||
/// context.set_value("three".into(), 3.into());
|
///
|
||||||
|
/// variables.insert("one".into(), 1.into());
|
||||||
|
/// variables.insert("two".into(), 2.into());
|
||||||
|
/// variables.insert("three".into(), 3.into());
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// let dust_code = "four = 4 one + two + three + four";
|
/// let dust_code = "four = 4 one + two + three + four";
|
||||||
///
|
///
|
||||||
|
@ -9,6 +9,14 @@ fn clue_solver() {
|
|||||||
evaluate(&file_contents).unwrap();
|
evaluate(&file_contents).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn download_async() {
|
||||||
|
let file_contents = read_to_string("examples/download_async.ds").unwrap();
|
||||||
|
|
||||||
|
evaluate(&file_contents).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn fetch() {
|
fn fetch() {
|
||||||
@ -59,6 +67,13 @@ fn remove_loop() {
|
|||||||
evaluate(&file_contents).unwrap();
|
evaluate(&file_contents).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn select() {
|
||||||
|
let file_contents = read_to_string("examples/select.ds").unwrap();
|
||||||
|
|
||||||
|
evaluate(&file_contents).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn table() {
|
fn table() {
|
||||||
let file_contents = read_to_string("examples/table.ds").unwrap();
|
let file_contents = read_to_string("examples/table.ds").unwrap();
|
||||||
|
@ -1,52 +1,47 @@
|
|||||||
==================
|
================================================================================
|
||||||
Full Line Comments
|
Full Line Comments
|
||||||
==================
|
================================================================================
|
||||||
|
|
||||||
not_a_comment
|
not_a_comment
|
||||||
# comment
|
# comment
|
||||||
|
|
||||||
---
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
(root
|
(root
|
||||||
(block
|
(block
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(identifier))))
|
(identifier)))))
|
||||||
(comment))
|
|
||||||
|
|
||||||
==================
|
================================================================================
|
||||||
Partial Line Comments
|
Partial Line Comments
|
||||||
==================
|
================================================================================
|
||||||
|
|
||||||
not_a_comment # comment
|
not_a_comment # comment
|
||||||
|
|
||||||
---
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
(root
|
(root
|
||||||
(block
|
(block
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(identifier))))
|
(identifier)))))
|
||||||
(comment))
|
|
||||||
|
|
||||||
==================
|
================================================================================
|
||||||
Multiline Comments
|
Multiline Comments
|
||||||
==================
|
================================================================================
|
||||||
|
|
||||||
# comment #
|
# comment #
|
||||||
not_a_comment #
|
not_a_comment #
|
||||||
# comment # "not a comment"
|
# comment # "not a comment"
|
||||||
|
|
||||||
---
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
(root
|
(root
|
||||||
(comment)
|
|
||||||
(block
|
(block
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(identifier)))
|
(identifier)))
|
||||||
(comment)
|
|
||||||
(comment)
|
|
||||||
(statement
|
(statement
|
||||||
(expression
|
(expression
|
||||||
(value
|
(value
|
||||||
|
@ -3,7 +3,7 @@ module.exports = grammar({
|
|||||||
|
|
||||||
word: $ => $.identifier,
|
word: $ => $.identifier,
|
||||||
|
|
||||||
extras: $ => [ /\s/, $.comment ],
|
extras: $ => [ /\s/, $._comment ],
|
||||||
|
|
||||||
conflicts: $ => [
|
conflicts: $ => [
|
||||||
[$.block],
|
[$.block],
|
||||||
@ -13,7 +13,7 @@ module.exports = grammar({
|
|||||||
rules: {
|
rules: {
|
||||||
root: $ => repeat1($.block),
|
root: $ => repeat1($.block),
|
||||||
|
|
||||||
comment: $ => /[#][^#\n]*[#|\n]/,
|
_comment: $ => /[#][^#\n]*[#|\n]/,
|
||||||
|
|
||||||
block: $ => choice(
|
block: $ => choice(
|
||||||
repeat1($.statement),
|
repeat1($.statement),
|
||||||
@ -200,7 +200,10 @@ module.exports = grammar({
|
|||||||
),
|
),
|
||||||
|
|
||||||
for: $ => seq(
|
for: $ => seq(
|
||||||
|
choice(
|
||||||
'for',
|
'for',
|
||||||
|
'async for',
|
||||||
|
),
|
||||||
$.identifier,
|
$.identifier,
|
||||||
'in',
|
'in',
|
||||||
$.expression,
|
$.expression,
|
||||||
@ -218,7 +221,7 @@ module.exports = grammar({
|
|||||||
filter: $ => seq(
|
filter: $ => seq(
|
||||||
'filter',
|
'filter',
|
||||||
field('count', optional($.expression)),
|
field('count', optional($.expression)),
|
||||||
field('statement_id', $.identifier),
|
field('item_id', $.identifier),
|
||||||
'in',
|
'in',
|
||||||
field('collection', $.expression),
|
field('collection', $.expression),
|
||||||
field('predicate', $.block),
|
field('predicate', $.block),
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"name": "block"
|
"name": "block"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"comment": {
|
"_comment": {
|
||||||
"type": "PATTERN",
|
"type": "PATTERN",
|
||||||
"value": "[#][^#\\n]*[#|\\n]"
|
"value": "[#][^#\\n]*[#|\\n]"
|
||||||
},
|
},
|
||||||
@ -706,11 +706,20 @@
|
|||||||
},
|
},
|
||||||
"assignment": {
|
"assignment": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "identifier"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "index"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "assignment_operator"
|
"name": "assignment_operator"
|
||||||
@ -873,11 +882,20 @@
|
|||||||
},
|
},
|
||||||
"for": {
|
"for": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
"members": [
|
"members": [
|
||||||
{
|
{
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"value": "for"
|
"value": "for"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "async for"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "identifier"
|
||||||
@ -946,7 +964,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "FIELD",
|
"type": "FIELD",
|
||||||
"name": "statement_id",
|
"name": "item_id",
|
||||||
"content": {
|
"content": {
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "identifier"
|
"name": "identifier"
|
||||||
@ -1428,7 +1446,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "comment"
|
"name": "_comment"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"conflicts": [
|
"conflicts": [
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
"type": "identifier",
|
"type": "identifier",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "index",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "statement",
|
"type": "statement",
|
||||||
"named": true
|
"named": true
|
||||||
@ -170,6 +174,16 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"item_id": {
|
||||||
|
"multiple": false,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "identifier",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"predicate": {
|
"predicate": {
|
||||||
"multiple": false,
|
"multiple": false,
|
||||||
"required": true,
|
"required": true,
|
||||||
@ -179,16 +193,6 @@
|
|||||||
"named": true
|
"named": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"statement_id": {
|
|
||||||
"multiple": false,
|
|
||||||
"required": true,
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"type": "identifier",
|
|
||||||
"named": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -846,6 +850,10 @@
|
|||||||
"type": "async",
|
"type": "async",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "async for",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "bash",
|
"type": "bash",
|
||||||
"named": false
|
"named": false
|
||||||
@ -854,10 +862,6 @@
|
|||||||
"type": "columns",
|
"type": "columns",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "comment",
|
|
||||||
"named": true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "download",
|
"type": "download",
|
||||||
"named": false
|
"named": false
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user