From 4e3c95c3bcdaffc1bb8766dbf6b37251104ee58f Mon Sep 17 00:00:00 2001 From: Gekko Wrld Date: Wed, 30 Oct 2024 14:26:42 +0300 Subject: [PATCH 1/3] chore: Extend the string object to format code. Strings now can be formatted using the `"Jina langu ni {0}".badilisha('Nuru')`. Sucessor to Instead of using a function, just do it on the string level. Signed-off-by: Gekko Wrld --- object/strings.go | 113 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/object/strings.go b/object/strings.go index 5a428d0..a8eff11 100644 --- a/object/strings.go +++ b/object/strings.go @@ -1,7 +1,9 @@ package object import ( + "fmt" "hash/fnv" + "strconv" "strings" ) @@ -39,6 +41,8 @@ func (s *String) Method(method string, args []Object) Object { return s.lower(args) case "gawa": return s.split(args) + case "badilisha": + return s.format(args) default: return newError("Samahani, kiendesha hiki hakitumiki na tungo (Neno)") } @@ -81,3 +85,112 @@ func (s *String) split(args []Object) Object { } return &Array{Elements: elements} } + +func (s *String) format(args []Object) Object { + value, err := formatStr(s.Value, args) + + if err != nil { + return newError(err.Error()) + } + + return &String{Value: value} +} + +// Format the string like "Hello {0}", jina ... +func formatStr(format string, options []Object) (string, error) { + var str strings.Builder + var val strings.Builder + var check_val bool + var opts_len int = len(options) + + // This is to enable escaping the {} braces if you want them included + var escapeChar bool + + type optM struct { + val bool + obj Object + } + + var optionsMap = make(map[int]optM, opts_len) + + // convert the options into a map (may not be the most efficient but we are not going fast) + for i, optm := range options { + optionsMap[i] = optM{val: false, obj: optm} + } + + // Now go through the format string and do the replacement(s) + // this has approx time complexity of O(n) (bestest case) + for _, opt := range format { + + if !escapeChar && opt == '\\' { + escapeChar = true + continue + } + + if opt == '{' && !escapeChar { + check_val = true + continue + } + + if escapeChar { + if opt != '{' && opt != '}' { + str.WriteRune('\\') + } + escapeChar = false + } + + if check_val && opt == '}' { + vstr := strings.TrimSpace(val.String()) // remove accidental spaces + + // check the value and try to convert to int + arrv, err := strconv.Atoi(vstr) + if err != nil { + // return non-cryptic go errors + return "", fmt.Errorf(fmt.Sprintf("Ulichopeana si NAMBA, jaribu tena: `%s'", vstr)) + } + + oVal, exists := optionsMap[arrv] + + if !exists { + return "", fmt.Errorf(fmt.Sprintf("Nambari ya chaguo unalolitaka %d ni kubwa kuliko ulizopeana (%d)", arrv, opts_len)) + } + + str.WriteString(oVal.obj.Inspect()) + // may be innefficient + optionsMap[arrv] = optM{val: true, obj: oVal.obj} + + check_val = false + val.Reset() + continue + } + + if check_val { + val.WriteRune(opt) + continue + } + + str.WriteRune(opt) + } + + // A check if they never closed the formatting braces e.g '{0' + if check_val { + return "", fmt.Errorf(fmt.Sprintf("Haukufunga '{', tuliokota kabla ya kufika mwisho `%s'", val.String())) + } + + // Another innefficient loop + for _, v := range optionsMap { + if !v.val { + return "", fmt.Errorf(fmt.Sprintf("Ulipeana hili chaguo (%s) {%s} lakini haukutumia", v.obj.Inspect(), v.obj.Type())) + } + } + + // !start + // Here we can talk about wtf just happened + // 3 loops to do just formatting, formatting for codes sake. + // it can be done in 2 loops, the last one is just to confirm that you didn't forget anything. + // this is not required but a nice syntatic sugar, we are not here for speed, so ergonomics matter instead of speed + // finally we can say we are slower than python!, what an achievement + // done! + + return str.String(), nil +} From 42ff0555a692938b370a89f15f6eaee3444f3114 Mon Sep 17 00:00:00 2001 From: Avicenna <87450618+AvicennaJr@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:31:29 +0300 Subject: [PATCH 2/3] use panga keyword --- object/strings.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/object/strings.go b/object/strings.go index a8eff11..f1a0e92 100644 --- a/object/strings.go +++ b/object/strings.go @@ -41,7 +41,7 @@ func (s *String) Method(method string, args []Object) Object { return s.lower(args) case "gawa": return s.split(args) - case "badilisha": + case "panga": return s.format(args) default: return newError("Samahani, kiendesha hiki hakitumiki na tungo (Neno)") From aa194e8079237f5a73699bf55a983d86988826e8 Mon Sep 17 00:00:00 2001 From: Avicenna <87450618+AvicennaJr@users.noreply.github.com> Date: Wed, 30 Oct 2024 17:33:19 +0300 Subject: [PATCH 3/3] remove comments --- object/strings.go | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/object/strings.go b/object/strings.go index f1a0e92..095a832 100644 --- a/object/strings.go +++ b/object/strings.go @@ -96,14 +96,12 @@ func (s *String) format(args []Object) Object { return &String{Value: value} } -// Format the string like "Hello {0}", jina ... func formatStr(format string, options []Object) (string, error) { var str strings.Builder var val strings.Builder var check_val bool var opts_len int = len(options) - // This is to enable escaping the {} braces if you want them included var escapeChar bool type optM struct { @@ -113,13 +111,10 @@ func formatStr(format string, options []Object) (string, error) { var optionsMap = make(map[int]optM, opts_len) - // convert the options into a map (may not be the most efficient but we are not going fast) for i, optm := range options { optionsMap[i] = optM{val: false, obj: optm} } - // Now go through the format string and do the replacement(s) - // this has approx time complexity of O(n) (bestest case) for _, opt := range format { if !escapeChar && opt == '\\' { @@ -140,12 +135,9 @@ func formatStr(format string, options []Object) (string, error) { } if check_val && opt == '}' { - vstr := strings.TrimSpace(val.String()) // remove accidental spaces - - // check the value and try to convert to int + vstr := strings.TrimSpace(val.String()) arrv, err := strconv.Atoi(vstr) if err != nil { - // return non-cryptic go errors return "", fmt.Errorf(fmt.Sprintf("Ulichopeana si NAMBA, jaribu tena: `%s'", vstr)) } @@ -156,7 +148,6 @@ func formatStr(format string, options []Object) (string, error) { } str.WriteString(oVal.obj.Inspect()) - // may be innefficient optionsMap[arrv] = optM{val: true, obj: oVal.obj} check_val = false @@ -172,25 +163,15 @@ func formatStr(format string, options []Object) (string, error) { str.WriteRune(opt) } - // A check if they never closed the formatting braces e.g '{0' if check_val { return "", fmt.Errorf(fmt.Sprintf("Haukufunga '{', tuliokota kabla ya kufika mwisho `%s'", val.String())) } - // Another innefficient loop for _, v := range optionsMap { if !v.val { return "", fmt.Errorf(fmt.Sprintf("Ulipeana hili chaguo (%s) {%s} lakini haukutumia", v.obj.Inspect(), v.obj.Type())) } } - // !start - // Here we can talk about wtf just happened - // 3 loops to do just formatting, formatting for codes sake. - // it can be done in 2 loops, the last one is just to confirm that you didn't forget anything. - // this is not required but a nice syntatic sugar, we are not here for speed, so ergonomics matter instead of speed - // finally we can say we are slower than python!, what an achievement - // done! - return str.String(), nil }