Begin adding string functions

This commit is contained in:
Jeff 2024-01-01 08:52:25 -05:00
parent 976cb7de3f
commit c2d919957e
10 changed files with 12468 additions and 12473 deletions

21
Cargo.lock generated
View File

@ -946,6 +946,7 @@ dependencies = [
"eframe", "eframe",
"egui", "egui",
"egui_extras", "egui_extras",
"enum-iterator",
"env_logger", "env_logger",
"getrandom", "getrandom",
"libc", "libc",
@ -1096,6 +1097,26 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
[[package]]
name = "enum-iterator"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.44",
]
[[package]] [[package]]
name = "enum-map" name = "enum-map"
version = "2.7.3" version = "2.7.3"

View File

@ -38,6 +38,7 @@ serde_json = "1.0.107"
toml = "0.8.1" toml = "0.8.1"
tree-sitter = "0.20.10" tree-sitter = "0.20.10"
egui_extras = "0.24.2" egui_extras = "0.24.2"
enum-iterator = "1.4.1"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
env_logger = "0.10" env_logger = "0.10"

View File

@ -3,12 +3,16 @@ use std::{env::args, sync::OnceLock};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::Node; use tree_sitter::Node;
use crate::{AbstractTree, BuiltInFunction, Function, List, Map, Result, Type, Value}; use crate::{
built_in_functions::{string_functions, StringFunction},
AbstractTree, BuiltInFunction, Function, List, Map, Result, Type, Value,
};
static ARGS: OnceLock<Value> = OnceLock::new(); static ARGS: OnceLock<Value> = OnceLock::new();
static FS: OnceLock<Value> = OnceLock::new(); static FS: OnceLock<Value> = OnceLock::new();
static JSON: OnceLock<Value> = OnceLock::new(); static JSON: OnceLock<Value> = OnceLock::new();
static RANDOM: OnceLock<Value> = OnceLock::new(); static RANDOM: OnceLock<Value> = OnceLock::new();
static STRING: OnceLock<Value> = OnceLock::new();
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInValue { pub enum BuiltInValue {
@ -19,6 +23,7 @@ pub enum BuiltInValue {
Length, Length,
Output, Output,
Random, Random,
String,
} }
impl BuiltInValue { impl BuiltInValue {
@ -31,6 +36,7 @@ impl BuiltInValue {
BuiltInValue::Length => BuiltInFunction::Length.r#type(), BuiltInValue::Length => BuiltInFunction::Length.r#type(),
BuiltInValue::Output => BuiltInFunction::Output.r#type(), BuiltInValue::Output => BuiltInFunction::Output.r#type(),
BuiltInValue::Random => Type::Map, BuiltInValue::Random => Type::Map,
BuiltInValue::String => Type::Map,
} }
} }
@ -94,6 +100,25 @@ impl BuiltInValue {
Value::Map(random_context) Value::Map(random_context)
}), }),
BuiltInValue::String => STRING.get_or_init(|| {
let string_context = Map::new();
{
let mut variables = string_context.variables_mut().unwrap();
for string_function in [StringFunction::AsBytes] {
let key = string_function.name().to_string();
let value = Value::Function(Function::BuiltIn(BuiltInFunction::String(
string_function,
)));
let r#type = string_function.r#type();
variables.insert(key, (value, r#type));
}
}
Value::Map(string_context)
}),
} }
} }
} }
@ -108,6 +133,7 @@ impl AbstractTree for BuiltInValue {
"length" => BuiltInValue::Length, "length" => BuiltInValue::Length,
"output" => BuiltInValue::Output, "output" => BuiltInValue::Output,
"random" => BuiltInValue::Random, "random" => BuiltInValue::Random,
"string" => BuiltInValue::String,
_ => todo!(), _ => todo!(),
}; };

View File

@ -1,3 +1,5 @@
mod string;
use std::fs::read_to_string; use std::fs::read_to_string;
use rand::{random, thread_rng, Rng}; use rand::{random, thread_rng, Rng};
@ -5,6 +7,8 @@ use serde::{Deserialize, Serialize};
use crate::{Error, Map, Result, Type, Value}; use crate::{Error, Map, Result, Type, Value};
pub use string::{string_functions, StringFunction};
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum BuiltInFunction { pub enum BuiltInFunction {
AssertEqual, AssertEqual,
@ -16,6 +20,7 @@ pub enum BuiltInFunction {
RandomFloat, RandomFloat,
RandomFrom, RandomFrom,
RandomInteger, RandomInteger,
String(StringFunction),
} }
impl BuiltInFunction { impl BuiltInFunction {
@ -30,6 +35,7 @@ impl BuiltInFunction {
BuiltInFunction::RandomFloat => "float", BuiltInFunction::RandomFloat => "float",
BuiltInFunction::RandomFrom => "from", BuiltInFunction::RandomFrom => "from",
BuiltInFunction::RandomInteger => "integer", BuiltInFunction::RandomInteger => "integer",
BuiltInFunction::String(string_function) => string_function.name(),
} }
} }
@ -44,13 +50,14 @@ impl BuiltInFunction {
BuiltInFunction::RandomFloat => Type::function(vec![], Type::Float), BuiltInFunction::RandomFloat => Type::function(vec![], Type::Float),
BuiltInFunction::RandomFrom => Type::function(vec![Type::Collection], Type::Any), BuiltInFunction::RandomFrom => Type::function(vec![Type::Collection], Type::Any),
BuiltInFunction::RandomInteger => Type::function(vec![], Type::Integer), BuiltInFunction::RandomInteger => Type::function(vec![], Type::Integer),
BuiltInFunction::String(string_function) => string_function.r#type(),
} }
} }
pub fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> { pub fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> {
match self { match self {
BuiltInFunction::AssertEqual => { BuiltInFunction::AssertEqual => {
Error::expect_argument_amount(self, 2, arguments.len())?; Error::expect_argument_amount(self.name(), 2, arguments.len())?;
let left = arguments.get(0).unwrap(); let left = arguments.get(0).unwrap();
let right = arguments.get(1).unwrap(); let right = arguments.get(1).unwrap();
@ -58,7 +65,7 @@ impl BuiltInFunction {
Ok(Value::Boolean(left == right)) Ok(Value::Boolean(left == right))
} }
BuiltInFunction::FsRead => { BuiltInFunction::FsRead => {
Error::expect_argument_amount(self, 1, arguments.len())?; Error::expect_argument_amount(self.name(), 1, arguments.len())?;
let path = arguments.first().unwrap().as_string()?; let path = arguments.first().unwrap().as_string()?;
let file_content = read_to_string(path)?; let file_content = read_to_string(path)?;
@ -66,7 +73,7 @@ impl BuiltInFunction {
Ok(Value::String(file_content)) Ok(Value::String(file_content))
} }
BuiltInFunction::JsonParse => { BuiltInFunction::JsonParse => {
Error::expect_argument_amount(self, 1, arguments.len())?; Error::expect_argument_amount(self.name(), 1, arguments.len())?;
let string = arguments.first().unwrap().as_string()?; let string = arguments.first().unwrap().as_string()?;
let value = serde_json::from_str(&string)?; let value = serde_json::from_str(&string)?;
@ -74,7 +81,7 @@ impl BuiltInFunction {
Ok(value) Ok(value)
} }
BuiltInFunction::Length => { BuiltInFunction::Length => {
Error::expect_argument_amount(self, 1, arguments.len())?; Error::expect_argument_amount(self.name(), 1, arguments.len())?;
let value = arguments.first().unwrap(); let value = arguments.first().unwrap();
let length = if let Ok(list) = value.as_list() { let length = if let Ok(list) = value.as_list() {
@ -92,7 +99,7 @@ impl BuiltInFunction {
Ok(Value::Integer(length as i64)) Ok(Value::Integer(length as i64))
} }
BuiltInFunction::Output => { BuiltInFunction::Output => {
Error::expect_argument_amount(self, 1, arguments.len())?; Error::expect_argument_amount(self.name(), 1, arguments.len())?;
let value = arguments.first().unwrap(); let value = arguments.first().unwrap();
@ -101,17 +108,17 @@ impl BuiltInFunction {
Ok(Value::none()) Ok(Value::none())
} }
BuiltInFunction::RandomBoolean => { BuiltInFunction::RandomBoolean => {
Error::expect_argument_amount(self, 0, arguments.len())?; Error::expect_argument_amount(self.name(), 0, arguments.len())?;
Ok(Value::Boolean(random())) Ok(Value::Boolean(random()))
} }
BuiltInFunction::RandomFloat => { BuiltInFunction::RandomFloat => {
Error::expect_argument_amount(self, 0, arguments.len())?; Error::expect_argument_amount(self.name(), 0, arguments.len())?;
Ok(Value::Float(random())) Ok(Value::Float(random()))
} }
BuiltInFunction::RandomFrom => { BuiltInFunction::RandomFrom => {
Error::expect_argument_amount(self, 1, arguments.len())?; Error::expect_argument_amount(self.name(), 1, arguments.len())?;
let value = arguments.first().unwrap(); let value = arguments.first().unwrap();
@ -131,10 +138,13 @@ impl BuiltInFunction {
} }
} }
BuiltInFunction::RandomInteger => { BuiltInFunction::RandomInteger => {
Error::expect_argument_amount(self, 0, arguments.len())?; Error::expect_argument_amount(self.name(), 0, arguments.len())?;
Ok(Value::Integer(random())) Ok(Value::Integer(random()))
} }
BuiltInFunction::String(string_function) => {
string_function.call(arguments, _source, _outer_context)
}
} }
} }
} }

View File

@ -0,0 +1,153 @@
use enum_iterator::{all, Sequence};
use serde::{Deserialize, Serialize};
use crate::{Error, List, Map, Result, Type, Value};
pub fn string_functions() -> impl Iterator<Item = StringFunction> {
all()
}
#[derive(Sequence, Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum StringFunction {
AsBytes,
EndsWith,
Find,
IsAscii,
IsEmpty,
Lines,
Matches,
Split,
SplitAt,
SplitInclusive,
SplitN,
SplitOnce,
SplitTerminator,
SplitWhitespace,
StartsWith,
StripPrefix,
ToLowercase,
ToUppercase,
Trim,
TrimEnd,
TrimEndMatches,
TrimLeft,
TrimLeftMatches,
TrimMatches,
TrimRight,
TrimRightMatches,
TrimStart,
TrimStartMatches,
}
impl StringFunction {
pub fn name(&self) -> &'static str {
match self {
StringFunction::AsBytes => "as_bytes",
StringFunction::EndsWith => todo!(),
StringFunction::Find => todo!(),
StringFunction::IsAscii => todo!(),
StringFunction::IsEmpty => todo!(),
StringFunction::Lines => todo!(),
StringFunction::Matches => todo!(),
StringFunction::Split => todo!(),
StringFunction::SplitAt => todo!(),
StringFunction::SplitInclusive => todo!(),
StringFunction::SplitN => todo!(),
StringFunction::SplitOnce => todo!(),
StringFunction::SplitTerminator => todo!(),
StringFunction::SplitWhitespace => todo!(),
StringFunction::StartsWith => todo!(),
StringFunction::StripPrefix => todo!(),
StringFunction::ToLowercase => todo!(),
StringFunction::ToUppercase => todo!(),
StringFunction::Trim => todo!(),
StringFunction::TrimEnd => todo!(),
StringFunction::TrimEndMatches => todo!(),
StringFunction::TrimLeft => todo!(),
StringFunction::TrimLeftMatches => todo!(),
StringFunction::TrimMatches => todo!(),
StringFunction::TrimRight => todo!(),
StringFunction::TrimRightMatches => todo!(),
StringFunction::TrimStart => todo!(),
StringFunction::TrimStartMatches => todo!(),
}
}
pub fn r#type(&self) -> Type {
match self {
StringFunction::AsBytes => {
Type::function(vec![Type::String], Type::list_of(Type::Integer))
}
StringFunction::EndsWith => todo!(),
StringFunction::Find => todo!(),
StringFunction::IsAscii => todo!(),
StringFunction::IsEmpty => todo!(),
StringFunction::Lines => todo!(),
StringFunction::Matches => todo!(),
StringFunction::Split => todo!(),
StringFunction::SplitAt => todo!(),
StringFunction::SplitInclusive => todo!(),
StringFunction::SplitN => todo!(),
StringFunction::SplitOnce => todo!(),
StringFunction::SplitTerminator => todo!(),
StringFunction::SplitWhitespace => todo!(),
StringFunction::StartsWith => todo!(),
StringFunction::StripPrefix => todo!(),
StringFunction::ToLowercase => todo!(),
StringFunction::ToUppercase => todo!(),
StringFunction::Trim => todo!(),
StringFunction::TrimEnd => todo!(),
StringFunction::TrimEndMatches => todo!(),
StringFunction::TrimLeft => todo!(),
StringFunction::TrimLeftMatches => todo!(),
StringFunction::TrimMatches => todo!(),
StringFunction::TrimRight => todo!(),
StringFunction::TrimRightMatches => todo!(),
StringFunction::TrimStart => todo!(),
StringFunction::TrimStartMatches => todo!(),
}
}
pub fn call(&self, arguments: &[Value], _source: &str, _outer_context: &Map) -> Result<Value> {
match self {
StringFunction::AsBytes => {
Error::expect_argument_amount(self.name(), 1, arguments.len())?;
let string = arguments.first().unwrap().as_string()?;
let bytes = string
.bytes()
.map(|byte| Value::Integer(byte as i64))
.collect();
Ok(Value::List(List::with_items(bytes)))
}
StringFunction::EndsWith => todo!(),
StringFunction::Find => todo!(),
StringFunction::IsAscii => todo!(),
StringFunction::IsEmpty => todo!(),
StringFunction::Lines => todo!(),
StringFunction::Matches => todo!(),
StringFunction::Split => todo!(),
StringFunction::SplitAt => todo!(),
StringFunction::SplitInclusive => todo!(),
StringFunction::SplitN => todo!(),
StringFunction::SplitOnce => todo!(),
StringFunction::SplitTerminator => todo!(),
StringFunction::SplitWhitespace => todo!(),
StringFunction::StartsWith => todo!(),
StringFunction::StripPrefix => todo!(),
StringFunction::ToLowercase => todo!(),
StringFunction::ToUppercase => todo!(),
StringFunction::Trim => todo!(),
StringFunction::TrimEnd => todo!(),
StringFunction::TrimEndMatches => todo!(),
StringFunction::TrimLeft => todo!(),
StringFunction::TrimLeftMatches => todo!(),
StringFunction::TrimMatches => todo!(),
StringFunction::TrimRight => todo!(),
StringFunction::TrimRightMatches => todo!(),
StringFunction::TrimStart => todo!(),
StringFunction::TrimStartMatches => todo!(),
}
}
}

View File

@ -6,7 +6,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tree_sitter::{LanguageError, Node, Point}; use tree_sitter::{LanguageError, Node, Point};
use crate::{value::Value, BuiltInFunction, Type}; use crate::{value::Value, Type};
use std::{ use std::{
fmt::{self, Formatter}, fmt::{self, Formatter},
@ -200,7 +200,7 @@ impl Error {
} }
pub fn expect_argument_amount( pub fn expect_argument_amount(
function: &BuiltInFunction, function_name: &str,
expected: usize, expected: usize,
actual: usize, actual: usize,
) -> Result<()> { ) -> Result<()> {
@ -208,7 +208,7 @@ impl Error {
Ok(()) Ok(())
} else { } else {
Err(Error::ExpectedBuiltInFunctionArgumentAmount { Err(Error::ExpectedBuiltInFunctionArgumentAmount {
function_name: function.name().to_string(), function_name: function_name.to_string(),
expected, expected,
actual, actual,
}) })

View File

@ -446,6 +446,7 @@ module.exports = grammar({
'length', 'length',
'output', 'output',
'random', 'random',
'string',
), ),
}, },
}); });

View File

@ -1431,6 +1431,10 @@
{ {
"type": "STRING", "type": "STRING",
"value": "random" "value": "random"
},
{
"type": "STRING",
"value": "string"
} }
] ]
} }

View File

@ -880,6 +880,10 @@
"type": "string", "type": "string",
"named": true "named": true
}, },
{
"type": "string",
"named": false
},
{ {
"type": "true", "type": "true",
"named": false "named": false

File diff suppressed because it is too large Load Diff