Skip to content

Commit e9c3aec

Browse files
authored
Merge pull request #94 from gekkowrld/strfmt
Extend the string object to format code. Closes #81 .
2 parents f8d1a7d + aa194e8 commit e9c3aec

File tree

1 file changed

+94
-0
lines changed

1 file changed

+94
-0
lines changed

object/strings.go

+94
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package object
22

33
import (
4+
"fmt"
45
"hash/fnv"
6+
"strconv"
57
"strings"
68
)
79

@@ -39,6 +41,8 @@ func (s *String) Method(method string, args []Object) Object {
3941
return s.lower(args)
4042
case "gawa":
4143
return s.split(args)
44+
case "panga":
45+
return s.format(args)
4246
default:
4347
return newError("Samahani, kiendesha hiki hakitumiki na tungo (Neno)")
4448
}
@@ -81,3 +85,93 @@ func (s *String) split(args []Object) Object {
8185
}
8286
return &Array{Elements: elements}
8387
}
88+
89+
func (s *String) format(args []Object) Object {
90+
value, err := formatStr(s.Value, args)
91+
92+
if err != nil {
93+
return newError(err.Error())
94+
}
95+
96+
return &String{Value: value}
97+
}
98+
99+
func formatStr(format string, options []Object) (string, error) {
100+
var str strings.Builder
101+
var val strings.Builder
102+
var check_val bool
103+
var opts_len int = len(options)
104+
105+
var escapeChar bool
106+
107+
type optM struct {
108+
val bool
109+
obj Object
110+
}
111+
112+
var optionsMap = make(map[int]optM, opts_len)
113+
114+
for i, optm := range options {
115+
optionsMap[i] = optM{val: false, obj: optm}
116+
}
117+
118+
for _, opt := range format {
119+
120+
if !escapeChar && opt == '\\' {
121+
escapeChar = true
122+
continue
123+
}
124+
125+
if opt == '{' && !escapeChar {
126+
check_val = true
127+
continue
128+
}
129+
130+
if escapeChar {
131+
if opt != '{' && opt != '}' {
132+
str.WriteRune('\\')
133+
}
134+
escapeChar = false
135+
}
136+
137+
if check_val && opt == '}' {
138+
vstr := strings.TrimSpace(val.String())
139+
arrv, err := strconv.Atoi(vstr)
140+
if err != nil {
141+
return "", fmt.Errorf(fmt.Sprintf("Ulichopeana si NAMBA, jaribu tena: `%s'", vstr))
142+
}
143+
144+
oVal, exists := optionsMap[arrv]
145+
146+
if !exists {
147+
return "", fmt.Errorf(fmt.Sprintf("Nambari ya chaguo unalolitaka %d ni kubwa kuliko ulizopeana (%d)", arrv, opts_len))
148+
}
149+
150+
str.WriteString(oVal.obj.Inspect())
151+
optionsMap[arrv] = optM{val: true, obj: oVal.obj}
152+
153+
check_val = false
154+
val.Reset()
155+
continue
156+
}
157+
158+
if check_val {
159+
val.WriteRune(opt)
160+
continue
161+
}
162+
163+
str.WriteRune(opt)
164+
}
165+
166+
if check_val {
167+
return "", fmt.Errorf(fmt.Sprintf("Haukufunga '{', tuliokota kabla ya kufika mwisho `%s'", val.String()))
168+
}
169+
170+
for _, v := range optionsMap {
171+
if !v.val {
172+
return "", fmt.Errorf(fmt.Sprintf("Ulipeana hili chaguo (%s) {%s} lakini haukutumia", v.obj.Inspect(), v.obj.Type()))
173+
}
174+
}
175+
176+
return str.String(), nil
177+
}

0 commit comments

Comments
 (0)