Skip to content

Commit

Permalink
add string functions
Browse files Browse the repository at this point in the history
  • Loading branch information
bobimicroweber committed Aug 20, 2024
1 parent 3cf840a commit 3fceaa4
Show file tree
Hide file tree
Showing 2 changed files with 344 additions and 1 deletion.
200 changes: 199 additions & 1 deletion interpreter/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ var builtins = map[string]builtinFunction{
"int": {intFunction, "int"},
"join": {joinFunction, "join"},
"len": {lenFunction, "len"},
"lower": {lowerFunction, "lower"},
"echo": {echoFunction, "echo"},
"range": {rangeFunction, "range"},
"read": {readFunction, "read"},
Expand All @@ -101,7 +100,17 @@ var builtins = map[string]builtinFunction{
"explode": {explodeFunction, "explode"},
"str": {strFunction, "str"},
"type": {typeFunction, "type"},
"lower": {lowerFunction, "lower"},
"upper": {upperFunction, "upper"},
"upFirst": {upFirstFunction, "upFirst"},
"upWords": {upWordsFunction, "upWords"},
"lowerFirst": {lowerFirstFunction, "lowerFirst"},
"lowerWords": {lowerWordsFunction, "lowerWords"},
"camelCase": {camelCaseFunction, "camelCase"},
"snakeCase": {snakeCaseFunction, "snakeCase"},
"kebabCase": {kebabCaseFunction, "kebabCase"},
"pascalCase": {pascalCaseFunction, "pascalCase"},
"dotCase": {dotCaseFunction, "dotCase"},
"time": {timeFunction, "time"},
"fileGetContents": {fileGetContentsFunction, "fileGetContents"},
"httpRegister": {httpRegisterFunction, "httpRegister"},
Expand Down Expand Up @@ -703,6 +712,195 @@ func upperFunction(interp *interpreter, pos Position, args []Value) Value {
panic(typeError(pos, "upper() requires a str"))
}

/**
* function: upFirst
* args: string
* return: str
* example: upFirst("hello") => "Hello"
* output: "Hello"
* description: Convert the first character of a string to uppercase.
* title: Up First
* category: String
*/
func upFirstFunction(interp *interpreter, pos Position, args []Value) Value {

ensureNumArgs(pos, "upFirstFunction", args, 1)

if len(args) != 1 {
panic(fmt.Sprintf("upFirstFunction expected 1 argument, got %d", len(args)))
}

str, ok := args[0].(string)
if !ok {
panic(fmt.Sprintf("upFirstFunction expected a string argument, got %T", args[0]))
}

return Value(functions.UpFirst(str))

}

/**
* function: upWords
* args: string
* return: str
* example: upWords("hello, world!")
* output: "Hello, World!"
* description: Convert all words in a string to uppercase.
* title: Up Words
* category: String
*/
func upWordsFunction(interp *interpreter, pos Position, args []Value) Value {
ensureNumArgs(pos, "upWords", args, 1)

if s, ok := args[0].(string); ok {
return functions.UpWords(s)
}

panic(typeError(pos, "upWords() requires a str"))
}

/**
* function: lowerFirst
* args: string
* return: str
* example: lowerFirst("Hello")
* output: "hello"
* description: Convert the first character of a string to lowercase.
* title: Lower First
* category: String
*/
func lowerFirstFunction(interp *interpreter, pos Position, args []Value) Value {

ensureNumArgs(pos, "lowerFirstFunction", args, 1)
if len(args) != 1 {
panic(fmt.Sprintf("lowerFirstFunction expected 1 argument, got %d", len(args)))
}

str, ok := args[0].(string)
if !ok {
panic(fmt.Sprintf("lowerFirstFunction expected a string argument, got %T", args[0]))
}

return functions.LowerFirst(str)

}

/**
* function: lowerWords
* args: string
* return: str
* example: lowerWords("Hello, World!")
* output: "hello, world!"
* description: Convert all words in a string to lowercase.
* title: Lower Words
* category: String
*/
func lowerWordsFunction(interp *interpreter, pos Position, args []Value) Value {
ensureNumArgs(pos, "lowerWords", args, 1)
if s, ok := args[0].(string); ok {
return functions.LowerWords(s)
}
panic(typeError(pos, "lowerWords() requires a str"))
}

/**
* function: camelCase
* args: string
* return: str
* example: camelCase("Hello, World!")
* output: "helloWorld"
* description: Convert a string to camelCase.
* title: Camel Case
* category: String
*/
func camelCaseFunction(interp *interpreter, pos Position, args []Value) Value {
ensureNumArgs(pos, "camelCase", args, 1)

if len(args) != 1 {
panic(fmt.Sprintf("camelCaseFunction expected 1 argument, got %d", len(args)))
}

str, ok := args[0].(string)
if !ok {
panic(fmt.Sprintf("camelCaseFunction expected a string argument, got %T", args[0]))
}

return functions.ToCamelCase(str)
}

/**
* function: snakeCase
* args: string
* return: str
* example: snakeCase("Hello, World!")
* output: "hello_world"
* description: Convert a string to snake_case.
* title: Snake Case
* category: String
*/
func snakeCaseFunction(interp *interpreter, pos Position, args []Value) Value {

ensureNumArgs(pos, "snakeCase", args, 1)
if s, ok := args[0].(string); ok {
return functions.ToSnakeCase(s)
}
panic(typeError(pos, "snakeCase() requires a str"))
}

/**
* function: kebabCase
* args: string
* return: str
* example: kebabCase("Hello, World!")
* output: "hello-world"
* description: Convert a string to kebab-case.
* title: Kebab Case
* category: String
*/
func kebabCaseFunction(interp *interpreter, pos Position, args []Value) Value {
ensureNumArgs(pos, "kebabCase", args, 1)
if s, ok := args[0].(string); ok {
return functions.ToKebabCase(s)
}
panic(typeError(pos, "kebabCase() requires a str"))
}

/**
* function: pascalCase
* args: string
* return: str
* example: pascalCase("Hello, World!")
* output: "HelloWorld"
* description: Convert a string to PascalCase.
* title: Pascal Case
* category: String
*/
func pascalCaseFunction(interp *interpreter, pos Position, args []Value) Value {
ensureNumArgs(pos, "pascalCase", args, 1)
if s, ok := args[0].(string); ok {
return functions.ToPascalCase(s)
}
panic(typeError(pos, "pascalCase() requires a str"))
}

/**
* function: dotCase
* args: string
* return: str
* example: dotCase("Hello, World!")
* output: "hello.world"
* description: Convert a string to dot.case.
* title: Dot Case
* category: String
*/
func dotCaseFunction(interp *interpreter, pos Position, args []Value) Value {
ensureNumArgs(pos, "dotCase", args, 1)
if s, ok := args[0].(string); ok {
return functions.ToDotCase(s)
}
panic(typeError(pos, "dotCase() requires a str"))
}

/**
* function: time
* args: none
Expand Down
145 changes: 145 additions & 0 deletions interpreter/functions/strings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package functions

import (
"strings"
"unicode"
)

// toCamelCase converts a string to camelCase.
func ToCamelCase(s string) string {
words := strings.Fields(s)
if len(words) == 0 {
return ""
}

// Convert the first word to lowercase
words[0] = strings.ToLower(words[0])

// Capitalize the first letter of the remaining words
for i := 1; i < len(words); i++ {
words[i] = Capitalize(words[i])
}

return strings.Join(words, "")
}

// capitalize capitalizes the first letter of a word.
func Capitalize(word string) string {
if len(word) == 0 {
return word
}
runes := []rune(word)
runes[0] = unicode.ToUpper(runes[0])
return string(runes)
}

// lowerFirst converts the first letter of the first word in the input string to lowercase.
func LowerFirst(s string) string {
if len(s) == 0 {
return s
}

runes := []rune(s)
runes[0] = unicode.ToLower(runes[0])
return string(runes)
}

// lowerWords converts all words in the input string to lowercase.
func LowerWords(s string) string {
return strings.ToLower(s)
}

// upFirst capitalizes the first letter of the first word in the input string.
func UpFirst(s string) string {
if len(s) == 0 {
return s
}

runes := []rune(s)
runes[0] = unicode.ToUpper(runes[0])
return string(runes)
}

func UpWords(s string) string {
return strings.Title(s)
}

// ToSnakeCase converts a string to snake_case.
func ToSnakeCase(s string) string {
var result []rune
for i, r := range s {
if unicode.IsUpper(r) {
// Add an underscore before uppercase letters (except at the start)
if i > 0 {
result = append(result, '_')
}
// Convert the letter to lowercase
r = unicode.ToLower(r)
} else if r == ' ' || r == '-' || r == '.' || r == ',' {
// Replace spaces and certain punctuation with underscores
r = '_'
}
result = append(result, r)
}
return string(result)
}

// ToKebabCase converts a string to kebab-case.
func ToKebabCase(s string) string {
var result []rune
for i, r := range s {
if unicode.IsUpper(r) {
// Add a hyphen before uppercase letters (except at the start)
if i > 0 {
result = append(result, '-')
}
// Convert the letter to lowercase
r = unicode.ToLower(r)
} else if r == ' ' || r == '_' || r == '.' || r == ',' {
// Replace spaces and certain punctuation with hyphens
r = '-'
}
result = append(result, r)
}
return string(result)
}

// ToPascalCase converts a string to PascalCase.
func ToPascalCase(s string) string {
var result []rune
capitalizeNext := true

for _, r := range s {
if unicode.IsLetter(r) || unicode.IsDigit(r) {
if capitalizeNext {
r = unicode.ToUpper(r)
capitalizeNext = false
} else {
r = unicode.ToLower(r)
}
result = append(result, r)
} else {
capitalizeNext = true
}
}
return string(result)
}

// ToDotCase converts a string to dot.case.
func ToDotCase(s string) string {
var result []rune
for i, r := range s {
if unicode.IsLetter(r) || unicode.IsDigit(r) {
if i > 0 && (unicode.IsUpper(r) || (!unicode.IsLetter([]rune(s)[i-1]) && unicode.IsLetter(r))) {
result = append(result, '.')
}
result = append(result, unicode.ToLower(r))
} else if len(result) > 0 && result[len(result)-1] != '.' {
result = append(result, '.')
}
}
if len(result) > 0 && result[len(result)-1] == '.' {
result = result[:len(result)-1] // Remove trailing dot, if any
}
return string(result)
}

0 comments on commit 3fceaa4

Please sign in to comment.