This commit is contained in:
Jeff 2023-11-10 16:24:19 -05:00
parent 9828d9c643
commit 020ebd8833
15 changed files with 4099 additions and 3139 deletions

View File

@ -1,63 +1,57 @@
all_rooms = ['Library' 'Kitchen']
all_suspects = ['White' 'Green']
all_weapons = ['Rope' 'Lead_Pipe']
is_ready_to_solve = |state| => {
((length state:suspects) == 1)
&& ((length state:rooms) == 1)
&& ((length state:weapons) == 1)
all_cards = {
rooms = ['Library' 'Kitchen' 'Conservatory']
suspects = ['White' 'Green' 'Scarlett']
weapons = ['Rope' 'Lead_Pipe' 'Knife']
}
take_turn = |opponent_card state| => {
state = (remove_card state opponent_card)
(make_guess state)
state
is_ready_to_solve = |cards| => {
((length cards:suspects) == 1)
&& ((length cards:rooms) == 1)
&& ((length cards:weapons) == 1)
}
take_turn = |opponent_card, current_room, cards| => {
(remove_card opponent_card cards)
(make_guess current_room cards)
cards
}
remove_card = |state opponent_card| => {
rooms = filter card in state:rooms {
card != opponent_card
remove_card = |opponent_card cards| => {
remove card from cards:rooms {
card == opponent_card
}
suspects = filter card in state:suspects {
card != opponent_card
remove card from cards:weapons {
card == opponent_card
}
weapons = filter card in state:weapons {
card != opponent_card
}
{
current_room = state:current_room
rooms = rooms
suspects = suspects
weapons = weapons
remove card from cards:suspects {
card == opponent_card
}
}
make_guess = |state| => {
if (is_ready_to_solve state) {
make_guess = |current_room cards| => {
if (is_ready_to_solve cards) {
(output 'It was '
+ state:suspects:0
+ cards:suspects:0
+ ' in the '
+ state:rooms:0
+ cards:rooms:0
+ ' with the '
+ state:weapons:0
+ cards:weapons:0
+ '!')
} else {
(output 'I accuse '
+ (random state:suspects)
+ (random cards:suspects)
+ ' in the '
# + state:current_room
+ current_room
+ ' with the '
+ (random state:weapons)
+ (random cards:weapons)
+ '!')
}
}
init_state = {
current_room = 'Library'
rooms = all_rooms
suspects = all_suspects
weapons = all_weapons
}
(take_turn 'Rope' 'Kitchen'
(take_turn 'Library' 'Kitchen'
(take_turn 'Conservatory' 'Kitchen'
(take_turn 'White' 'Kitchen'
(take_turn 'Green' 'Kitchen'
(take_turn 'Knife' 'Kitchen' all_cards))))))
(take_turn 'Green' (take_turn 'Kitchen' (take_turn 'Rope' init_state)))

View File

@ -1,7 +1,7 @@
numbers = [1, 2, 3]
x = numbers.{0}
y = numbers.{1}
z = numbers.{2}
x = numbers:0
y = numbers:1
z = numbers:2
(assert_equal x + y, z)

View File

@ -5,7 +5,7 @@ dictionary = {
(output
'Dust is '
+ dictionary.dust
+ dictionary:dust
+ '! The answer is '
+ dictionary.answer
+ dictionary:answer
)

View File

@ -19,6 +19,7 @@ pub enum BuiltInFunction {
Assert(Vec<Expression>),
AssertEqual(Vec<Expression>),
Download(Expression),
Context,
Help(Option<Expression>),
Length(Expression),
Output(Vec<Expression>),
@ -93,6 +94,7 @@ impl AbstractTree for BuiltInFunction {
BuiltInFunction::AssertEqual(expressions)
}
"context" => BuiltInFunction::Context,
"download" => {
let expression_node = node.child(1).unwrap();
let expression = Expression::from_syntax_node(source, expression_node)?;
@ -306,6 +308,7 @@ impl AbstractTree for BuiltInFunction {
Ok(Value::Empty)
}
BuiltInFunction::Context => Ok(Value::Map(context.clone())),
BuiltInFunction::Download(expression) => {
let value = expression.run(source, context)?;
let url = value.as_string()?;

View File

@ -32,12 +32,14 @@ impl AbstractTree for Find {
let value = self.expression.run(source, context)?;
let values = value.as_list()?.items();
let key = self.identifier.inner();
let mut loop_context = Map::clone_from(context)?;
let mut variables = context.variables_mut()?;
for value in values.iter() {
variables.insert(key.clone(), value.clone());
let should_return = self.item.run(source, &mut context.clone())?.as_boolean()?;
let should_return = self.item.run(source, &mut loop_context)?.as_boolean()?;
if should_return {
return Ok(value.clone());

View File

@ -49,11 +49,10 @@ impl AbstractTree for For {
let expression_run = self.collection.run(source, context)?;
let values = expression_run.as_list()?.items();
let key = self.item_id.inner();
let loop_context = Map::clone_from(context)?;
if self.is_async {
values.par_iter().try_for_each(|value| {
let mut iter_context = loop_context.clone();
let mut iter_context = Map::clone_from(context)?;
iter_context
.variables_mut()?
@ -62,10 +61,12 @@ impl AbstractTree for For {
self.block.run(source, &mut iter_context).map(|_value| ())
})?;
} else {
let mut variables = loop_context.variables_mut()?;
let loop_context = Map::clone_from(context)?;
for value in values.iter() {
variables.insert(key.clone(), value.clone());
loop_context
.variables_mut()?
.insert(key.clone(), value.clone());
self.block.run(source, &mut loop_context.clone())?;
}
@ -74,3 +75,4 @@ impl AbstractTree for For {
Ok(Value::Empty)
}
}

View File

@ -50,8 +50,17 @@ impl AbstractTree for Index {
Ok(item)
}
Value::Map(mut map) => {
let value = self.index.run(source, &mut map)?;
Value::Map(map) => {
let value = if let Expression::Identifier(identifier) = &self.index {
let key = identifier.inner();
map.variables()?.get(key).cloned().unwrap_or(Value::Empty)
} else {
let value = self.index.run(source, context)?;
let key = value.as_string()?;
map.variables()?.get(key).cloned().unwrap_or(Value::Empty)
};
Ok(value)
}
@ -65,3 +74,30 @@ impl AbstractTree for Index {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::evaluate;
#[test]
fn evaluate_list_index() {
let test = evaluate("x = [1 [2] 3] x:1:0").unwrap();
assert_eq!(Value::Integer(2), test);
}
#[test]
fn evaluate_map_index() {
let test = evaluate("x = {y = {z = 2}} x:y:z").unwrap();
assert_eq!(Value::Integer(2), test);
}
#[test]
fn evaluate_complex_index() {
let test = evaluate("{x = [1 2 3]; y = || => {0}; x:((y));}").unwrap();
assert_eq!(Value::Integer(1), test);
}
}

View File

@ -1,3 +1,6 @@
use std::sync::RwLock;
use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use tree_sitter::Node;
@ -30,28 +33,41 @@ impl AbstractTree for Remove {
fn run(&self, source: &str, context: &mut Map) -> Result<Value> {
let value = self.collection.run(source, context)?;
let mut values = value.as_list()?.items_mut();
let values = value.as_list()?;
let key = self.item_id.inner();
let mut should_remove_index = None;
let mut variables = context.variables_mut()?;
let should_remove_index = RwLock::new(None);
values.iter().enumerate().try_for_each(|(index, value)| {
variables.insert(key.clone(), value.clone());
values
.items()
.par_iter()
.enumerate()
.try_for_each(|(index, value)| {
if should_remove_index.read()?.is_some() {
return Ok(());
}
let should_remove = self
.predicate
.run(source, &mut context.clone())?
.as_boolean()?;
let iter_context = Map::clone_from(context)?;
if should_remove {
should_remove_index = Some(index);
}
iter_context
.variables_mut()?
.insert(key.clone(), value.clone());
Ok::<(), Error>(())
})?;
let should_remove = self
.predicate
.run(source, &mut iter_context.clone())?
.as_boolean()?;
if let Some(index) = should_remove_index {
Ok(values.remove(index))
if should_remove {
let _ = should_remove_index.write()?.insert(index);
}
Ok::<(), Error>(())
})?;
let index = should_remove_index.read()?;
if let Some(index) = *index {
Ok(values.items_mut().remove(index))
} else {
Ok(Value::Empty)
}

View File

@ -61,12 +61,13 @@ impl AbstractTree for Select {
for row in old_table.rows() {
let mut new_row = Vec::new();
let row_context = Map::new();
let mut row_variables = row_context.variables_mut()?;
for (i, value) in row.iter().enumerate() {
let column_name = old_table.headers().get(i).unwrap();
row_variables.insert(column_name.clone(), value.clone());
row_context
.variables_mut()?
.insert(column_name.clone(), value.clone());
let new_table_column_index =
new_table

View File

@ -36,20 +36,16 @@ impl AbstractTree for Transform {
let new_values = values
.par_iter()
.map(|value| {
let iter_context = Map::new();
let mut iter_variables = match iter_context.variables_mut() {
Ok(variables) => variables,
Err(_) => return Value::Empty,
};
let iter_context = Map::clone_from(context).unwrap();
iter_variables.insert(key.clone(), value.clone());
iter_context
.variables_mut()
.unwrap()
.insert(key.clone(), value.clone());
let item_run = self.item.run(source, &mut iter_context.clone());
match item_run {
Ok(value) => value,
Err(_) => Value::Empty,
}
self.item
.run(source, &mut iter_context.clone())
.unwrap_or_default()
})
.filter(|value| !value.is_empty())
.collect();

View File

@ -3,16 +3,23 @@ use std::fs::read_to_string;
use dust_lang::*;
#[test]
fn clue_solver() {
let file_contents = read_to_string("examples/clue_solver.ds").unwrap();
fn r#async() {
let file_contents = read_to_string("examples/async.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
#[ignore]
fn download_async() {
let file_contents = read_to_string("examples/download_async.ds").unwrap();
fn async_download() {
let file_contents = read_to_string("examples/async_download.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn clue_solver() {
let file_contents = read_to_string("examples/clue_solver.ds").unwrap();
evaluate(&file_contents).unwrap();
}
@ -32,6 +39,13 @@ fn fibonacci() {
evaluate(&file_contents).unwrap();
}
#[test]
fn filter_loop() {
let file_contents = read_to_string("examples/filter_loop.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn find_loop() {
let file_contents = read_to_string("examples/find_loop.ds").unwrap();
@ -60,6 +74,34 @@ fn hello_world() {
evaluate(&file_contents).unwrap();
}
#[test]
fn jq_data() {
let file_contents = read_to_string("examples/jq_data.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn list() {
let file_contents = read_to_string("examples/list.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn map() {
let file_contents = read_to_string("examples/map.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn random() {
let file_contents = read_to_string("examples/random.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn remove_loop() {
let file_contents = read_to_string("examples/remove_loop.ds").unwrap();
@ -67,6 +109,13 @@ fn remove_loop() {
evaluate(&file_contents).unwrap();
}
#[test]
fn sea_creatures() {
let file_contents = read_to_string("examples/sea_creatures.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test]
fn select() {
let file_contents = read_to_string("examples/select.ds").unwrap();
@ -101,3 +150,10 @@ fn while_loop() {
evaluate(&file_contents).unwrap();
}
#[test]
fn r#yield() {
let file_contents = read_to_string("examples/yield.ds").unwrap();
evaluate(&file_contents).unwrap();
}

View File

@ -312,6 +312,7 @@ module.exports = grammar({
// General
'assert',
'assert_equal',
'context',
'download',
'help',
'length',

View File

@ -1315,6 +1315,10 @@
"type": "STRING",
"value": "assert_equal"
},
{
"type": "STRING",
"value": "context"
},
{
"type": "STRING",
"value": "download"

View File

@ -858,6 +858,10 @@
"type": "columns",
"named": false
},
{
"type": "context",
"named": false
},
{
"type": "download",
"named": false

File diff suppressed because it is too large Load Diff