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",
"egui",
"egui_extras",
"enum-iterator",
"env_logger",
"getrandom",
"libc",
@ -1096,6 +1097,26 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
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]]
name = "enum-map"
version = "2.7.3"

View File

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

View File

@ -3,12 +3,16 @@ use std::{env::args, sync::OnceLock};
use serde::{Deserialize, Serialize};
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 FS: OnceLock<Value> = OnceLock::new();
static JSON: 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)]
pub enum BuiltInValue {
@ -19,6 +23,7 @@ pub enum BuiltInValue {
Length,
Output,
Random,
String,
}
impl BuiltInValue {
@ -31,6 +36,7 @@ impl BuiltInValue {
BuiltInValue::Length => BuiltInFunction::Length.r#type(),
BuiltInValue::Output => BuiltInFunction::Output.r#type(),
BuiltInValue::Random => Type::Map,
BuiltInValue::String => Type::Map,
}
}
@ -94,6 +100,25 @@ impl BuiltInValue {
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,
"output" => BuiltInValue::Output,
"random" => BuiltInValue::Random,
"string" => BuiltInValue::String,
_ => todo!(),
};

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff