1
0
This commit is contained in:
Jeff 2023-11-30 09:48:56 -05:00
parent e90a4d7353
commit 21099a4092
19 changed files with 2952 additions and 3066 deletions

View File

@ -1,7 +1,5 @@
(output "This will print first.") create_random_numbers <fn int> |count| {
mnumbers = [];
create_random_numbers = |count <int>| {
numbers = [];
while (length numbers) < count { while (length numbers) < count {
numbers += (random_integer) numbers += (random_integer)
@ -10,6 +8,8 @@ create_random_numbers = |count <int>| {
(output "Made " + count + " numbers.") (output "Made " + count + " numbers.")
} }
(output "This will print first.")
async { async {
(create_random_numbers 1000) (create_random_numbers 1000)
(create_random_numbers 100) (create_random_numbers 100)

View File

@ -4,25 +4,25 @@ all_cards = {
weapons = ['Rope' 'Lead_Pipe' 'Knife'] weapons = ['Rope' 'Lead_Pipe' 'Knife']
} }
is_ready_to_solve = |cards <map>| <bool> { is_ready_to_solve <fn map -> bool> |cards| {
((length cards:suspects) == 1) ((length cards:suspects) == 1)
&& ((length cards:rooms) == 1) && ((length cards:rooms) == 1)
&& ((length cards:weapons) == 1) && ((length cards:weapons) == 1)
} }
take_turn = |opponent_card <str>, current_room <str>, cards <map>| <map> { take_turn <fn str str map -> map> |opponent_card current_room cards| {
(remove_card opponent_card cards) (remove_card opponent_card cards)
(make_guess current_room cards) (make_guess current_room cards)
cards cards
} }
remove_card = |opponent_card <str>, cards <map>| { remove_card <fn str map> |opponent_card cards| {
cards:rooms -= opponent_card cards:rooms -= opponent_card
cards:suspects -= opponent_card cards:suspects -= opponent_card
cards:weapons -= opponent_card cards:weapons -= opponent_card
} }
make_guess = |current_room <str>, cards <map>| { make_guess <fn str map> |current_room cards| {
if (is_ready_to_solve cards) { if (is_ready_to_solve cards) {
(output 'It was ' (output 'It was '
+ cards:suspects:0 + cards:suspects:0

View File

@ -1,4 +1,4 @@
fib <fn int -> int> = |i| { fib <fn int -> int> |i| {
if i <= 1 { if i <= 1 {
1 1
} else { } else {

View File

@ -1,15 +0,0 @@
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)

View File

@ -1,43 +0,0 @@
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)
test_table = table |number bool| [
[1, true]
[3, true]
]
test_select_where = select |number, bool| from my_table {
text == "a"
}
(assert_equal test_select_where, test_table)
test_table = table |text number bool| [
["a", 1, true]
["b", 2, true]
["a", 3, true]
["c", 4, true]
["d", 5, true]
["e", 6, true]
]
insert into my_table [
["c", 4, true]
["d", 5, true]
["e", 6, true]
]
(assert_equal test_table, my_table)

View File

@ -1,6 +1,6 @@
1 -> (output) 1 -> (output)
add_one = |numbers <list>| <list> { add_one <fn [int] -> [int]> |numbers| {
new_numbers = [] new_numbers = []
for number in numbers { for number in numbers {

View File

@ -192,17 +192,4 @@ mod tests {
assert_eq!(Value::List(List::with_items(vec![Value::Integer(1)])), test); assert_eq!(Value::List(List::with_items(vec![Value::Integer(1)])), test);
} }
#[test]
fn function_assignment() {
let test = evaluate(
"
foobar <fn str -> str> = |text| { 'hi' }
foobar
",
)
.unwrap();
assert_eq!(Value::String("hi".to_string()), test);
}
} }

View File

@ -91,3 +91,26 @@ impl AbstractTree for FunctionCall {
self.function.expected_type(context) self.function.expected_type(context)
} }
} }
#[cfg(test)]
mod tests {
use crate::{evaluate, Value};
#[test]
fn evaluate_function_call() {
assert_eq!(
evaluate(
"
foobar <fn str -> str> |message| { message }
(foobar 'Hiya')
",
),
Ok(Value::String("Hiya".to_string()))
);
}
#[test]
fn evaluate_built_in_function_call() {
assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty));
}
}

View File

@ -100,7 +100,7 @@ mod tests {
fn simple_function_declaration() { fn simple_function_declaration() {
let test = evaluate( let test = evaluate(
" "
fn foo <fn int -> int> = |x| { x } foo <fn int -> int> |x| { x }
(foo 42) (foo 42)
", ",
) )

View File

@ -85,3 +85,65 @@ impl AbstractTree for IfElse {
self.if_block.expected_type(context) self.if_block.expected_type(context)
} }
} }
#[cfg(test)]
mod tests {
use crate::{evaluate, Value};
#[test]
fn evaluate_if() {
assert_eq!(
evaluate("if true { 'true' }"),
Ok(Value::String("true".to_string()))
);
}
#[test]
fn evaluate_if_else() {
assert_eq!(evaluate("if false { 1 } else { 2 }"), Ok(Value::Integer(2)));
assert_eq!(
evaluate("if true { 1.0 } else { 42.0 }"),
Ok(Value::Float(1.0))
);
}
#[test]
fn evaluate_if_else_else_if_else() {
assert_eq!(
evaluate(
"
if false {
'no'
} else if 1 + 1 == 3 {
'nope'
} else {
'ok'
}
"
),
Ok(Value::String("ok".to_string()))
);
}
#[test]
fn evaluate_if_else_if_else_if_else_if_else() {
assert_eq!(
evaluate(
"
if false {
'no'
} else if 1 + 1 == 1 {
'nope'
} else if 9 / 2 == 4 {
'nope'
} else if 'foo' == 'bar' {
'nope'
} else {
'ok'
}
"
),
Ok(Value::String("ok".to_string()))
);
}
}

View File

@ -147,6 +147,12 @@ impl AbstractTree for Type {
let type_node = node.child(0).unwrap(); let type_node = node.child(0).unwrap();
let r#type = match type_node.kind() { let r#type = match type_node.kind() {
"[" => {
let item_type_node = node.child(1).unwrap();
let item_type = Type::from_syntax_node(source, item_type_node, context)?;
Type::List(Box::new(item_type))
}
"any" => Type::Any, "any" => Type::Any,
"bool" => Type::Boolean, "bool" => Type::Boolean,
"float" => Type::Float, "float" => Type::Float,
@ -171,12 +177,6 @@ impl AbstractTree for Type {
} }
} }
"int" => Type::Integer, "int" => Type::Integer,
"list" => {
let item_type_node = node.child(1).unwrap();
let item_type = Type::from_syntax_node(source, item_type_node, context)?;
Type::List(Box::new(item_type))
}
"map" => Type::Map, "map" => Type::Map,
"num" => Type::Number, "num" => Type::Number,
"str" => Type::String, "str" => Type::String,

View File

@ -215,3 +215,68 @@ impl AbstractTree for ValueNode {
Ok(type_definition) Ok(type_definition)
} }
} }
#[cfg(test)]
mod tests {
use crate::{evaluate, List};
use super::*;
#[test]
fn evaluate_empty() {
assert_eq!(evaluate("x = 9"), Ok(Value::Empty));
assert_eq!(evaluate("x = 1 + 1"), Ok(Value::Empty));
}
#[test]
fn evaluate_integer() {
assert_eq!(evaluate("1"), Ok(Value::Integer(1)));
assert_eq!(evaluate("123"), Ok(Value::Integer(123)));
assert_eq!(evaluate("-666"), Ok(Value::Integer(-666)));
}
#[test]
fn evaluate_float() {
assert_eq!(evaluate("0.1"), Ok(Value::Float(0.1)));
assert_eq!(evaluate("12.3"), Ok(Value::Float(12.3)));
assert_eq!(evaluate("-6.66"), Ok(Value::Float(-6.66)));
}
#[test]
fn evaluate_string() {
assert_eq!(evaluate("\"one\""), Ok(Value::String("one".to_string())));
assert_eq!(evaluate("'one'"), Ok(Value::String("one".to_string())));
assert_eq!(evaluate("`one`"), Ok(Value::String("one".to_string())));
assert_eq!(evaluate("`'one'`"), Ok(Value::String("'one'".to_string())));
assert_eq!(evaluate("'`one`'"), Ok(Value::String("`one`".to_string())));
assert_eq!(
evaluate("\"'one'\""),
Ok(Value::String("'one'".to_string()))
);
}
#[test]
fn evaluate_list() {
assert_eq!(
evaluate("[1, 2, 'foobar']"),
Ok(Value::List(List::with_items(vec![
Value::Integer(1),
Value::Integer(2),
Value::String("foobar".to_string()),
])))
);
}
#[test]
fn evaluate_map() {
let map = Map::new();
{
let mut variables = map.variables_mut().unwrap();
variables.insert("x".to_string(), Value::Integer(1));
variables.insert("foo".to_string(), Value::String("bar".to_string()));
}
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
}
}

View File

@ -84,144 +84,3 @@ impl<'c, 's> Interpreter<'c, 's> {
self.syntax_tree.root_node().to_sexp() self.syntax_tree.root_node().to_sexp()
} }
} }
#[cfg(test)]
mod tests {
use crate::{List, Table};
use super::*;
#[test]
fn evaluate_empty() {
assert_eq!(evaluate("x = 9"), Ok(Value::Empty));
assert_eq!(evaluate("x = 1 + 1"), Ok(Value::Empty));
}
#[test]
fn evaluate_integer() {
assert_eq!(evaluate("1"), Ok(Value::Integer(1)));
assert_eq!(evaluate("123"), Ok(Value::Integer(123)));
assert_eq!(evaluate("-666"), Ok(Value::Integer(-666)));
}
#[test]
fn evaluate_float() {
assert_eq!(evaluate("0.1"), Ok(Value::Float(0.1)));
assert_eq!(evaluate("12.3"), Ok(Value::Float(12.3)));
assert_eq!(evaluate("-6.66"), Ok(Value::Float(-6.66)));
}
#[test]
fn evaluate_string() {
assert_eq!(evaluate("\"one\""), Ok(Value::String("one".to_string())));
assert_eq!(evaluate("'one'"), Ok(Value::String("one".to_string())));
assert_eq!(evaluate("`one`"), Ok(Value::String("one".to_string())));
assert_eq!(evaluate("`'one'`"), Ok(Value::String("'one'".to_string())));
assert_eq!(evaluate("'`one`'"), Ok(Value::String("`one`".to_string())));
assert_eq!(
evaluate("\"'one'\""),
Ok(Value::String("'one'".to_string()))
);
}
#[test]
fn evaluate_list() {
assert_eq!(
evaluate("[1, 2, 'foobar']"),
Ok(Value::List(List::with_items(vec![
Value::Integer(1),
Value::Integer(2),
Value::String("foobar".to_string()),
])))
);
}
#[test]
fn evaluate_map() {
let map = Map::new();
{
let mut variables = map.variables_mut().unwrap();
variables.insert("x".to_string(), Value::Integer(1));
variables.insert("foo".to_string(), Value::String("bar".to_string()));
}
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
}
#[test]
fn evaluate_if() {
assert_eq!(
evaluate("if true { 'true' }"),
Ok(Value::String("true".to_string()))
);
}
#[test]
fn evaluate_if_else() {
assert_eq!(evaluate("if false { 1 } else { 2 }"), Ok(Value::Integer(2)));
assert_eq!(
evaluate("if true { 1.0 } else { 42.0 }"),
Ok(Value::Float(1.0))
);
}
#[test]
fn evaluate_if_else_else_if_else() {
assert_eq!(
evaluate(
"
if false {
'no'
} else if 1 + 1 == 3 {
'nope'
} else {
'ok'
}
"
),
Ok(Value::String("ok".to_string()))
);
}
#[test]
fn evaluate_if_else_if_else_if_else_if_else() {
assert_eq!(
evaluate(
"
if false {
'no'
} else if 1 + 1 == 1 {
'nope'
} else if 9 / 2 == 4 {
'nope'
} else if 'foo' == 'bar' {
'nope'
} else {
'ok'
}
"
),
Ok(Value::String("ok".to_string()))
);
}
#[test]
fn evaluate_function_call() {
assert_eq!(
evaluate(
"
foobar <fn str -> str> = |message| { message }
(foobar 'Hiya')
",
),
Ok(Value::String("Hiya".to_string()))
);
}
#[test]
fn evaluate_built_in_function_call() {
assert_eq!(evaluate("(output 'Hiya')"), Ok(Value::Empty));
}
}

View File

@ -95,20 +95,6 @@ fn sea_creatures() {
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]
fn table() {
let file_contents = read_to_string("examples/table.ds").unwrap();
evaluate(&file_contents).unwrap();
}
#[test] #[test]
fn variables() { fn variables() {
let file_contents = read_to_string("examples/variables.ds").unwrap(); let file_contents = read_to_string("examples/variables.ds").unwrap();

View File

@ -341,7 +341,7 @@ module.exports = grammar({
optional(seq('->', $.type)), optional(seq('->', $.type)),
), ),
'int', 'int',
seq('list', $.type), seq('[', $.type, ']'),
'map', 'map',
'num', 'num',
'str', 'str',

View File

@ -1096,11 +1096,15 @@
"members": [ "members": [
{ {
"type": "STRING", "type": "STRING",
"value": "list" "value": "["
}, },
{ {
"type": "SYMBOL", "type": "SYMBOL",
"name": "type" "name": "type"
},
{
"type": "STRING",
"value": "]"
} }
] ]
}, },

View File

@ -748,10 +748,6 @@
"type": "integer", "type": "integer",
"named": true "named": true
}, },
{
"type": "list",
"named": false
},
{ {
"type": "map", "type": "map",
"named": false "named": false

File diff suppressed because it is too large Load Diff