1
0
mirror of https://github.com/robertkrimen/otto synced 2025-10-19 19:55:30 +08:00
otto/global.go
Robert Krimen c55510cb36 Inline context initialization & improve _object.value
* Context setup is now done via _newContext.
* _newContext is a function that resides in inline.go. _newContext is very flat,
resulting in almost no function calls (a 180 from the earlier status quo).
* inline.go is a Go source file that is built by Perl (via inline).
* Lots of crufty functions removed (along with all of their TODO & FIXME).
* In addition, before, the underlying value of _object.value was a pointer to
something. This made for extra work, since the type of _object.value is interface{},
which is already something of a pointer. Now, the underlying value of _object.value
in Function, Date, RegExp, ..., is a struct value.
* type_function.go was streamlined, removing superfluous struct fields and methods.
* There is now less "digging" to get to the actual value of a function, which is important
when makings lots of calls.

Before (without inline):

    PASS
    BenchmarkNew        2000           1067871 ns/op
    ok      github.com/robertkrimen/otto    3.336s
    PASS
    BenchmarkNew        2000           1077644 ns/op
    ok      github.com/robertkrimen/otto    3.367s

After (with inline):

    PASS
    BenchmarkNew       10000            364418 ns/op
    ok      github.com/robertkrimen/otto    4.616s
    PASS
    BenchmarkNew       10000            307241 ns/op
    ok      github.com/robertkrimen/otto    4.051s

This (partially) fixes #22
2013-06-09 18:28:18 -07:00

219 lines
5.4 KiB
Go

package otto
import (
"strconv"
Time "time"
)
var (
prototypeValueObject = interface{}(nil)
prototypeValueFunction = _functionObject{
call: _nativeCallFunction(func(_ FunctionCall) Value {
return UndefinedValue()
}),
}
prototypeValueString = _stringObject{
value: Value{
_valueType: valueString,
value: "",
},
value16: []uint16(nil),
}
prototypeValueBoolean = Value{
_valueType: valueBoolean,
value: false,
}
prototypeValueNumber = Value{
_valueType: valueNumber,
value: 0,
}
prototypeValueDate = _dateObject{
epoch: 0,
isNaN: false,
time: Time.Unix(0, 0).UTC(),
value: Value{
_valueType: valueNumber,
value: 0,
},
}
prototypeValueRegExp = _regExpObject{
regularExpression: nil,
global: false,
ignoreCase: false,
multiline: false,
source: "",
flags: "",
}
)
func newContext() *_runtime {
self := &_runtime{}
self.GlobalEnvironment = self.newObjectEnvironment(nil, nil)
self.GlobalObject = self.GlobalEnvironment.Object
self.EnterGlobalExecutionContext()
_newContext(self)
self.eval = self.GlobalObject.property["eval"].value.(Value).value.(*_object)
self.GlobalObject.prototype = self.Global.ObjectPrototype
return self
}
func (runtime *_runtime) newBaseObject() *_object {
self := newObject(runtime, "")
return self
}
func (runtime *_runtime) newClassObject(class string) *_object {
return newObject(runtime, class)
}
func (runtime *_runtime) newPrimitiveObject(class string, value Value) *_object {
self := runtime.newClassObject(class)
self.value = value
return self
}
func (self *_object) primitiveValue() Value {
switch value := self.value.(type) {
case Value:
return value
case _stringObject:
return value.value
}
return Value{}
}
func (self *_object) hasPrimitive() bool {
switch self.value.(type) {
case Value, *_stringObject:
return true
}
return false
}
func (runtime *_runtime) newObject() *_object {
self := runtime.newClassObject("Object")
self.prototype = runtime.Global.ObjectPrototype
return self
}
func (runtime *_runtime) newArray(length uint32) *_object {
self := runtime.newArrayObject(length)
self.prototype = runtime.Global.ArrayPrototype
return self
}
func (runtime *_runtime) newArrayOf(valueArray []Value) *_object {
self := runtime.newArray(uint32(len(valueArray)))
for index, value := range valueArray {
if value.isEmpty() {
continue
}
self.defineProperty(strconv.FormatInt(int64(index), 10), value, 0111, false)
}
return self
}
func (runtime *_runtime) newString(value Value) *_object {
self := runtime.newStringObject(value)
self.prototype = runtime.Global.StringPrototype
return self
}
func (runtime *_runtime) newBoolean(value Value) *_object {
self := runtime.newBooleanObject(value)
self.prototype = runtime.Global.BooleanPrototype
return self
}
func (runtime *_runtime) newNumber(value Value) *_object {
self := runtime.newNumberObject(value)
self.prototype = runtime.Global.NumberPrototype
return self
}
func (runtime *_runtime) newRegExp(patternValue Value, flagsValue Value) *_object {
pattern := ""
flags := ""
if object := patternValue._object(); object != nil && object.class == "RegExp" {
if flagsValue.IsDefined() {
panic(newTypeError("Cannot supply flags when constructing one RegExp from another"))
}
regExp := object.regExpValue()
pattern = regExp.source
flags = regExp.flags
} else {
if patternValue.IsDefined() {
pattern = toString(patternValue)
}
if flagsValue.IsDefined() {
flags = toString(flagsValue)
}
}
return runtime._newRegExp(pattern, flags)
}
func (runtime *_runtime) _newRegExp(pattern string, flags string) *_object {
self := runtime.newRegExpObject(pattern, flags)
self.prototype = runtime.Global.RegExpPrototype
return self
}
// TODO Should (probably) be one argument, right? This is redundant
func (runtime *_runtime) newDate(epoch float64) *_object {
self := runtime.newDateObject(epoch)
self.prototype = runtime.Global.DatePrototype
return self
}
func (runtime *_runtime) newError(name string, message Value) *_object {
var self *_object
switch name {
case "EvalError":
return runtime.newEvalError(message)
case "TypeError":
return runtime.newTypeError(message)
case "RangeError":
return runtime.newRangeError(message)
case "ReferenceError":
return runtime.newReferenceError(message)
case "SyntaxError":
return runtime.newSyntaxError(message)
case "URIError":
return runtime.newURIError(message)
}
self = runtime.newErrorObject(message)
self.prototype = runtime.Global.ErrorPrototype
if name != "" {
self.defineProperty("name", toValue(name), 0111, false)
}
return self
}
func (runtime *_runtime) newNativeFunction(_nativeFunction _nativeFunction) *_object {
self := runtime.newNativeFunctionObject(_nativeFunction, 0)
self.prototype = runtime.Global.FunctionPrototype
prototype := runtime.newObject()
self.defineProperty("prototype", toValue(prototype), 0100, false)
prototype.defineProperty("constructor", toValue(self), 0100, false)
return self
}
func (runtime *_runtime) newNodeFunction(node *_functionNode, scopeEnvironment _environment) *_object {
// TODO Implement 13.2 fully
self := runtime.newNodeFunctionObject(node, scopeEnvironment)
self.prototype = runtime.Global.FunctionPrototype
prototype := runtime.newObject()
self.defineProperty("prototype", toValue(prototype), 0100, false)
prototype.defineProperty("constructor", toValue(self), 0101, false)
return self
}