Add async statements

This commit is contained in:
Jeff 2023-10-16 16:48:02 -04:00
parent 4e8d320c77
commit 2ccd28bbf4
8 changed files with 80 additions and 12 deletions

View File

@ -11,9 +11,8 @@ A basic dust program:
Dust can do two (or more) things at the same time with effortless concurrency: Dust can do two (or more) things at the same time with effortless concurrency:
```dust ```dust
(run async (output 'will this one finish first?')
(output 'will this one finish first?') async (output 'or will this one?')
(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. 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.
@ -172,6 +171,19 @@ print = function <input> {
} }
``` ```
### Concurrency
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)
}
}
```
## Implementation ## 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. 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.

View File

@ -1,12 +1,18 @@
suspects = ["White", "Green"];
rooms = ["Library", "Kitchen"]; rooms = ["Library", "Kitchen"];
suspects = ["White", "Green"];
weapons = ["Rope", "Lead Pipe"]; weapons = ["Rope", "Lead Pipe"];
show_card = function <card> {
(remove rooms card)
(remove suspects card)
(remove weapons card)
}
make_guess = function <current_room> { make_guess = function <current_room> {
if (length suspects) == 1 if (length suspects) == 1
&& (length rooms) == 1 && (length rooms) == 1
&& (length weapons) == 1 && (length weapons) == 1
then {
(output 'It was ' (output 'It was '
+ suspects.0 + suspects.0
+ ' in the ' + ' in the '
@ -14,8 +20,8 @@ make_guess = function <current_room> {
+ ' with the ' + ' with the '
+ weapons.0 + weapons.0
+ '!' + '!'
); )
else } else {
(output 'I accuse ' (output 'I accuse '
+ (random suspects) + (random suspects)
+ ' in the ' + ' in the '
@ -24,3 +30,4 @@ make_guess = function <current_room> {
+ (random weapons) + (random weapons)
+ '!') + '!')
} }
}

View File

@ -0,0 +1,23 @@
use serde::{Deserialize, Serialize};
use crate::{AbstractTree, Item};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub struct Async {
item: Item,
}
impl AbstractTree for Async {
fn from_syntax_node(source: &str, node: tree_sitter::Node) -> crate::Result<Self> {
debug_assert_eq!("async", node.kind());
let item_node = node.child(2).unwrap();
let item = Item::from_syntax_node(source, item_node)?;
Ok(Async { item })
}
fn run(&self, source: &str, context: &mut crate::VariableMap) -> crate::Result<crate::Value> {
self.item.run_parallel(source, context)
}
}

View File

@ -1,5 +1,6 @@
//! Top-level unit of Dust code. //! Top-level unit of Dust code.
use rayon::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
@ -19,6 +20,16 @@ impl Item {
pub fn new(statements: Vec<Statement>) -> Self { pub fn new(statements: Vec<Statement>) -> Self {
Self { statements } Self { statements }
} }
pub fn run_parallel(&self, source: &str, context: &mut VariableMap) -> Result<Value> {
self.statements.par_iter().for_each(|statement| {
let mut context = context.clone();
statement.run(source, &mut context);
});
Ok(Value::Empty)
}
} }
impl AbstractTree for Item { impl AbstractTree for Item {

View File

@ -7,6 +7,7 @@
//! examples. //! examples.
pub mod assignment; pub mod assignment;
pub mod r#async;
pub mod expression; pub mod expression;
pub mod function_call; pub mod function_call;
pub mod identifier; pub mod identifier;

View File

@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{ use crate::{
r#while::While, AbstractTree, Assignment, Error, Expression, IfElse, Match, Result, Value, r#async::Async, r#while::While, AbstractTree, Assignment, Error, Expression, IfElse, Match,
VariableMap, Result, Value, VariableMap,
}; };
/// Abstract representation of a statement. /// Abstract representation of a statement.
@ -17,6 +17,7 @@ pub enum Statement {
IfElse(Box<IfElse>), IfElse(Box<IfElse>),
Match(Match), Match(Match),
While(Box<While>), While(Box<While>),
Run(Box<Async>),
} }
impl AbstractTree for Statement { impl AbstractTree for Statement {
@ -41,8 +42,11 @@ impl AbstractTree for Statement {
"while" => Ok(Statement::While(Box::new(While::from_syntax_node( "while" => Ok(Statement::While(Box::new(While::from_syntax_node(
source, child, source, child,
)?))), )?))),
"async" => Ok(Statement::Run(Box::new(Async::from_syntax_node(
source, child,
)?))),
_ => Err(Error::UnexpectedSyntaxNode { _ => Err(Error::UnexpectedSyntaxNode {
expected: "assignment, expression, if...else or tool", expected: "assignment, expression, if...else, while, tool or async",
actual: child.kind(), actual: child.kind(),
location: child.start_position(), location: child.start_position(),
relevant_source: source[child.byte_range()].to_string(), relevant_source: source[child.byte_range()].to_string(),
@ -57,6 +61,7 @@ impl AbstractTree for Statement {
Statement::IfElse(if_else) => if_else.run(source, context), Statement::IfElse(if_else) => if_else.run(source, context),
Statement::Match(r#match) => r#match.run(source, context), Statement::Match(r#match) => r#match.run(source, context),
Statement::While(r#while) => r#while.run(source, context), Statement::While(r#while) => r#while.run(source, context),
Statement::Run(run) => run.run(source, context),
} }
} }
} }

View File

@ -3,13 +3,14 @@ use std::fs::read_to_string;
use rand::{random, thread_rng, Rng}; use rand::{random, thread_rng, Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Error, Result, Table, Value}; use crate::{evaluate, Error, Result, Table, Value};
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
pub enum Tool { pub enum Tool {
Assert, Assert,
AssertEqual, AssertEqual,
Output, Output,
Run,
Read, Read,
Help, Help,
@ -96,6 +97,14 @@ impl Tool {
}); });
} }
} }
Tool::Run => {
Error::expect_tool_argument_amount("run", 1, values.len())?;
let file_path = values[0].as_string()?;
let file_contents = read_to_string(file_path)?;
evaluate(&file_contents)?
}
Tool::Output => { Tool::Output => {
if values.len() != 1 { if values.len() != 1 {
return Err(Error::ExpectedToolArgumentAmount { return Err(Error::ExpectedToolArgumentAmount {

@ -1 +1 @@
Subproject commit b47907ee26b42990e5170ba9521de5ae66d596ef Subproject commit 0f58ea5a7a05d49d99bbe24b9da03eea5249cbd7