123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package goja
- import (
- "fmt"
- "github.com/dlclark/regexp2"
- "github.com/dop251/goja/parser"
- "regexp"
- )
- func (r *Runtime) newRegexpObject(proto *Object) *regexpObject {
- v := &Object{runtime: r}
- o := ®expObject{}
- o.class = classRegExp
- o.val = v
- o.extensible = true
- v.self = o
- o.prototype = proto
- o.init()
- return o
- }
- func (r *Runtime) newRegExpp(pattern regexpPattern, patternStr valueString, global, ignoreCase, multiline bool, proto *Object) *Object {
- o := r.newRegexpObject(proto)
- o.pattern = pattern
- o.source = patternStr
- o.global = global
- o.ignoreCase = ignoreCase
- o.multiline = multiline
- return o.val
- }
- func compileRegexp(patternStr, flags string) (p regexpPattern, global, ignoreCase, multiline bool, err error) {
- if flags != "" {
- invalidFlags := func() {
- err = fmt.Errorf("Invalid flags supplied to RegExp constructor '%s'", flags)
- }
- for _, chr := range flags {
- switch chr {
- case 'g':
- if global {
- invalidFlags()
- return
- }
- global = true
- case 'm':
- if multiline {
- invalidFlags()
- return
- }
- multiline = true
- case 'i':
- if ignoreCase {
- invalidFlags()
- return
- }
- ignoreCase = true
- default:
- invalidFlags()
- return
- }
- }
- }
- re2Str, err1 := parser.TransformRegExp(patternStr)
- if /*false &&*/ err1 == nil {
- re2flags := ""
- if multiline {
- re2flags += "m"
- }
- if ignoreCase {
- re2flags += "i"
- }
- if len(re2flags) > 0 {
- re2Str = fmt.Sprintf("(?%s:%s)", re2flags, re2Str)
- }
- pattern, err1 := regexp.Compile(re2Str)
- if err1 != nil {
- err = fmt.Errorf("Invalid regular expression (re2): %s (%v)", re2Str, err1)
- return
- }
- p = (*regexpWrapper)(pattern)
- } else {
- var opts regexp2.RegexOptions = regexp2.ECMAScript
- if multiline {
- opts |= regexp2.Multiline
- }
- if ignoreCase {
- opts |= regexp2.IgnoreCase
- }
- regexp2Pattern, err1 := regexp2.Compile(patternStr, opts)
- if err1 != nil {
- err = fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", patternStr, err1)
- return
- }
- p = (*regexp2Wrapper)(regexp2Pattern)
- }
- return
- }
- func (r *Runtime) newRegExp(patternStr valueString, flags string, proto *Object) *Object {
- pattern, global, ignoreCase, multiline, err := compileRegexp(patternStr.String(), flags)
- if err != nil {
- panic(r.newSyntaxError(err.Error(), -1))
- }
- return r.newRegExpp(pattern, patternStr, global, ignoreCase, multiline, proto)
- }
- func (r *Runtime) builtin_newRegExp(args []Value) *Object {
- var pattern valueString
- var flags string
- if len(args) > 0 {
- if obj, ok := args[0].(*Object); ok {
- if regexp, ok := obj.self.(*regexpObject); ok {
- if len(args) < 2 || args[1] == _undefined {
- return regexp.clone()
- } else {
- return r.newRegExp(regexp.source, args[1].String(), r.global.RegExpPrototype)
- }
- }
- }
- if args[0] != _undefined {
- pattern = args[0].ToString()
- }
- }
- if len(args) > 1 {
- if a := args[1]; a != _undefined {
- flags = a.String()
- }
- }
- if pattern == nil {
- pattern = stringEmpty
- }
- return r.newRegExp(pattern, flags, r.global.RegExpPrototype)
- }
- func (r *Runtime) builtin_RegExp(call FunctionCall) Value {
- flags := call.Argument(1)
- if flags == _undefined {
- if obj, ok := call.Argument(0).(*Object); ok {
- if _, ok := obj.self.(*regexpObject); ok {
- return call.Arguments[0]
- }
- }
- }
- return r.builtin_newRegExp(call.Arguments)
- }
- func (r *Runtime) regexpproto_exec(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- return this.exec(call.Argument(0).ToString())
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.exec called on incompatible receiver %s", call.This.ToString())
- return nil
- }
- }
- func (r *Runtime) regexpproto_test(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- if this.test(call.Argument(0).ToString()) {
- return valueTrue
- } else {
- return valueFalse
- }
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.test called on incompatible receiver %s", call.This.ToString())
- return nil
- }
- }
- func (r *Runtime) regexpproto_toString(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- var g, i, m string
- if this.global {
- g = "g"
- }
- if this.ignoreCase {
- i = "i"
- }
- if this.multiline {
- m = "m"
- }
- return newStringValue(fmt.Sprintf("/%s/%s%s%s", this.source.String(), g, i, m))
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.toString called on incompatible receiver %s", call.This)
- return nil
- }
- }
- func (r *Runtime) regexpproto_getSource(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- return this.source
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.source getter called on incompatible receiver %s", call.This.ToString())
- return nil
- }
- }
- func (r *Runtime) regexpproto_getGlobal(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- if this.global {
- return valueTrue
- } else {
- return valueFalse
- }
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.global getter called on incompatible receiver %s", call.This.ToString())
- return nil
- }
- }
- func (r *Runtime) regexpproto_getMultiline(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- if this.multiline {
- return valueTrue
- } else {
- return valueFalse
- }
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.multiline getter called on incompatible receiver %s", call.This.ToString())
- return nil
- }
- }
- func (r *Runtime) regexpproto_getIgnoreCase(call FunctionCall) Value {
- if this, ok := r.toObject(call.This).self.(*regexpObject); ok {
- if this.ignoreCase {
- return valueTrue
- } else {
- return valueFalse
- }
- } else {
- r.typeErrorResult(true, "Method RegExp.prototype.ignoreCase getter called on incompatible receiver %s", call.This.ToString())
- return nil
- }
- }
- func (r *Runtime) initRegExp() {
- r.global.RegExpPrototype = r.NewObject()
- o := r.global.RegExpPrototype.self
- o._putProp("exec", r.newNativeFunc(r.regexpproto_exec, nil, "exec", nil, 1), true, false, true)
- o._putProp("test", r.newNativeFunc(r.regexpproto_test, nil, "test", nil, 1), true, false, true)
- o._putProp("toString", r.newNativeFunc(r.regexpproto_toString, nil, "toString", nil, 0), true, false, true)
- o.putStr("source", &valueProperty{
- configurable: true,
- getterFunc: r.newNativeFunc(r.regexpproto_getSource, nil, "get source", nil, 0),
- accessor: true,
- }, false)
- o.putStr("global", &valueProperty{
- configurable: true,
- getterFunc: r.newNativeFunc(r.regexpproto_getGlobal, nil, "get global", nil, 0),
- accessor: true,
- }, false)
- o.putStr("multiline", &valueProperty{
- configurable: true,
- getterFunc: r.newNativeFunc(r.regexpproto_getMultiline, nil, "get multiline", nil, 0),
- accessor: true,
- }, false)
- o.putStr("ignoreCase", &valueProperty{
- configurable: true,
- getterFunc: r.newNativeFunc(r.regexpproto_getIgnoreCase, nil, "get ignoreCase", nil, 0),
- accessor: true,
- }, false)
- r.global.RegExp = r.newNativeFunc(r.builtin_RegExp, r.builtin_newRegExp, "RegExp", r.global.RegExpPrototype, 2)
- r.addToGlobal("RegExp", r.global.RegExp)
- }
|