Implement new built-in values

This commit is contained in:
Jeff 2024-01-01 07:46:47 -05:00
parent f136cafb41
commit 976cb7de3f
16 changed files with 13048 additions and 12393 deletions

62
Cargo.lock generated
View File

@ -367,7 +367,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -396,13 +396,13 @@ checksum = "e1d90cd0b264dfdd8eb5bad0a2c217c1f88fa96a8573f40e7b12de23fb468f46"
[[package]]
name = "async-trait"
version = "0.1.75"
version = "0.1.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98"
checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -574,7 +574,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -671,7 +671,7 @@ dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -1114,7 +1114,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -1135,7 +1135,7 @@ checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -1146,7 +1146,7 @@ checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -2125,7 +2125,7 @@ dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -2221,7 +2221,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -2401,18 +2401,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.71"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8"
checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a"
dependencies = [
"proc-macro2",
]
@ -2656,7 +2656,7 @@ checksum = "5a32af5427251d2e4be14fc151eabe18abb4a7aad5efee7044da9f096c906a43"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -2735,14 +2735,14 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
name = "serde_json"
version = "1.0.108"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9"
dependencies = [
"itoa",
"ryu",
@ -2757,7 +2757,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -2911,9 +2911,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.43"
version = "2.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53"
checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d"
dependencies = [
"proc-macro2",
"quote",
@ -2965,22 +2965,22 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.52"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d"
checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.52"
version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3"
checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -3108,7 +3108,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]
@ -3288,7 +3288,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
"wasm-bindgen-shared",
]
@ -3322,7 +3322,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -3917,7 +3917,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.43",
"syn 2.0.44",
]
[[package]]

View File

@ -30,11 +30,11 @@ make_guess = (cards <map>, current_room <str>) <none> {
} else {
output(
'I question '
+ random(cards:suspects)
+ random:from(cards:suspects)
+ ' in the '
+ current_room
+ ' with the '
+ random(cards:weapons)
+ random:from(cards:weapons)
+ '.'
)
}

View File

@ -1,4 +1,4 @@
data = from_json(read('examples/assets/jq_data.json'))
data = json:parse(fs:read('examples/assets/jq_data.json'))
new_data = []

View File

@ -1,9 +1,9 @@
foo_or_bar = match random_boolean() {
foo_or_bar = match random:boolean() {
true => "foo"
false => "bar"
}
num = match random_integer() {
num = match random:integer() {
1 => "one",
2 => { "two" },
* => "neither",

View File

@ -1,5 +1,5 @@
raw_data = read('examples/assets/seaCreatures.json')
sea_creatures = from_json(raw_data)
raw_data = fs:read('examples/assets/seaCreatures.json')
sea_creatures = json:parse(raw_data)
data = {
creatures = []

3
examples/threads.ds Normal file
View File

@ -0,0 +1,3 @@
handle = thread:spawn("my_thread", {
})

View File

@ -83,8 +83,6 @@ impl AbstractTree for Assignment {
AssignmentOperator::Equal => {}
AssignmentOperator::PlusEqual => {
if let Type::List(item_type) = identifier_type {
println!("{item_type} {statement_type}");
item_type
.check(&statement_type)
.map_err(|error| error.at_node(statement_node, source))?;

View File

@ -6,12 +6,16 @@ use tree_sitter::Node;
use crate::{AbstractTree, BuiltInFunction, Function, List, Map, Result, Type, Value};
static ARGS: OnceLock<Value> = OnceLock::new();
static FS: OnceLock<Value> = OnceLock::new();
static JSON: OnceLock<Value> = OnceLock::new();
static RANDOM: OnceLock<Value> = OnceLock::new();
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInValue {
Args,
AssertEqual,
Fs,
Json,
Length,
Output,
Random,
@ -22,6 +26,8 @@ impl BuiltInValue {
match self {
BuiltInValue::Args => Type::list_of(Type::String),
BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(),
BuiltInValue::Fs => Type::Map,
BuiltInValue::Json => Type::Map,
BuiltInValue::Length => BuiltInFunction::Length.r#type(),
BuiltInValue::Output => BuiltInFunction::Output.r#type(),
BuiltInValue::Random => Type::Map,
@ -38,6 +44,32 @@ impl BuiltInValue {
BuiltInValue::AssertEqual => {
&Value::Function(Function::BuiltIn(BuiltInFunction::AssertEqual))
}
BuiltInValue::Fs => FS.get_or_init(|| {
let fs_context = Map::new();
fs_context
.set(
"read".to_string(),
Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)),
None,
)
.unwrap();
Value::Map(fs_context)
}),
BuiltInValue::Json => JSON.get_or_init(|| {
let json_context = Map::new();
json_context
.set(
"parse".to_string(),
Value::Function(Function::BuiltIn(BuiltInFunction::JsonParse)),
None,
)
.unwrap();
Value::Map(json_context)
}),
BuiltInValue::Length => &Value::Function(Function::BuiltIn(BuiltInFunction::Length)),
BuiltInValue::Output => &Value::Function(Function::BuiltIn(BuiltInFunction::Output)),
BuiltInValue::Random => RANDOM.get_or_init(|| {
@ -46,7 +78,12 @@ impl BuiltInValue {
{
let mut variables = random_context.variables_mut().unwrap();
for built_in_function in [BuiltInFunction::RandomBoolean] {
for built_in_function in [
BuiltInFunction::RandomBoolean,
BuiltInFunction::RandomFloat,
BuiltInFunction::RandomFrom,
BuiltInFunction::RandomInteger,
] {
let key = built_in_function.name().to_string();
let value = Value::Function(Function::BuiltIn(built_in_function));
let r#type = built_in_function.r#type();
@ -66,6 +103,8 @@ impl AbstractTree for BuiltInValue {
let built_in_value = match node.kind() {
"args" => BuiltInValue::Args,
"assert_equal" => BuiltInValue::AssertEqual,
"fs" => BuiltInValue::Fs,
"json" => BuiltInValue::Json,
"length" => BuiltInValue::Length,
"output" => BuiltInValue::Output,
"random" => BuiltInValue::Random,

View File

@ -78,13 +78,13 @@ impl AbstractTree for FunctionCall {
}
fn run(&self, source: &str, context: &Map) -> Result<Value> {
let value = match &self.function_expression {
let (name, value) = match &self.function_expression {
FunctionExpression::Identifier(identifier) => {
let key = identifier.inner();
let variables = context.variables()?;
if let Some((value, _)) = variables.get(key) {
value.clone()
(Some(key.clone()), value.clone())
} else {
return Err(Error::FunctionIdentifierNotFound(
identifier.inner().clone(),
@ -92,11 +92,11 @@ impl AbstractTree for FunctionCall {
}
}
FunctionExpression::FunctionCall(function_call) => {
function_call.run(source, context)?
(None, function_call.run(source, context)?)
}
FunctionExpression::Value(value_node) => value_node.run(source, context)?,
FunctionExpression::Index(index) => index.run(source, context)?,
FunctionExpression::Yield(r#yield) => r#yield.run(source, context)?,
FunctionExpression::Value(value_node) => (None, value_node.run(source, context)?),
FunctionExpression::Index(index) => (None, index.run(source, context)?),
FunctionExpression::Yield(r#yield) => (None, r#yield.run(source, context)?),
};
let mut arguments = Vec::with_capacity(self.arguments.len());
@ -107,7 +107,18 @@ impl AbstractTree for FunctionCall {
arguments.push(value);
}
value.as_function()?.call(&arguments, source, context)
if let Some(name) = &name {
context.set(name.to_string(), value.clone(), None)?;
}
value
.as_function()
.map_err(|error| {
println!("{name:?}");
error
})?
.call(name, &arguments, source, context)
}
fn expected_type(&self, context: &Map) -> Result<Type> {

View File

@ -1,9 +1,6 @@
use std::{
fmt::{self, Display, Formatter},
fs::read_to_string,
};
use std::fs::read_to_string;
use rand::random;
use rand::{random, thread_rng, Rng};
use serde::{Deserialize, Serialize};
use crate::{Error, Map, Result, Type, Value};
@ -12,19 +9,27 @@ use crate::{Error, Map, Result, Type, Value};
pub enum BuiltInFunction {
AssertEqual,
FsRead,
JsonParse,
Length,
Output,
RandomBoolean,
Length,
RandomFloat,
RandomFrom,
RandomInteger,
}
impl BuiltInFunction {
pub fn name(&self) -> &'static str {
match self {
BuiltInFunction::AssertEqual => "assert_equal",
BuiltInFunction::FsRead => "fs_read",
BuiltInFunction::FsRead => "read",
BuiltInFunction::JsonParse => "parse",
BuiltInFunction::Length => "length",
BuiltInFunction::Output => "output",
BuiltInFunction::RandomBoolean => "boolean",
BuiltInFunction::Length => "length",
BuiltInFunction::RandomFloat => "float",
BuiltInFunction::RandomFrom => "from",
BuiltInFunction::RandomInteger => "integer",
}
}
@ -32,9 +37,13 @@ impl BuiltInFunction {
match self {
BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None),
BuiltInFunction::FsRead => Type::function(vec![Type::String], Type::String),
BuiltInFunction::JsonParse => Type::function(vec![Type::String], Type::Any),
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
BuiltInFunction::Output => Type::function(vec![Type::Any], Type::None),
BuiltInFunction::RandomBoolean => Type::function(vec![], Type::Boolean),
BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer),
BuiltInFunction::RandomFloat => Type::function(vec![], Type::Float),
BuiltInFunction::RandomFrom => Type::function(vec![Type::Collection], Type::Any),
BuiltInFunction::RandomInteger => Type::function(vec![], Type::Integer),
}
}
@ -56,19 +65,13 @@ impl BuiltInFunction {
Ok(Value::String(file_content))
}
BuiltInFunction::Output => {
BuiltInFunction::JsonParse => {
Error::expect_argument_amount(self, 1, arguments.len())?;
let value = arguments.first().unwrap();
let string = arguments.first().unwrap().as_string()?;
let value = serde_json::from_str(&string)?;
println!("{value}");
Ok(Value::none())
}
BuiltInFunction::RandomBoolean => {
Error::expect_argument_amount(self, 0, arguments.len())?;
Ok(Value::Boolean(random()))
Ok(value)
}
BuiltInFunction::Length => {
Error::expect_argument_amount(self, 1, arguments.len())?;
@ -88,12 +91,50 @@ impl BuiltInFunction {
Ok(Value::Integer(length as i64))
}
BuiltInFunction::Output => {
Error::expect_argument_amount(self, 1, arguments.len())?;
let value = arguments.first().unwrap();
println!("{value}");
Ok(Value::none())
}
BuiltInFunction::RandomBoolean => {
Error::expect_argument_amount(self, 0, arguments.len())?;
Ok(Value::Boolean(random()))
}
BuiltInFunction::RandomFloat => {
Error::expect_argument_amount(self, 0, arguments.len())?;
Ok(Value::Float(random()))
}
BuiltInFunction::RandomFrom => {
Error::expect_argument_amount(self, 1, arguments.len())?;
let value = arguments.first().unwrap();
if let Ok(list) = value.as_list() {
let items = list.items();
if items.len() == 0 {
Ok(Value::none())
} else {
let random_index = thread_rng().gen_range(0..items.len());
let random_value = items.get(random_index).cloned().unwrap_or_default();
Ok(random_value)
}
} else {
todo!()
}
}
BuiltInFunction::RandomInteger => {
Error::expect_argument_amount(self, 0, arguments.len())?;
Ok(Value::Integer(random()))
}
}
}
}
impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.r#type())
}
}

View File

@ -17,20 +17,28 @@ pub enum Function {
impl Display for Function {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Function::BuiltIn(inner) => write!(f, "{inner}"),
Function::ContextDefined(inner) => write!(f, "{inner}"),
Function::BuiltIn(built_in_function) => write!(f, "{}", built_in_function.r#type()),
Function::ContextDefined(context_defined_function) => {
write!(f, "{}", context_defined_function.r#type())
}
}
}
}
impl Function {
pub fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result<Value> {
pub fn call(
&self,
name: Option<String>,
arguments: &[Value],
source: &str,
outer_context: &Map,
) -> Result<Value> {
match self {
Function::BuiltIn(built_in_function) => {
built_in_function.call(arguments, source, outer_context)
}
Function::ContextDefined(context_defined_function) => {
context_defined_function.call(arguments, source, outer_context)
context_defined_function.call(name, arguments, source, outer_context)
}
}
}
@ -90,15 +98,10 @@ impl AbstractTree for Function {
.check(&body.expected_type(&function_context)?)
.map_err(|error| error.at_node(body_node, source))?;
let r#type = Type::Function {
parameter_types,
return_type: Box::new(return_type.take_inner()),
};
let r#type = Type::function(parameter_types, return_type.take_inner());
Ok(Self::ContextDefined(ContextDefinedFunction::new(
parameters,
body,
Some(r#type),
parameters, body, r#type,
)))
}
@ -122,12 +125,7 @@ pub struct ContextDefinedFunction {
}
impl ContextDefinedFunction {
pub fn new(parameters: Vec<Identifier>, body: Block, r#type: Option<Type>) -> Self {
let r#type = r#type.unwrap_or(Type::Function {
parameter_types: vec![Type::Any; parameters.len()],
return_type: Box::new(Type::Any),
});
pub fn new(parameters: Vec<Identifier>, body: Block, r#type: Type) -> Self {
Self {
parameters,
body,
@ -157,49 +155,32 @@ impl ContextDefinedFunction {
}
}
pub fn call(&self, arguments: &[Value], source: &str, outer_context: &Map) -> Result<Value> {
let context = Map::clone_from(outer_context)?;
pub fn call(
&self,
name: Option<String>,
arguments: &[Value],
source: &str,
outer_context: &Map,
) -> Result<Value> {
let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter());
let function_context = Map::clone_from(outer_context)?;
for (identifier, value) in parameter_argument_pairs {
let key = identifier.inner().clone();
context.set(key, value.clone(), None)?;
function_context.set(key, value.clone(), None)?;
}
let return_value = self.body.run(source, &context)?;
if let Some(name) = name {
function_context.set(
name,
Value::Function(Function::ContextDefined(self.clone())),
None,
)?;
}
let return_value = self.body.run(source, &function_context)?;
Ok(return_value)
}
}
impl Display for ContextDefinedFunction {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "(")?;
let (parameter_types, return_type) = if let Type::Function {
parameter_types,
return_type,
} = &self.r#type
{
(parameter_types, return_type)
} else {
return Err(fmt::Error);
};
for (index, (parameter, r#type)) in self
.parameters
.iter()
.zip(parameter_types.iter())
.enumerate()
{
write!(f, "{} <{}>", parameter.inner(), r#type)?;
if index != self.parameters.len() - 1 {
write!(f, ", ")?;
}
}
write!(f, ") -> {}", return_type)
}
}

View File

@ -514,14 +514,11 @@ mod blocks {
}
}
mod std {
mod built_in_values {
use dust_lang::*;
#[test]
fn load_std() {
assert_eq!(
interpret("std:read"),
Ok(Value::Function(Function::BuiltIn(BuiltInFunction::FsRead)))
);
fn args() {
assert!(interpret("args").is_ok_and(|value| value.is_list()));
}
}

View File

@ -441,6 +441,8 @@ module.exports = grammar({
'args',
'assert_equal',
'env',
'fs',
'json',
'length',
'output',
'random',

View File

@ -1412,6 +1412,14 @@
"type": "STRING",
"value": "env"
},
{
"type": "STRING",
"value": "fs"
},
{
"type": "STRING",
"value": "json"
},
{
"type": "STRING",
"value": "length"

View File

@ -804,6 +804,10 @@
"type": "for",
"named": false
},
{
"type": "fs",
"named": false
},
{
"type": "identifier",
"named": true
@ -824,6 +828,10 @@
"type": "integer",
"named": true
},
{
"type": "json",
"named": false
},
{
"type": "length",
"named": false

File diff suppressed because it is too large Load Diff