From 384f8252178be5aea33203040c17ca7606dd20ec Mon Sep 17 00:00:00 2001 From: Mitchell Paulus Date: Mon, 11 Nov 2024 16:57:23 -0600 Subject: [PATCH] Add split/join for strings --- doc/mshell.md | 6 ++- mshell-go/Evaluator.go | 79 ++++++++++++++++++++++++++++++ mshell/tests/split_join.msh | 1 + mshell/tests/split_join.msh.stdout | 1 + 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 mshell/tests/split_join.msh create mode 100644 mshell/tests/split_join.msh.stdout diff --git a/doc/mshell.md b/doc/mshell.md index 0a0308c..c4cf2c7 100644 --- a/doc/mshell.md +++ b/doc/mshell.md @@ -28,6 +28,8 @@ `str`: Convert to string `findReplace`: Find and replace in string. `findReplace (string string, string find, string replace -- string)` `lines`: Split string into list of string lines +`split`: Split string into list of strings by delimiter, use `ws` literal or `"ws"` for whitespace. (string delimiter -- list) +`join`: Join list of strings into a single string, (list delimiter -- string) ### List Functions @@ -38,9 +40,9 @@ ```mshell # Storing -10 @a +10 my_var! # Retrieving -a! +@my_var ``` ## Process Substitution diff --git a/mshell-go/Evaluator.go b/mshell-go/Evaluator.go index 1d5977b..e64315e 100644 --- a/mshell-go/Evaluator.go +++ b/mshell-go/Evaluator.go @@ -386,6 +386,85 @@ func (state *EvalState) Evaluate(objects []MShellParseItem, stack *MShellStack, return FailWithMessage(fmt.Sprintf("%d:%d: Cannot find-replace a %s.\n", t.Line, t.Column, obj1.TypeName())) } + } else if t.Lexeme == "split" { + delimiter, err := stack.Pop() + if err != nil { + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot do 'split' operation on an empty stack.\n", t.Line, t.Column)) + } + + strLiteral, err := stack.Pop() + if err != nil { + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot do 'split' operation on a stack with only one item.\n", t.Line, t.Column)) + } + + + var delimiterStr string + var strToSplit string + + switch delimiter.(type) { + case *MShellString: + delimiterStr = delimiter.(*MShellString).Content + case *MShellLiteral: + delimiterStr = delimiter.(*MShellLiteral).LiteralText + default: + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot split with a %s.\n", t.Line, t.Column, delimiter.TypeName())) + } + + switch strLiteral.(type) { + case *MShellString: + strToSplit = strLiteral.(*MShellString).Content + case *MShellLiteral: + strToSplit = strLiteral.(*MShellLiteral).LiteralText + default: + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot split a %s.\n", t.Line, t.Column, strLiteral.TypeName())) + } + + split := strings.Split(strToSplit, delimiterStr) + newList := &MShellList { Items: make([]MShellObject, len(split)), StandardInputFile: "", StandardOutputFile: "", StdoutBehavior: STDOUT_NONE } + for i, item := range split { + newList.Items[i] = &MShellString { item } + } + stack.Push(newList) + } else if t.Lexeme == "join" { + delimiter, err := stack.Pop() + if err != nil { + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot do 'join' operation on an empty stack.\n", t.Line, t.Column)) + } + + list, err := stack.Pop() + if err != nil { + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot do 'join' operation on a stack with only one item.\n", t.Line, t.Column)) + } + + var delimiterStr string + var listItems []string + + switch delimiter.(type) { + case *MShellString: + delimiterStr = delimiter.(*MShellString).Content + case *MShellLiteral: + delimiterStr = delimiter.(*MShellLiteral).LiteralText + default: + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot join with a %s.\n", t.Line, t.Column, delimiter.TypeName())) + } + + switch list.(type) { + case *MShellList: + for _, item := range list.(*MShellList).Items { + switch item.(type) { + case *MShellString: + listItems = append(listItems, item.(*MShellString).Content) + case *MShellLiteral: + listItems = append(listItems, item.(*MShellLiteral).LiteralText) + default: + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot join a list with a %s inside (%s).\n", t.Line, t.Column, item.TypeName(), item.DebugString())) + } + } + default: + return FailWithMessage(fmt.Sprintf("%d:%d: Cannot join a %s.\n", t.Line, t.Column, list.TypeName())) + } + + stack.Push(&MShellString { strings.Join(listItems, delimiterStr) }) } else if t.Lexeme == "lines" { obj, err := stack.Pop() if err != nil { diff --git a/mshell/tests/split_join.msh b/mshell/tests/split_join.msh new file mode 100644 index 0000000..0342f28 --- /dev/null +++ b/mshell/tests/split_join.msh @@ -0,0 +1 @@ +"cell1|cell2|cell3" "|" split ":" join wl diff --git a/mshell/tests/split_join.msh.stdout b/mshell/tests/split_join.msh.stdout new file mode 100644 index 0000000..4879c89 --- /dev/null +++ b/mshell/tests/split_join.msh.stdout @@ -0,0 +1 @@ +cell1:cell2:cell3