From ab4c8922b1a9f08d8ba15b18f25cb400af0ae773 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 1 Jan 2024 09:39:59 -0500 Subject: [PATCH] Implement string functions --- src/abstract_tree/built_in_value.rs | 8 +- src/abstract_tree/type_definition.rs | 10 +- src/built_in_functions/string.rs | 154 +++++++++++++++++---------- 3 files changed, 109 insertions(+), 63 deletions(-) diff --git a/src/abstract_tree/built_in_value.rs b/src/abstract_tree/built_in_value.rs index 3132451..db1c301 100644 --- a/src/abstract_tree/built_in_value.rs +++ b/src/abstract_tree/built_in_value.rs @@ -4,8 +4,8 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Node; use crate::{ - built_in_functions::{string_functions, StringFunction}, - AbstractTree, BuiltInFunction, Function, List, Map, Result, Type, Value, + built_in_functions::string_functions, AbstractTree, BuiltInFunction, Function, List, Map, + Result, Type, Value, }; static ARGS: OnceLock = OnceLock::new(); @@ -29,7 +29,7 @@ pub enum BuiltInValue { impl BuiltInValue { fn r#type(&self) -> Type { match self { - BuiltInValue::Args => Type::list_of(Type::String), + BuiltInValue::Args => Type::list(Type::String), BuiltInValue::AssertEqual => BuiltInFunction::AssertEqual.r#type(), BuiltInValue::Fs => Type::Map, BuiltInValue::Json => Type::Map, @@ -106,7 +106,7 @@ impl BuiltInValue { { let mut variables = string_context.variables_mut().unwrap(); - for string_function in [StringFunction::AsBytes] { + for string_function in string_functions() { let key = string_function.name().to_string(); let value = Value::Function(Function::BuiltIn(BuiltInFunction::String( string_function, diff --git a/src/abstract_tree/type_definition.rs b/src/abstract_tree/type_definition.rs index 2e0d32b..bb024d7 100644 --- a/src/abstract_tree/type_definition.rs +++ b/src/abstract_tree/type_definition.rs @@ -69,7 +69,7 @@ pub enum Type { } impl Type { - pub fn list_of(item_type: Type) -> Self { + pub fn list(item_type: Type) -> Self { Type::List(Box::new(item_type)) } @@ -80,6 +80,10 @@ impl Type { } } + pub fn option(optional_type: Type) -> Self { + Type::Option(Box::new(optional_type)) + } + pub fn check(&self, other: &Type) -> Result<()> { match (self, other) { (Type::Any, _) @@ -257,10 +261,10 @@ impl Display for Type { } => { write!(f, "(")?; - for parameter_type in parameter_types { + for (index, parameter_type) in parameter_types.iter().enumerate() { write!(f, "{parameter_type}")?; - if parameter_type != parameter_types.last().unwrap() { + if index != parameter_types.len() - 1 { write!(f, " ")?; } } diff --git a/src/built_in_functions/string.rs b/src/built_in_functions/string.rs index eb67992..4dd7437 100644 --- a/src/built_in_functions/string.rs +++ b/src/built_in_functions/string.rs @@ -43,68 +43,104 @@ 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!(), + StringFunction::EndsWith => "ends_with", + StringFunction::Find => "find", + StringFunction::IsAscii => "is_ascii", + StringFunction::IsEmpty => "is_empty", + StringFunction::Lines => "lines", + StringFunction::Matches => "matches", + StringFunction::Split => "split", + StringFunction::SplitAt => "split_at", + StringFunction::SplitInclusive => "split_inclusive", + StringFunction::SplitN => "split_n", + StringFunction::SplitOnce => "split_once", + StringFunction::SplitTerminator => "split_terminator", + StringFunction::SplitWhitespace => "split_whitespace", + StringFunction::StartsWith => "starts_with", + StringFunction::StripPrefix => "strip_prefix", + StringFunction::ToLowercase => "to_lowercase", + StringFunction::ToUppercase => "to_uppercase", + StringFunction::Trim => "trim", + StringFunction::TrimEnd => "trim_end", + StringFunction::TrimEndMatches => "trim_end_matches", + StringFunction::TrimLeft => "trim_left", + StringFunction::TrimLeftMatches => "trim_left_matches", + StringFunction::TrimMatches => "trim_matches", + StringFunction::TrimRight => "trim_right", + StringFunction::TrimRightMatches => "trim_right_matches", + StringFunction::TrimStart => "trim_start", + StringFunction::TrimStartMatches => "trim_start_matches", } } pub fn r#type(&self) -> Type { match self { StringFunction::AsBytes => { - Type::function(vec![Type::String], Type::list_of(Type::Integer)) + Type::function(vec![Type::String], Type::list(Type::Integer)) + } + StringFunction::EndsWith => { + Type::function(vec![Type::String, Type::String], Type::Boolean) + } + StringFunction::Find => Type::function( + vec![Type::String, Type::String], + Type::option(Type::Integer), + ), + StringFunction::IsAscii => Type::function(vec![Type::String], Type::Boolean), + StringFunction::IsEmpty => Type::function(vec![Type::String], Type::Boolean), + StringFunction::Lines => Type::function(vec![Type::String], Type::list(Type::String)), + StringFunction::Matches => { + Type::function(vec![Type::String, Type::String], Type::list(Type::String)) + } + StringFunction::Split => { + Type::function(vec![Type::String, Type::String], Type::list(Type::String)) + } + StringFunction::SplitAt => { + Type::function(vec![Type::String, Type::Integer], Type::list(Type::String)) + } + StringFunction::SplitInclusive => { + Type::function(vec![Type::String, Type::String], Type::list(Type::String)) + } + StringFunction::SplitN => Type::function( + vec![Type::String, Type::Integer, Type::String], + Type::list(Type::String), + ), + StringFunction::SplitOnce => { + Type::function(vec![Type::String, Type::String], Type::list(Type::String)) + } + StringFunction::SplitTerminator => { + Type::function(vec![Type::String, Type::String], Type::list(Type::String)) + } + StringFunction::SplitWhitespace => { + Type::function(vec![Type::String], Type::list(Type::String)) + } + StringFunction::StartsWith => { + Type::function(vec![Type::String, Type::String], Type::Boolean) + } + StringFunction::StripPrefix => { + Type::function(vec![Type::String, Type::String], Type::option(Type::String)) + } + StringFunction::ToLowercase => Type::function(vec![Type::String], Type::String), + StringFunction::ToUppercase => Type::function(vec![Type::String], Type::String), + StringFunction::Trim => Type::function(vec![Type::String], Type::String), + StringFunction::TrimEnd => Type::function(vec![Type::String], Type::String), + StringFunction::TrimEndMatches => { + Type::function(vec![Type::String, Type::String], Type::String) + } + StringFunction::TrimLeft => Type::function(vec![Type::String], Type::String), + StringFunction::TrimLeftMatches => { + Type::function(vec![Type::String, Type::String], Type::String) + } + StringFunction::TrimMatches => { + Type::function(vec![Type::String, Type::String], Type::String) + } + StringFunction::TrimRight => Type::function(vec![Type::String], Type::String), + StringFunction::TrimRightMatches => { + Type::function(vec![Type::String, Type::String], Type::String) + } + StringFunction::TrimStart => Type::function(vec![Type::String], Type::String), + StringFunction::TrimStartMatches => { + Type::function(vec![Type::String, Type::String], Type::String) } - 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!(), } } @@ -138,7 +174,13 @@ impl StringFunction { StringFunction::StripPrefix => todo!(), StringFunction::ToLowercase => todo!(), StringFunction::ToUppercase => todo!(), - StringFunction::Trim => todo!(), + StringFunction::Trim => { + Error::expect_argument_amount(self.name(), 1, arguments.len())?; + + let trimmed = arguments.first().unwrap().as_string()?.trim().to_string(); + + Ok(Value::String(trimmed)) + } StringFunction::TrimEnd => todo!(), StringFunction::TrimEndMatches => todo!(), StringFunction::TrimLeft => todo!(),