diff --git a/README.md b/README.md
index 486ec15..01aeaef 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,10 @@ A basic dust program:
Dust can do two (or more) things at the same time with effortless concurrency:
```dust
-async (output 'will this one finish first?')
-async (output 'or will this one?')
+async {
+ (output 'will this one finish first?')
+ (output 'or will this one?')
+}
```
Dust is an interpreted, general purpose language with first class functions. It is *data-oriented*, with extensive tools to manage structured and relational data. Dust also includes built-in tooling to import and export data in a variety of formats, including JSON, TOML, YAML and CSV.
@@ -28,6 +30,7 @@ Dust is an interpreted, general purpose language with first class functions. It
- [Maps](#maps)
- [Tables](#tables)
- [Functions](#functions)
+ - [Concurrency](#concurrency)
- [Implementation](#implementation)
@@ -176,14 +179,22 @@ print = function {
As a language written in Rust, Dust features effortless concurrency anywhere in your code.
```dust
-if (random_integer) % 2 == 0 {
- run {
- (output 1 + 1)
- (output 1 + 1 == 2)
- }
+async {
+ await 1 + 1
}
```
+The **await** keyword can be used in an asnyc block to indicate what value the async block should evaluate to. In this case, we want "data" to be read from a file.
+
+```dust
+data = async {
+ (output "Reading a file...")
+ (read "examples/assets/faithful.csv")
+}
+
+(output data)
+```
+
## Implementation
Dust is formally defined as a Tree Sitter grammar in the tree-sitter-dust module. Tree sitter generates a parser, written in C, from a set of rules defined in Javascript. Dust itself is a rust binary that calls the C parser using FFI.
diff --git a/src/abstract_tree/async.rs b/src/abstract_tree/async.rs
index 142ea37..d84e7e5 100644
--- a/src/abstract_tree/async.rs
+++ b/src/abstract_tree/async.rs
@@ -1,23 +1,60 @@
+use rayon::prelude::*;
use serde::{Deserialize, Serialize};
+use tree_sitter::Node;
-use crate::{AbstractTree, Item};
+use crate::{AbstractTree, Error, Result, Statement, Value, VariableMap};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Async {
- item: Item,
+ statements: Vec,
}
impl AbstractTree for Async {
- fn from_syntax_node(source: &str, node: tree_sitter::Node) -> crate::Result {
+ fn from_syntax_node(source: &str, node: Node) -> Result {
debug_assert_eq!("async", node.kind());
- let item_node = node.child(2).unwrap();
- let item = Item::from_syntax_node(source, item_node)?;
+ let child_count = node.child_count();
+ let mut statements = Vec::with_capacity(child_count);
- Ok(Async { item })
+ for index in 2..child_count - 1 {
+ let child = node.child(index).unwrap();
+
+ let statement = match child.kind() {
+ "statement" => Statement::from_syntax_node(source, child)?,
+ _ => {
+ return Err(Error::UnexpectedSyntaxNode {
+ expected: "comment or statement",
+ actual: child.kind(),
+ location: child.start_position(),
+ relevant_source: source[child.byte_range()].to_string(),
+ })
+ }
+ };
+
+ statements.push(statement);
+ }
+
+ Ok(Async { statements })
}
- fn run(&self, source: &str, context: &mut crate::VariableMap) -> crate::Result {
- self.item.run_parallel(source, context)
+ fn run(&self, source: &str, context: &mut VariableMap) -> Result {
+ let statements = &self.statements;
+
+ statements
+ .into_par_iter()
+ .enumerate()
+ .find_map_last(|(index, statement)| {
+ let mut context = context.clone();
+ let result = statement.run(source, &mut context).unwrap_or_default();
+
+ if index == statements.len() - 1 {
+ Some(result)
+ } else {
+ None
+ }
+ })
+ .ok_or(Error::CustomMessage(
+ "Async block has nothing to run.".to_string(),
+ ))
}
}
diff --git a/src/abstract_tree/item.rs b/src/abstract_tree/item.rs
index 273e774..b311e8e 100644
--- a/src/abstract_tree/item.rs
+++ b/src/abstract_tree/item.rs
@@ -22,13 +22,16 @@ impl Item {
}
pub fn run_parallel(&self, source: &str, context: &mut VariableMap) -> Result {
- self.statements.par_iter().for_each(|statement| {
+ let statements = &self.statements;
+ let run_result = statements.into_par_iter().try_for_each(|statement| {
let mut context = context.clone();
-
- statement.run(source, &mut context);
+ statement.run(source, &mut context).map(|_| ())
});
- Ok(Value::Empty)
+ match run_result {
+ Ok(()) => Ok(Value::Empty),
+ Err(error) => Err(error),
+ }
}
}
diff --git a/tree-sitter-dust b/tree-sitter-dust
index 0f58ea5..cf22950 160000
--- a/tree-sitter-dust
+++ b/tree-sitter-dust
@@ -1 +1 @@
-Subproject commit 0f58ea5a7a05d49d99bbe24b9da03eea5249cbd7
+Subproject commit cf22950b7ee6f40c7840b6af4d7b2dda69f4965b