mirror of
https://github.com/robertkrimen/otto
synced 2025-10-12 20:27:30 +08:00

This fixes #68 Some changes over the original patch, removing references to utf8string.String: * (better) This removes a dependency on a non-standard (though solid) package * (better) utf8string.String has mutable parts * (worse) utf8string.String has a smarter consecutive access approach (by remembering where the last access was) * (?) _stringWide allocates a []rune if charAt or charCodeAt access is needed (though it will only do this once for the string object)
215 lines
5.5 KiB
Go
215 lines
5.5 KiB
Go
package otto
|
|
|
|
import (
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
prototypeValueObject = interface{}(nil)
|
|
prototypeValueFunction = _functionObject{
|
|
call: _nativeCallFunction{"", func(_ FunctionCall) Value {
|
|
return UndefinedValue()
|
|
}},
|
|
}
|
|
prototypeValueString = _stringASCII("")
|
|
// TODO Make this just false?
|
|
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
|
|
//self.parser = ast.NewParser()
|
|
|
|
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 toValue_string(value.String())
|
|
}
|
|
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_string(name), 0111, false)
|
|
}
|
|
return self
|
|
}
|
|
|
|
func (runtime *_runtime) newNativeFunction(name string, _nativeFunction _nativeFunction) *_object {
|
|
self := runtime.newNativeFunctionObject(name, _nativeFunction, 0)
|
|
self.prototype = runtime.Global.FunctionPrototype
|
|
prototype := runtime.newObject()
|
|
self.defineProperty("prototype", toValue_object(prototype), 0100, false)
|
|
prototype.defineProperty("constructor", toValue_object(self), 0100, false)
|
|
return self
|
|
}
|
|
|
|
func (runtime *_runtime) newNodeFunction(node *_nodeFunctionLiteral, 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_object(prototype), 0100, false)
|
|
prototype.defineProperty("constructor", toValue_object(self), 0101, false)
|
|
return self
|
|
}
|