Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 0 additions & 48 deletions interp/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,51 +449,3 @@ func (p *interp) sprintf(format string, args []value) (string, error) {
}
return fmt.Sprintf(format, converted...), nil
}

func substrChars(s string, pos int) string {
// Count characters till we get to pos.
chars := 1
start := 0
for start = range s {
chars++
if chars > pos {
break
}
}
if pos >= chars {
start = len(s)
}
return s[start:]
}

func substrLengthChars(s string, pos, length int) string {
// Count characters till we get to pos.
chars := 1
start := 0
for start = range s {
chars++
if chars > pos {
break
}
}
if pos >= chars {
start = len(s)
}

// Count characters from start till we reach length.
chars = 0
end := 0
for end = range s[start:] {
chars++
if chars > length {
break
}
}
if length >= chars {
end = len(s)
} else {
end += start
}

return s[start:end]
}
23 changes: 20 additions & 3 deletions interp/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ const (
type value struct {
typ valueType // Type of value
s string // String value (for typeStr and typeNumStr)
n float64 // Numeric value (for typeNum)
r *[]rune
n float64 // Numeric value (for typeNum)
}

// Create a new null value
Expand All @@ -37,12 +38,16 @@ func num(n float64) value {

// Create a new string value
func str(s string) value {
return value{typ: typeStr, s: s}
return value{typ: typeStr, s: s, r: new([]rune)}
}

func strFromRunes(runes []rune) value {
return value{typ: typeStr, s: string(runes), r: &runes}
}

// Create a new value to represent a "numeric string" from an input field
func numStr(s string) value {
return value{typ: typeNumStr, s: s}
return value{typ: typeNumStr, s: s, r: new([]rune)}
}

// Create a numeric value from a Go bool
Expand All @@ -53,6 +58,18 @@ func boolean(b bool) value {
return num(0)
}

func (v value) runes(floatFormat string) []rune {
switch v.typ {
case typeStr, typeNumStr:
if *v.r == nil {
*v.r = []rune(v.s)
}
return *v.r
default: // typeNum, typeNull
return []rune(v.str(floatFormat))
}
}

// String returns a string representation of v for debugging.
func (v value) String() string {
switch v.typ {
Expand Down
48 changes: 36 additions & 12 deletions interp/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -1001,12 +1001,12 @@ func (p *interp) callBuiltin(builtinOp compiler.BuiltinOp) error {
p.push(num(float64(length)))

case compiler.BuiltinLengthArg:
s := p.toString(p.peekTop())
s := p.peekTop()
var length int
if p.chars {
length = utf8.RuneCountInString(s)
length = len(s.runes(p.convertFormat))
} else {
length = len(s)
length = len(p.toString(s))
}
p.replaceTop(num(float64(length)))

Expand Down Expand Up @@ -1066,9 +1066,18 @@ func (p *interp) callBuiltin(builtinOp compiler.BuiltinOp) error {
sValue, posValue := p.peekPop()
pos := int(posValue.num())
s := p.toString(sValue)
var substr string
var substr value
if p.chars {
substr = substrChars(s, pos)
runes := sValue.runes(p.convertFormat)
if pos > len(runes) {
pos = len(runes) + 1
}
if pos < 1 {
pos = 1
}
length := len(runes) - pos + 1
runes = runes[pos-1 : pos-1+length]
substr = strFromRunes(runes)
} else {
if pos > len(s) {
pos = len(s) + 1
Expand All @@ -1077,19 +1086,34 @@ func (p *interp) callBuiltin(builtinOp compiler.BuiltinOp) error {
pos = 1
}
length := len(s) - pos + 1
substr = s[pos-1 : pos-1+length]
substr = str(s[pos-1 : pos-1+length])
}
p.replaceTop(str(substr))
p.replaceTop(substr)

case compiler.BuiltinSubstrLength:
posValue, lengthValue := p.popTwo()
length := int(lengthValue.num())
pos := int(posValue.num())
s := p.toString(p.peekTop())
var substr string
sValue := p.peekTop()
var substr value
if p.chars {
substr = substrLengthChars(s, pos, length)
runes := sValue.runes(p.convertFormat)
if pos > len(runes) {
pos = len(runes) + 1
}
if pos < 1 {
pos = 1
}
maxLength := len(runes) - pos + 1
if length < 0 {
length = 0
}
if length > maxLength {
length = maxLength
}
substr = strFromRunes(runes[pos-1 : pos-1+length])
} else {
s := p.toString(sValue)
if pos > len(s) {
pos = len(s) + 1
}
Expand All @@ -1103,9 +1127,9 @@ func (p *interp) callBuiltin(builtinOp compiler.BuiltinOp) error {
if length > maxLength {
length = maxLength
}
substr = s[pos-1 : pos-1+length]
substr = str(s[pos-1 : pos-1+length])
}
p.replaceTop(str(substr))
p.replaceTop(substr)

case compiler.BuiltinSystem:
if p.noExec {
Expand Down
Loading