Begin adding string functions
This commit is contained in:
parent
976cb7de3f
commit
c2d919957e
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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!(),
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
153
src/built_in_functions/string.rs
Normal file
153
src/built_in_functions/string.rs
Normal 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!(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
})
|
||||
|
@ -446,6 +446,7 @@ module.exports = grammar({
|
||||
'length',
|
||||
'output',
|
||||
'random',
|
||||
'string',
|
||||
),
|
||||
},
|
||||
});
|
||||
|
@ -1431,6 +1431,10 @@
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "random"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user