123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- package otto
- import (
- "strconv"
- "time"
- )
- var (
- prototypeValueObject = interface{}(nil)
- prototypeValueFunction = nativeFunctionObject{
- call: func(_ FunctionCall) Value {
- return Value{}
- },
- }
- prototypeValueString = stringASCII("")
- // TODO Make this just false?
- prototypeValueBoolean = Value{
- kind: valueBoolean,
- value: false,
- }
- prototypeValueNumber = Value{
- kind: valueNumber,
- value: 0,
- }
- prototypeValueDate = dateObject{
- epoch: 0,
- isNaN: false,
- time: time.Unix(0, 0).UTC(),
- value: Value{
- kind: valueNumber,
- value: 0,
- },
- }
- prototypeValueRegExp = regExpObject{
- regularExpression: nil,
- global: false,
- ignoreCase: false,
- multiline: false,
- source: "",
- flags: "",
- }
- )
- func newContext() *runtime {
- rt := &runtime{}
- rt.globalStash = rt.newObjectStash(nil, nil)
- rt.globalObject = rt.globalStash.object
- rt.newContext()
- rt.eval = rt.globalObject.property["eval"].value.(Value).value.(*object)
- rt.globalObject.prototype = rt.global.ObjectPrototype
- return rt
- }
- func (rt *runtime) newBaseObject() *object {
- return newObject(rt, "")
- }
- func (rt *runtime) newClassObject(class string) *object {
- return newObject(rt, class)
- }
- func (rt *runtime) newPrimitiveObject(class string, value Value) *object {
- o := rt.newClassObject(class)
- o.value = value
- return o
- }
- func (o *object) primitiveValue() Value {
- switch value := o.value.(type) {
- case Value:
- return value
- case stringObjecter:
- return stringValue(value.String())
- }
- return Value{}
- }
- func (o *object) hasPrimitive() bool { //nolint:unused
- switch o.value.(type) {
- case Value, stringObjecter:
- return true
- }
- return false
- }
- func (rt *runtime) newObject() *object {
- o := rt.newClassObject(classObjectName)
- o.prototype = rt.global.ObjectPrototype
- return o
- }
- func (rt *runtime) newArray(length uint32) *object {
- o := rt.newArrayObject(length)
- o.prototype = rt.global.ArrayPrototype
- return o
- }
- func (rt *runtime) newArrayOf(valueArray []Value) *object {
- o := rt.newArray(uint32(len(valueArray)))
- for index, value := range valueArray {
- if value.isEmpty() {
- continue
- }
- o.defineProperty(strconv.FormatInt(int64(index), 10), value, 0o111, false)
- }
- return o
- }
- func (rt *runtime) newString(value Value) *object {
- o := rt.newStringObject(value)
- o.prototype = rt.global.StringPrototype
- return o
- }
- func (rt *runtime) newBoolean(value Value) *object {
- o := rt.newBooleanObject(value)
- o.prototype = rt.global.BooleanPrototype
- return o
- }
- func (rt *runtime) newNumber(value Value) *object {
- o := rt.newNumberObject(value)
- o.prototype = rt.global.NumberPrototype
- return o
- }
- func (rt *runtime) newRegExp(patternValue Value, flagsValue Value) *object {
- pattern := ""
- flags := ""
- if obj := patternValue.object(); obj != nil && obj.class == classRegExpName {
- if flagsValue.IsDefined() {
- panic(rt.panicTypeError("Cannot supply flags when constructing one RegExp from another"))
- }
- regExp := obj.regExpValue()
- pattern = regExp.source
- flags = regExp.flags
- } else {
- if patternValue.IsDefined() {
- pattern = patternValue.string()
- }
- if flagsValue.IsDefined() {
- flags = flagsValue.string()
- }
- }
- return rt.newRegExpDirect(pattern, flags)
- }
- func (rt *runtime) newRegExpDirect(pattern string, flags string) *object {
- o := rt.newRegExpObject(pattern, flags)
- o.prototype = rt.global.RegExpPrototype
- return o
- }
- // TODO Should (probably) be one argument, right? This is redundant.
- func (rt *runtime) newDate(epoch float64) *object {
- o := rt.newDateObject(epoch)
- o.prototype = rt.global.DatePrototype
- return o
- }
- func (rt *runtime) newError(name string, message Value, stackFramesToPop int) *object {
- switch name {
- case "EvalError":
- return rt.newEvalError(message)
- case "TypeError":
- return rt.newTypeError(message)
- case "RangeError":
- return rt.newRangeError(message)
- case "ReferenceError":
- return rt.newReferenceError(message)
- case "SyntaxError":
- return rt.newSyntaxError(message)
- case "URIError":
- return rt.newURIError(message)
- }
- obj := rt.newErrorObject(name, message, stackFramesToPop)
- obj.prototype = rt.global.ErrorPrototype
- if name != "" {
- obj.defineProperty("name", stringValue(name), 0o111, false)
- }
- return obj
- }
- func (rt *runtime) newNativeFunction(name, file string, line int, fn nativeFunction) *object {
- o := rt.newNativeFunctionObject(name, file, line, fn, 0)
- o.prototype = rt.global.FunctionPrototype
- prototype := rt.newObject()
- o.defineProperty("prototype", objectValue(prototype), 0o100, false)
- prototype.defineProperty("constructor", objectValue(o), 0o100, false)
- return o
- }
- func (rt *runtime) newNodeFunction(node *nodeFunctionLiteral, scopeEnvironment stasher) *object {
- // TODO Implement 13.2 fully
- o := rt.newNodeFunctionObject(node, scopeEnvironment)
- o.prototype = rt.global.FunctionPrototype
- prototype := rt.newObject()
- o.defineProperty("prototype", objectValue(prototype), 0o100, false)
- prototype.defineProperty("constructor", objectValue(o), 0o101, false)
- return o
- }
- // FIXME Only in one place...
- func (rt *runtime) newBoundFunction(target *object, this Value, argumentList []Value) *object {
- o := rt.newBoundFunctionObject(target, this, argumentList)
- o.prototype = rt.global.FunctionPrototype
- prototype := rt.newObject()
- o.defineProperty("prototype", objectValue(prototype), 0o100, false)
- prototype.defineProperty("constructor", objectValue(o), 0o100, false)
- return o
- }
|