1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
package otto
import (
"fmt"
"regexp"
"unicode/utf8"
"github.com/robertkrimen/otto/parser"
)
type _regExpObject struct {
regularExpression *regexp.Regexp
global bool
ignoreCase bool
multiline bool
source string
flags string
}
func (runtime *_runtime) newRegExpObject(pattern string, flags string) *_object {
self := runtime.newObject()
self.class = "RegExp"
global := false
ignoreCase := false
multiline := false
re2flags := ""
// TODO Maybe clean up the panicking here... TypeError, SyntaxError, ?
for _, chr := range flags {
switch chr {
case 'g':
if global {
panic(runtime.panicSyntaxError("newRegExpObject: %s %s", pattern, flags))
}
global = true
case 'm':
if multiline {
panic(runtime.panicSyntaxError("newRegExpObject: %s %s", pattern, flags))
}
multiline = true
re2flags += "m"
case 'i':
if ignoreCase {
panic(runtime.panicSyntaxError("newRegExpObject: %s %s", pattern, flags))
}
ignoreCase = true
re2flags += "i"
}
}
re2pattern, err := parser.TransformRegExp(pattern)
if err != nil {
panic(runtime.panicTypeError("Invalid regular expression: %s", err.Error()))
}
if len(re2flags) > 0 {
re2pattern = fmt.Sprintf("(?%s:%s)", re2flags, re2pattern)
}
regularExpression, err := regexp.Compile(re2pattern)
if err != nil {
panic(runtime.panicSyntaxError("Invalid regular expression: %s", err.Error()[22:]))
}
self.value = _regExpObject{
regularExpression: regularExpression,
global: global,
ignoreCase: ignoreCase,
multiline: multiline,
source: pattern,
flags: flags,
}
self.defineProperty("global", toValue_bool(global), 0, false)
self.defineProperty("ignoreCase", toValue_bool(ignoreCase), 0, false)
self.defineProperty("multiline", toValue_bool(multiline), 0, false)
self.defineProperty("lastIndex", toValue_int(0), 0100, false)
self.defineProperty("source", toValue_string(pattern), 0, false)
return self
}
func (self *_object) regExpValue() _regExpObject {
value, _ := self.value.(_regExpObject)
return value
}
func execRegExp(this *_object, target string) (match bool, result []int) {
if this.class != "RegExp" {
panic(this.runtime.panicTypeError("Calling RegExp.exec on a non-RegExp object"))
}
lastIndex := this.get("lastIndex").number().int64
index := lastIndex
global := this.get("global").bool()
if !global {
index = 0
}
if 0 > index || index > int64(len(target)) {
} else {
result = this.regExpValue().regularExpression.FindStringSubmatchIndex(target[index:])
}
if result == nil {
//this.defineProperty("lastIndex", toValue_(0), 0111, true)
this.put("lastIndex", toValue_int(0), true)
return // !match
}
match = true
startIndex := index
endIndex := int(lastIndex) + result[1]
// We do this shift here because the .FindStringSubmatchIndex above
// was done on a local subordinate slice of the string, not the whole string
for index, _ := range result {
result[index] += int(startIndex)
}
if global {
//this.defineProperty("lastIndex", toValue_(endIndex), 0111, true)
this.put("lastIndex", toValue_int(endIndex), true)
}
return // match
}
func execResultToArray(runtime *_runtime, target string, result []int) *_object {
captureCount := len(result) / 2
valueArray := make([]Value, captureCount)
for index := 0; index < captureCount; index++ {
offset := 2 * index
if result[offset] != -1 {
valueArray[index] = toValue_string(target[result[offset]:result[offset+1]])
} else {
valueArray[index] = Value{}
}
}
matchIndex := result[0]
if matchIndex != 0 {
matchIndex = 0
// Find the rune index in the string, not the byte index
for index := 0; index < result[0]; {
_, size := utf8.DecodeRuneInString(target[index:])
matchIndex += 1
index += size
}
}
match := runtime.newArrayOf(valueArray)
match.defineProperty("input", toValue_string(target), 0111, false)
match.defineProperty("index", toValue_int(matchIndex), 0111, false)
return match
}
|