Beispiel #1
0
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))
	}
}
Beispiel #2
0
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 {
Beispiel #3
0
		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]]
Beispiel #4
0
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)