func builtinString_replace(call FunctionCall) Value { checkObjectCoercible(call.runtime, call.This) target := []byte(call.This.string()) searchValue := call.Argument(0) searchObject := searchValue._object() // TODO If a capture is -1? var search *p5r.Regexp global := false find := 1 if searchValue.IsObject() && searchObject.class == "RegExp" { regExp := searchObject.regExpValue() search = regExp.regularExpression if regExp.global { find = -1 } } else { search = p5r.MustCompile(p5r.QuoteMeta(searchValue.string())) } // TODO: Use p5r directly instead of converting to a regexp struct found := search.MustConvert().FindAllSubmatchIndex(target, find) if found == nil { return toValue_string(string(target)) // !match } { lastIndex := 0 result := []byte{} replaceValue := call.Argument(1) if replaceValue.isCallable() { target := string(target) replace := replaceValue._object() for _, match := range found { if match[0] != lastIndex { result = append(result, target[lastIndex:match[0]]...) } matchCount := len(match) / 2 argumentList := make([]Value, matchCount+2) for index := 0; index < matchCount; index++ { offset := 2 * index if match[offset] != -1 { argumentList[index] = toValue_string(target[match[offset]:match[offset+1]]) } else { argumentList[index] = Value{} } } argumentList[matchCount+0] = toValue_int(match[0]) argumentList[matchCount+1] = toValue_string(target) replacement := replace.call(Value{}, argumentList, false, nativeFrame).string() result = append(result, []byte(replacement)...) lastIndex = match[1] } } else { replace := []byte(replaceValue.string()) for _, match := range found { result = builtinString_findAndReplaceString(result, lastIndex, match, target, replace) lastIndex = match[1] } } if lastIndex != len(target) { result = append(result, target[lastIndex:]...) } if global && searchObject != nil { searchObject.put("lastIndex", toValue_int(lastIndex), true) } return toValue_string(string(result)) } }
package otto import ( "fmt" "github.com/xyproto/p5r" "math" "strconv" "strings" ) var stringToNumberParseInteger = p5r.MustCompile(`^(?:0[xX])`) func parseNumber(value string) float64 { value = strings.TrimSpace(value) if value == "" { return 0 } parseFloat := false if strings.IndexRune(value, '.') != -1 { parseFloat = true } else if stringToNumberParseInteger.MatchString(value) { parseFloat = false } else { parseFloat = true } if parseFloat { number, err := strconv.ParseFloat(value, 64) if err != nil && err.(*strconv.NumError).Err != strconv.ErrRange {
matchCount := len(result) if result == nil { matcher.put("lastIndex", toValue_int(0), true) return Value{} // !match } matchCount = len(result) valueArray := make([]Value, matchCount) for index := 0; index < matchCount; index++ { valueArray[index] = toValue_string(target[result[index][0]:result[index][1]]) } matcher.put("lastIndex", toValue_int(result[matchCount-1][1]), true) return toValue_object(call.runtime.newArrayOf(valueArray)) } } var builtinString_replace_Regexp = p5r.MustCompile("\\$(?:[\\$\\&\\'\\`1-9]|0[1-9]|[1-9][0-9])") func builtinString_findAndReplaceString(input []byte, lastIndex int, match []int, target []byte, replaceValue []byte) (output []byte) { matchCount := len(match) / 2 output = input if match[0] != lastIndex { output = append(output, target[lastIndex:match[0]]...) } // TODO: Use p5r directly instead of converting to a regexp struct replacement := builtinString_replace_Regexp.MustConvert().ReplaceAllFunc(replaceValue, func(part []byte) []byte { // TODO Check if match[0] or match[1] can be -1 in this scenario switch part[1] { case '$': return []byte{'$'} case '&': return target[match[0]:match[1]]
func builtinNewFunction(self *_object, argumentList []Value) Value { return toValue_object(builtinNewFunctionNative(self.runtime, argumentList)) } func argumentList2parameterList(argumentList []Value) []string { parameterList := make([]string, 0, len(argumentList)) for _, value := range argumentList { tmp := strings.FieldsFunc(value.string(), func(chr rune) bool { return chr == ',' || unicode.IsSpace(chr) }) parameterList = append(parameterList, tmp...) } return parameterList } var matchIdentifier = p5r.MustCompile(`^[$_\p{L}][$_\p{L}\d}]*$`) func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object { var parameterList, body string count := len(argumentList) if count > 0 { tmp := make([]string, 0, count-1) for _, value := range argumentList[0 : count-1] { tmp = append(tmp, value.string()) } parameterList = strings.Join(tmp, ",") body = argumentList[count-1].string() } // FIXME function, err := parser.ParseFunction(parameterList, body)