Clean up
This commit is contained in:
parent
9828d9c643
commit
020ebd8833
@ -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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
take_turn = |opponent_card, current_room, cards| => {
|
||||
(remove_card opponent_card cards)
|
||||
(make_guess current_room cards)
|
||||
cards
|
||||
}
|
||||
|
||||
{
|
||||
current_room = state:current_room
|
||||
rooms = rooms
|
||||
suspects = suspects
|
||||
weapons = weapons
|
||||
remove_card = |opponent_card cards| => {
|
||||
remove card from cards:rooms {
|
||||
card == opponent_card
|
||||
}
|
||||
remove card from cards:weapons {
|
||||
card == opponent_card
|
||||
}
|
||||
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)))
|
||||
|
@ -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)
|
||||
|
@ -5,7 +5,7 @@ dictionary = {
|
||||
|
||||
(output
|
||||
'Dust is '
|
||||
+ dictionary.dust
|
||||
+ dictionary:dust
|
||||
+ '! The answer is '
|
||||
+ dictionary.answer
|
||||
+ dictionary:answer
|
||||
)
|
||||
|
@ -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()?;
|
||||
|
@ -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());
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 iter_context = Map::clone_from(context)?;
|
||||
|
||||
iter_context
|
||||
.variables_mut()?
|
||||
.insert(key.clone(), value.clone());
|
||||
|
||||
let should_remove = self
|
||||
.predicate
|
||||
.run(source, &mut context.clone())?
|
||||
.run(source, &mut iter_context.clone())?
|
||||
.as_boolean()?;
|
||||
|
||||
if should_remove {
|
||||
should_remove_index = Some(index);
|
||||
let _ = should_remove_index.write()?.insert(index);
|
||||
}
|
||||
|
||||
Ok::<(), Error>(())
|
||||
})?;
|
||||
|
||||
if let Some(index) = should_remove_index {
|
||||
Ok(values.remove(index))
|
||||
let index = should_remove_index.read()?;
|
||||
|
||||
if let Some(index) = *index {
|
||||
Ok(values.items_mut().remove(index))
|
||||
} else {
|
||||
Ok(Value::Empty)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -312,6 +312,7 @@ module.exports = grammar({
|
||||
// General
|
||||
'assert',
|
||||
'assert_equal',
|
||||
'context',
|
||||
'download',
|
||||
'help',
|
||||
'length',
|
||||
|
@ -1315,6 +1315,10 @@
|
||||
"type": "STRING",
|
||||
"value": "assert_equal"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "context"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "download"
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user