snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s

This commit is contained in:
upstream-mirror
2026-09-18 01:22:23 +05:00
commit 7e385fc126
8391 changed files with 1766236 additions and 0 deletions

3
server/vendor/github.com/dop251/goja/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
.idea
*.iml
testdata/test262

View File

@@ -0,0 +1,11 @@
#!/bin/sh
# this is just the commit it was last tested with
sha=926b0960d737b9f1dfd0ec0c1dfd95d836016d33
mkdir -p testdata/test262
cd testdata/test262
git init
git remote add origin https://github.com/tc39/test262.git
git fetch origin --depth=1 "${sha}"
git reset --hard "${sha}"
cd -

15
server/vendor/github.com/dop251/goja/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,15 @@
Copyright (c) 2016 Dmitry Panov
Copyright (c) 2012 Robert Krimen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

332
server/vendor/github.com/dop251/goja/README.md generated vendored Normal file
View File

@@ -0,0 +1,332 @@
goja
====
ECMAScript 5.1(+) implementation in Go.
[![Go Reference](https://pkg.go.dev/badge/github.com/dop251/goja.svg)](https://pkg.go.dev/github.com/dop251/goja)
Goja is an implementation of ECMAScript 5.1 in pure Go with emphasis on standard compliance and
performance.
This project was largely inspired by [otto](https://github.com/robertkrimen/otto).
Minimum required Go version is 1.16.
Features
--------
* Full ECMAScript 5.1 support (including regex and strict mode).
* Passes nearly all [tc39 tests](https://github.com/tc39/test262) for the features implemented so far. The goal is to
pass all of them. See .tc39_test262_checkout.sh for the latest working commit id.
* Capable of running Babel, Typescript compiler and pretty much anything written in ES5.
* Sourcemaps.
* Most of ES6 functionality, still work in progress, see https://github.com/dop251/goja/milestone/1?closed=1
Known incompatibilities and caveats
-----------------------------------
### WeakMap
WeakMap is implemented by embedding references to the values into the keys. This means that as long
as the key is reachable all values associated with it in any weak maps also remain reachable and therefore
cannot be garbage collected even if they are not otherwise referenced, even after the WeakMap is gone.
The reference to the value is dropped either when the key is explicitly removed from the WeakMap or when the
key becomes unreachable.
To illustrate this:
```javascript
var m = new WeakMap();
var key = {};
var value = {/* a very large object */};
m.set(key, value);
value = undefined;
m = undefined; // The value does NOT become garbage-collectable at this point
key = undefined; // Now it does
// m.delete(key); // This would work too
```
The reason for it is the limitation of the Go runtime. At the time of writing (version 1.15) having a finalizer
set on an object which is part of a reference cycle makes the whole cycle non-garbage-collectable. The solution
above is the only reasonable way I can think of without involving finalizers. This is the third attempt
(see https://github.com/dop251/goja/issues/250 and https://github.com/dop251/goja/issues/199 for more details).
Note, this does not have any effect on the application logic, but may cause a higher-than-expected memory usage.
### WeakRef and FinalizationRegistry
For the reason mentioned above implementing WeakRef and FinalizationRegistry does not seem to be possible at this stage.
### JSON
`JSON.parse()` uses the standard Go library which operates in UTF-8. Therefore, it cannot correctly parse broken UTF-16
surrogate pairs, for example:
```javascript
JSON.parse(`"\\uD800"`).charCodeAt(0).toString(16) // returns "fffd" instead of "d800"
```
### Date
Conversion from calendar date to epoch timestamp uses the standard Go library which uses `int`, rather than `float` as per
ECMAScript specification. This means if you pass arguments that overflow int to the `Date()` constructor or if there is
an integer overflow, the result will be incorrect, for example:
```javascript
Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740) // returns 29256 instead of 29312
```
FAQ
---
### How fast is it?
Although it's faster than many scripting language implementations in Go I have seen
(for example it's 6-7 times faster than otto on average) it is not a
replacement for V8 or SpiderMonkey or any other general-purpose JavaScript engine.
You can find some benchmarks [here](https://github.com/dop251/goja/issues/2).
### Why would I want to use it over a V8 wrapper?
It greatly depends on your usage scenario. If most of the work is done in javascript
(for example crypto or any other heavy calculations) you are definitely better off with V8.
If you need a scripting language that drives an engine written in Go so that
you need to make frequent calls between Go and javascript passing complex data structures
then the cgo overhead may outweigh the benefits of having a faster javascript engine.
Because it's written in pure Go there are no cgo dependencies, it's very easy to build and it
should run on any platform supported by Go.
It gives you a much better control over execution environment so can be useful for research.
### Is it goroutine-safe?
No. An instance of goja.Runtime can only be used by a single goroutine
at a time. You can create as many instances of Runtime as you like but
it's not possible to pass object values between runtimes.
### Where is setTimeout()?
setTimeout() assumes concurrent execution of code which requires an execution
environment, for example an event loop similar to nodejs or a browser.
There is a [separate project](https://github.com/dop251/goja_nodejs) aimed at providing some NodeJS functionality,
and it includes an event loop.
### Can you implement (feature X from ES6 or higher)?
I will be adding features in their dependency order and as quickly as time permits. Please do not ask
for ETAs. Features that are open in the [milestone](https://github.com/dop251/goja/milestone/1) are either in progress
or will be worked on next.
The ongoing work is done in separate feature branches which are merged into master when appropriate.
Every commit in these branches represents a relatively stable state (i.e. it compiles and passes all enabled tc39 tests),
however because the version of tc39 tests I use is quite old, it may be not as well tested as the ES5.1 functionality. Because there are (usually) no major breaking changes between ECMAScript revisions
it should not break your existing code. You are encouraged to give it a try and report any bugs found. Please do not submit fixes though without discussing it first, as the code could be changed in the meantime.
### How do I contribute?
Before submitting a pull request please make sure that:
- You followed ECMA standard as close as possible. If adding a new feature make sure you've read the specification,
do not just base it on a couple of examples that work fine.
- Your change does not have a significant negative impact on performance (unless it's a bugfix and it's unavoidable)
- It passes all relevant tc39 tests.
Current Status
--------------
* There should be no breaking changes in the API, however it may be extended.
* Some of the AnnexB functionality is missing.
Basic Example
-------------
Run JavaScript and get the result value.
```go
vm := goja.New()
v, err := vm.RunString("2 + 2")
if err != nil {
panic(err)
}
if num := v.Export().(int64); num != 4 {
panic(num)
}
```
Passing Values to JS
--------------------
Any Go value can be passed to JS using Runtime.ToValue() method. See the method's [documentation](https://pkg.go.dev/github.com/dop251/goja#Runtime.ToValue) for more details.
Exporting Values from JS
------------------------
A JS value can be exported into its default Go representation using Value.Export() method.
Alternatively it can be exported into a specific Go variable using [Runtime.ExportTo()](https://pkg.go.dev/github.com/dop251/goja#Runtime.ExportTo) method.
Within a single export operation the same Object will be represented by the same Go value (either the same map, slice or
a pointer to the same struct). This includes circular objects and makes it possible to export them.
Calling JS functions from Go
----------------------------
There are 2 approaches:
- Using [AssertFunction()](https://pkg.go.dev/github.com/dop251/goja#AssertFunction):
```go
vm := New()
_, err := vm.RunString(`
function sum(a, b) {
return a+b;
}
`)
if err != nil {
panic(err)
}
sum, ok := AssertFunction(vm.Get("sum"))
if !ok {
panic("Not a function")
}
res, err := sum(Undefined(), vm.ToValue(40), vm.ToValue(2))
if err != nil {
panic(err)
}
fmt.Println(res)
// Output: 42
```
- Using [Runtime.ExportTo()](https://pkg.go.dev/github.com/dop251/goja#Runtime.ExportTo):
```go
const SCRIPT = `
function f(param) {
return +param + 2;
}
`
vm := New()
_, err := vm.RunString(SCRIPT)
if err != nil {
panic(err)
}
var fn func(string) string
err = vm.ExportTo(vm.Get("f"), &fn)
if err != nil {
panic(err)
}
fmt.Println(fn("40")) // note, _this_ value in the function will be undefined.
// Output: 42
```
The first one is more low level and allows specifying _this_ value, whereas the second one makes the function look like
a normal Go function.
Mapping struct field and method names
-------------------------------------
By default, the names are passed through as is which means they are capitalised. This does not match
the standard JavaScript naming convention, so if you need to make your JS code look more natural or if you are
dealing with a 3rd party library, you can use a [FieldNameMapper](https://pkg.go.dev/github.com/dop251/goja#FieldNameMapper):
```go
vm := New()
vm.SetFieldNameMapper(TagFieldNameMapper("json", true))
type S struct {
Field int `json:"field"`
}
vm.Set("s", S{Field: 42})
res, _ := vm.RunString(`s.field`) // without the mapper it would have been s.Field
fmt.Println(res.Export())
// Output: 42
```
There are two standard mappers: [TagFieldNameMapper](https://pkg.go.dev/github.com/dop251/goja#TagFieldNameMapper) and
[UncapFieldNameMapper](https://pkg.go.dev/github.com/dop251/goja#UncapFieldNameMapper), or you can use your own implementation.
Native Constructors
-------------------
In order to implement a constructor function in Go use `func (goja.ConstructorCall) *goja.Object`.
See [Runtime.ToValue()](https://pkg.go.dev/github.com/dop251/goja#Runtime.ToValue) documentation for more details.
Regular Expressions
-------------------
Goja uses the embedded Go regexp library where possible, otherwise it falls back to [regexp2](https://github.com/dlclark/regexp2).
Exceptions
----------
Any exception thrown in JavaScript is returned as an error of type *Exception. It is possible to extract the value thrown
by using the Value() method:
```go
vm := New()
_, err := vm.RunString(`
throw("Test");
`)
if jserr, ok := err.(*Exception); ok {
if jserr.Value().Export() != "Test" {
panic("wrong value")
}
} else {
panic("wrong type")
}
```
If a native Go function panics with a Value, it is thrown as a Javascript exception (and therefore can be caught):
```go
var vm *Runtime
func Test() {
panic(vm.ToValue("Error"))
}
vm = New()
vm.Set("Test", Test)
_, err := vm.RunString(`
try {
Test();
} catch(e) {
if (e !== "Error") {
throw e;
}
}
`)
if err != nil {
panic(err)
}
```
Interrupting
------------
```go
func TestInterrupt(t *testing.T) {
const SCRIPT = `
var i = 0;
for (;;) {
i++;
}
`
vm := New()
time.AfterFunc(200 * time.Millisecond, func() {
vm.Interrupt("halt")
})
_, err := vm.RunString(SCRIPT)
if err == nil {
t.Fatal("Err is nil")
}
// err is of type *InterruptError and its Value() method returns whatever has been passed to vm.Interrupt()
}
```
NodeJS Compatibility
--------------------
There is a [separate project](https://github.com/dop251/goja_nodejs) aimed at providing some of the NodeJS functionality.

553
server/vendor/github.com/dop251/goja/array.go generated vendored Normal file
View File

@@ -0,0 +1,553 @@
package goja
import (
"fmt"
"math"
"math/bits"
"reflect"
"strconv"
"github.com/dop251/goja/unistring"
)
type arrayIterObject struct {
baseObject
obj *Object
nextIdx int64
kind iterationKind
}
func (ai *arrayIterObject) next() Value {
if ai.obj == nil {
return ai.val.runtime.createIterResultObject(_undefined, true)
}
if ta, ok := ai.obj.self.(*typedArrayObject); ok {
ta.viewedArrayBuf.ensureNotDetached(true)
}
l := toLength(ai.obj.self.getStr("length", nil))
index := ai.nextIdx
if index >= l {
ai.obj = nil
return ai.val.runtime.createIterResultObject(_undefined, true)
}
ai.nextIdx++
idxVal := valueInt(index)
if ai.kind == iterationKindKey {
return ai.val.runtime.createIterResultObject(idxVal, false)
}
elementValue := nilSafe(ai.obj.self.getIdx(idxVal, nil))
var result Value
if ai.kind == iterationKindValue {
result = elementValue
} else {
result = ai.val.runtime.newArrayValues([]Value{idxVal, elementValue})
}
return ai.val.runtime.createIterResultObject(result, false)
}
func (r *Runtime) createArrayIterator(iterObj *Object, kind iterationKind) Value {
o := &Object{runtime: r}
ai := &arrayIterObject{
obj: iterObj,
kind: kind,
}
ai.class = classObject
ai.val = o
ai.extensible = true
o.self = ai
ai.prototype = r.getArrayIteratorPrototype()
ai.init()
return o
}
type arrayObject struct {
baseObject
values []Value
length uint32
objCount int
propValueCount int
lengthProp valueProperty
}
func (a *arrayObject) init() {
a.baseObject.init()
a.lengthProp.writable = true
a._put("length", &a.lengthProp)
}
func (a *arrayObject) _setLengthInt(l uint32, throw bool) bool {
ret := true
if l <= a.length {
if a.propValueCount > 0 {
// Slow path
for i := len(a.values) - 1; i >= int(l); i-- {
if prop, ok := a.values[i].(*valueProperty); ok {
if !prop.configurable {
l = uint32(i) + 1
ret = false
break
}
a.propValueCount--
}
}
}
}
if l <= uint32(len(a.values)) {
if l >= 16 && l < uint32(cap(a.values))>>2 {
ar := make([]Value, l)
copy(ar, a.values)
a.values = ar
} else {
ar := a.values[l:len(a.values)]
for i := range ar {
ar[i] = nil
}
a.values = a.values[:l]
}
}
a.length = l
if !ret {
a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
}
return ret
}
func (a *arrayObject) setLengthInt(l uint32, throw bool) bool {
if l == a.length {
return true
}
if !a.lengthProp.writable {
a.val.runtime.typeErrorResult(throw, "length is not writable")
return false
}
return a._setLengthInt(l, throw)
}
func (a *arrayObject) setLength(v uint32, throw bool) bool {
if !a.lengthProp.writable {
a.val.runtime.typeErrorResult(throw, "length is not writable")
return false
}
return a._setLengthInt(v, throw)
}
func (a *arrayObject) getIdx(idx valueInt, receiver Value) Value {
prop := a.getOwnPropIdx(idx)
if prop == nil {
if a.prototype != nil {
if receiver == nil {
return a.prototype.self.getIdx(idx, a.val)
}
return a.prototype.self.getIdx(idx, receiver)
}
}
if prop, ok := prop.(*valueProperty); ok {
if receiver == nil {
return prop.get(a.val)
}
return prop.get(receiver)
}
return prop
}
func (a *arrayObject) getOwnPropStr(name unistring.String) Value {
if len(a.values) > 0 {
if i := strToArrayIdx(name); i != math.MaxUint32 {
if i < uint32(len(a.values)) {
return a.values[i]
}
}
}
if name == "length" {
return a.getLengthProp()
}
return a.baseObject.getOwnPropStr(name)
}
func (a *arrayObject) getOwnPropIdx(idx valueInt) Value {
if i := toIdx(idx); i != math.MaxUint32 {
if i < uint32(len(a.values)) {
return a.values[i]
}
return nil
}
return a.baseObject.getOwnPropStr(idx.string())
}
func (a *arrayObject) sortLen() int {
return len(a.values)
}
func (a *arrayObject) sortGet(i int) Value {
v := a.values[i]
if p, ok := v.(*valueProperty); ok {
v = p.get(a.val)
}
return v
}
func (a *arrayObject) swap(i int, j int) {
a.values[i], a.values[j] = a.values[j], a.values[i]
}
func (a *arrayObject) getStr(name unistring.String, receiver Value) Value {
return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
}
func (a *arrayObject) getLengthProp() *valueProperty {
a.lengthProp.value = intToValue(int64(a.length))
return &a.lengthProp
}
func (a *arrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
if i := toIdx(idx); i != math.MaxUint32 {
return a._setOwnIdx(i, val, throw)
} else {
return a.baseObject.setOwnStr(idx.string(), val, throw)
}
}
func (a *arrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
var prop Value
if idx < uint32(len(a.values)) {
prop = a.values[idx]
}
if prop == nil {
if proto := a.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
return res
}
}
// new property
if !a.extensible {
a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
return false
} else {
if idx >= a.length {
if !a.setLengthInt(idx+1, throw) {
return false
}
}
if idx >= uint32(len(a.values)) {
if !a.expand(idx) {
a.val.self.(*sparseArrayObject).add(idx, val)
return true
}
}
a.objCount++
}
} else {
if prop, ok := prop.(*valueProperty); ok {
if !prop.isWritable() {
a.val.runtime.typeErrorResult(throw)
return false
}
prop.set(a.val, val)
return true
}
}
a.values[idx] = val
return true
}
func (a *arrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._setOwnIdx(idx, val, throw)
} else {
if name == "length" {
return a.setLength(a.val.runtime.toLengthUint32(val), throw)
} else {
return a.baseObject.setOwnStr(name, val, throw)
}
}
}
func (a *arrayObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignIdx(idx, a.getOwnPropIdx(idx), val, receiver, throw)
}
func (a *arrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
}
type arrayPropIter struct {
a *arrayObject
limit int
idx int
}
func (i *arrayPropIter) next() (propIterItem, iterNextFunc) {
for i.idx < len(i.a.values) && i.idx < i.limit {
name := asciiString(strconv.Itoa(i.idx))
prop := i.a.values[i.idx]
i.idx++
if prop != nil {
return propIterItem{name: name, value: prop}, i.next
}
}
return i.a.baseObject.iterateStringKeys()()
}
func (a *arrayObject) iterateStringKeys() iterNextFunc {
return (&arrayPropIter{
a: a,
limit: len(a.values),
}).next
}
func (a *arrayObject) stringKeys(all bool, accum []Value) []Value {
for i, prop := range a.values {
name := strconv.Itoa(i)
if prop != nil {
if !all {
if prop, ok := prop.(*valueProperty); ok && !prop.enumerable {
continue
}
}
accum = append(accum, asciiString(name))
}
}
return a.baseObject.stringKeys(all, accum)
}
func (a *arrayObject) hasOwnPropertyStr(name unistring.String) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return idx < uint32(len(a.values)) && a.values[idx] != nil
} else {
return a.baseObject.hasOwnPropertyStr(name)
}
}
func (a *arrayObject) hasOwnPropertyIdx(idx valueInt) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return idx < uint32(len(a.values)) && a.values[idx] != nil
}
return a.baseObject.hasOwnPropertyStr(idx.string())
}
func (a *arrayObject) expand(idx uint32) bool {
targetLen := idx + 1
if targetLen > uint32(len(a.values)) {
if targetLen < uint32(cap(a.values)) {
a.values = a.values[:targetLen]
} else {
if idx > 4096 && (a.objCount == 0 || idx/uint32(a.objCount) > 10) {
//log.Println("Switching standard->sparse")
sa := &sparseArrayObject{
baseObject: a.baseObject,
length: a.length,
propValueCount: a.propValueCount,
}
sa.setValues(a.values, a.objCount+1)
sa.val.self = sa
sa.lengthProp.writable = a.lengthProp.writable
sa._put("length", &sa.lengthProp)
return false
} else {
if bits.UintSize == 32 {
if targetLen >= math.MaxInt32 {
panic(a.val.runtime.NewTypeError("Array index overflows int"))
}
}
tl := int(targetLen)
newValues := make([]Value, tl, growCap(tl, len(a.values), cap(a.values)))
copy(newValues, a.values)
a.values = newValues
}
}
}
return true
}
func (r *Runtime) defineArrayLength(prop *valueProperty, descr PropertyDescriptor, setter func(uint32, bool) bool, throw bool) bool {
var newLen uint32
ret := true
if descr.Value != nil {
newLen = r.toLengthUint32(descr.Value)
}
if descr.Configurable == FLAG_TRUE || descr.Enumerable == FLAG_TRUE || descr.Getter != nil || descr.Setter != nil {
ret = false
goto Reject
}
if descr.Value != nil {
oldLen := uint32(prop.value.ToInteger())
if oldLen != newLen {
ret = setter(newLen, false)
}
} else {
ret = true
}
if descr.Writable != FLAG_NOT_SET {
w := descr.Writable.Bool()
if prop.writable {
prop.writable = w
} else {
if w {
ret = false
goto Reject
}
}
}
Reject:
if !ret {
r.typeErrorResult(throw, "Cannot redefine property: length")
}
return ret
}
func (a *arrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
var existing Value
if idx < uint32(len(a.values)) {
existing = a.values[idx]
}
prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
if ok {
if idx >= a.length {
if !a.setLengthInt(idx+1, throw) {
return false
}
}
if a.expand(idx) {
a.values[idx] = prop
a.objCount++
if _, ok := prop.(*valueProperty); ok {
a.propValueCount++
}
} else {
a.val.self.(*sparseArrayObject).add(idx, prop)
}
}
return ok
}
func (a *arrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._defineIdxProperty(idx, descr, throw)
}
if name == "length" {
return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw)
}
return a.baseObject.defineOwnPropertyStr(name, descr, throw)
}
func (a *arrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._defineIdxProperty(idx, descr, throw)
}
return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
}
func (a *arrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
if idx < uint32(len(a.values)) {
if v := a.values[idx]; v != nil {
if p, ok := v.(*valueProperty); ok {
if !p.configurable {
a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
return false
}
a.propValueCount--
}
a.values[idx] = nil
a.objCount--
}
}
return true
}
func (a *arrayObject) deleteStr(name unistring.String, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._deleteIdxProp(idx, throw)
}
return a.baseObject.deleteStr(name, throw)
}
func (a *arrayObject) deleteIdx(idx valueInt, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._deleteIdxProp(idx, throw)
}
return a.baseObject.deleteStr(idx.string(), throw)
}
func (a *arrayObject) export(ctx *objectExportCtx) interface{} {
if v, exists := ctx.get(a.val); exists {
return v
}
arr := make([]interface{}, a.length)
ctx.put(a.val, arr)
if a.propValueCount == 0 && a.length == uint32(len(a.values)) && uint32(a.objCount) == a.length {
for i, v := range a.values {
if v != nil {
arr[i] = exportValue(v, ctx)
}
}
} else {
for i := uint32(0); i < a.length; i++ {
v := a.getIdx(valueInt(i), nil)
if v != nil {
arr[i] = exportValue(v, ctx)
}
}
}
return arr
}
func (a *arrayObject) exportType() reflect.Type {
return reflectTypeArray
}
func (a *arrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
r := a.val.runtime
if iter := a.getSym(SymIterator, nil); iter == r.global.arrayValues || iter == nil {
l := toIntStrict(int64(a.length))
if typ.Kind() == reflect.Array {
if dst.Len() != l {
return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len())
}
} else {
dst.Set(reflect.MakeSlice(typ, l, l))
}
ctx.putTyped(a.val, typ, dst.Interface())
for i := 0; i < l; i++ {
if i >= len(a.values) {
break
}
val := a.values[i]
if p, ok := val.(*valueProperty); ok {
val = p.get(a.val)
}
err := r.toReflectValue(val, dst.Index(i), ctx)
if err != nil {
return fmt.Errorf("could not convert array element %v to %v at %d: %w", val, typ, i, err)
}
}
return nil
}
return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
}
func (a *arrayObject) setValuesFromSparse(items []sparseArrayItem, newMaxIdx int) {
a.values = make([]Value, newMaxIdx+1)
for _, item := range items {
a.values[item.idx] = item.value
}
a.objCount = len(items)
}
func toIdx(v valueInt) uint32 {
if v >= 0 && v < math.MaxUint32 {
return uint32(v)
}
return math.MaxUint32
}

488
server/vendor/github.com/dop251/goja/array_sparse.go generated vendored Normal file
View File

@@ -0,0 +1,488 @@
package goja
import (
"fmt"
"math"
"math/bits"
"reflect"
"sort"
"strconv"
"github.com/dop251/goja/unistring"
)
type sparseArrayItem struct {
idx uint32
value Value
}
type sparseArrayObject struct {
baseObject
items []sparseArrayItem
length uint32
propValueCount int
lengthProp valueProperty
}
func (a *sparseArrayObject) findIdx(idx uint32) int {
return sort.Search(len(a.items), func(i int) bool {
return a.items[i].idx >= idx
})
}
func (a *sparseArrayObject) _setLengthInt(l uint32, throw bool) bool {
ret := true
if l <= a.length {
if a.propValueCount > 0 {
// Slow path
for i := len(a.items) - 1; i >= 0; i-- {
item := a.items[i]
if item.idx <= l {
break
}
if prop, ok := item.value.(*valueProperty); ok {
if !prop.configurable {
l = item.idx + 1
ret = false
break
}
a.propValueCount--
}
}
}
}
idx := a.findIdx(l)
aa := a.items[idx:]
for i := range aa {
aa[i].value = nil
}
a.items = a.items[:idx]
a.length = l
if !ret {
a.val.runtime.typeErrorResult(throw, "Cannot redefine property: length")
}
return ret
}
func (a *sparseArrayObject) setLengthInt(l uint32, throw bool) bool {
if l == a.length {
return true
}
if !a.lengthProp.writable {
a.val.runtime.typeErrorResult(throw, "length is not writable")
return false
}
return a._setLengthInt(l, throw)
}
func (a *sparseArrayObject) setLength(v uint32, throw bool) bool {
if !a.lengthProp.writable {
a.val.runtime.typeErrorResult(throw, "length is not writable")
return false
}
return a._setLengthInt(v, throw)
}
func (a *sparseArrayObject) _getIdx(idx uint32) Value {
i := a.findIdx(idx)
if i < len(a.items) && a.items[i].idx == idx {
return a.items[i].value
}
return nil
}
func (a *sparseArrayObject) getStr(name unistring.String, receiver Value) Value {
return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
}
func (a *sparseArrayObject) getIdx(idx valueInt, receiver Value) Value {
prop := a.getOwnPropIdx(idx)
if prop == nil {
if a.prototype != nil {
if receiver == nil {
return a.prototype.self.getIdx(idx, a.val)
}
return a.prototype.self.getIdx(idx, receiver)
}
}
if prop, ok := prop.(*valueProperty); ok {
if receiver == nil {
return prop.get(a.val)
}
return prop.get(receiver)
}
return prop
}
func (a *sparseArrayObject) getLengthProp() *valueProperty {
a.lengthProp.value = intToValue(int64(a.length))
return &a.lengthProp
}
func (a *sparseArrayObject) getOwnPropStr(name unistring.String) Value {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._getIdx(idx)
}
if name == "length" {
return a.getLengthProp()
}
return a.baseObject.getOwnPropStr(name)
}
func (a *sparseArrayObject) getOwnPropIdx(idx valueInt) Value {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._getIdx(idx)
}
return a.baseObject.getOwnPropStr(idx.string())
}
func (a *sparseArrayObject) add(idx uint32, val Value) {
i := a.findIdx(idx)
a.items = append(a.items, sparseArrayItem{})
copy(a.items[i+1:], a.items[i:])
a.items[i] = sparseArrayItem{
idx: idx,
value: val,
}
}
func (a *sparseArrayObject) _setOwnIdx(idx uint32, val Value, throw bool) bool {
var prop Value
i := a.findIdx(idx)
if i < len(a.items) && a.items[i].idx == idx {
prop = a.items[i].value
}
if prop == nil {
if proto := a.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, ok := proto.self.setForeignIdx(valueInt(idx), val, a.val, throw); ok {
return res
}
}
// new property
if !a.extensible {
a.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
return false
}
if idx >= a.length {
if !a.setLengthInt(idx+1, throw) {
return false
}
}
if a.expand(idx) {
a.items = append(a.items, sparseArrayItem{})
copy(a.items[i+1:], a.items[i:])
a.items[i] = sparseArrayItem{
idx: idx,
value: val,
}
} else {
ar := a.val.self.(*arrayObject)
ar.values[idx] = val
ar.objCount++
return true
}
} else {
if prop, ok := prop.(*valueProperty); ok {
if !prop.isWritable() {
a.val.runtime.typeErrorResult(throw)
return false
}
prop.set(a.val, val)
} else {
a.items[i].value = val
}
}
return true
}
func (a *sparseArrayObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._setOwnIdx(idx, val, throw)
} else {
if name == "length" {
return a.setLength(a.val.runtime.toLengthUint32(val), throw)
} else {
return a.baseObject.setOwnStr(name, val, throw)
}
}
}
func (a *sparseArrayObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._setOwnIdx(idx, val, throw)
}
return a.baseObject.setOwnStr(idx.string(), val, throw)
}
func (a *sparseArrayObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
}
func (a *sparseArrayObject) setForeignIdx(name valueInt, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignIdx(name, a.getOwnPropIdx(name), val, receiver, throw)
}
type sparseArrayPropIter struct {
a *sparseArrayObject
idx int
}
func (i *sparseArrayPropIter) next() (propIterItem, iterNextFunc) {
for i.idx < len(i.a.items) {
name := asciiString(strconv.Itoa(int(i.a.items[i.idx].idx)))
prop := i.a.items[i.idx].value
i.idx++
if prop != nil {
return propIterItem{name: name, value: prop}, i.next
}
}
return i.a.baseObject.iterateStringKeys()()
}
func (a *sparseArrayObject) iterateStringKeys() iterNextFunc {
return (&sparseArrayPropIter{
a: a,
}).next
}
func (a *sparseArrayObject) stringKeys(all bool, accum []Value) []Value {
if all {
for _, item := range a.items {
accum = append(accum, asciiString(strconv.FormatUint(uint64(item.idx), 10)))
}
} else {
for _, item := range a.items {
if prop, ok := item.value.(*valueProperty); ok && !prop.enumerable {
continue
}
accum = append(accum, asciiString(strconv.FormatUint(uint64(item.idx), 10)))
}
}
return a.baseObject.stringKeys(all, accum)
}
func (a *sparseArrayObject) setValues(values []Value, objCount int) {
a.items = make([]sparseArrayItem, 0, objCount)
for i, val := range values {
if val != nil {
a.items = append(a.items, sparseArrayItem{
idx: uint32(i),
value: val,
})
}
}
}
func (a *sparseArrayObject) hasOwnPropertyStr(name unistring.String) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
i := a.findIdx(idx)
return i < len(a.items) && a.items[i].idx == idx
} else {
return a.baseObject.hasOwnPropertyStr(name)
}
}
func (a *sparseArrayObject) hasOwnPropertyIdx(idx valueInt) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
i := a.findIdx(idx)
return i < len(a.items) && a.items[i].idx == idx
}
return a.baseObject.hasOwnPropertyStr(idx.string())
}
func (a *sparseArrayObject) expand(idx uint32) bool {
if l := len(a.items); l >= 1024 {
if ii := a.items[l-1].idx; ii > idx {
idx = ii
}
if (bits.UintSize == 64 || idx < math.MaxInt32) && int(idx)>>3 < l {
//log.Println("Switching sparse->standard")
ar := &arrayObject{
baseObject: a.baseObject,
length: a.length,
propValueCount: a.propValueCount,
}
ar.setValuesFromSparse(a.items, int(idx))
ar.val.self = ar
ar.lengthProp.writable = a.lengthProp.writable
a._put("length", &ar.lengthProp)
return false
}
}
return true
}
func (a *sparseArrayObject) _defineIdxProperty(idx uint32, desc PropertyDescriptor, throw bool) bool {
var existing Value
i := a.findIdx(idx)
if i < len(a.items) && a.items[i].idx == idx {
existing = a.items[i].value
}
prop, ok := a.baseObject._defineOwnProperty(unistring.String(strconv.FormatUint(uint64(idx), 10)), existing, desc, throw)
if ok {
if idx >= a.length {
if !a.setLengthInt(idx+1, throw) {
return false
}
}
if i >= len(a.items) || a.items[i].idx != idx {
if a.expand(idx) {
a.items = append(a.items, sparseArrayItem{})
copy(a.items[i+1:], a.items[i:])
a.items[i] = sparseArrayItem{
idx: idx,
value: prop,
}
if idx >= a.length {
a.length = idx + 1
}
} else {
a.val.self.(*arrayObject).values[idx] = prop
}
} else {
a.items[i].value = prop
}
if _, ok := prop.(*valueProperty); ok {
a.propValueCount++
}
}
return ok
}
func (a *sparseArrayObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._defineIdxProperty(idx, descr, throw)
}
if name == "length" {
return a.val.runtime.defineArrayLength(a.getLengthProp(), descr, a.setLength, throw)
}
return a.baseObject.defineOwnPropertyStr(name, descr, throw)
}
func (a *sparseArrayObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._defineIdxProperty(idx, descr, throw)
}
return a.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
}
func (a *sparseArrayObject) _deleteIdxProp(idx uint32, throw bool) bool {
i := a.findIdx(idx)
if i < len(a.items) && a.items[i].idx == idx {
if p, ok := a.items[i].value.(*valueProperty); ok {
if !p.configurable {
a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.toString())
return false
}
a.propValueCount--
}
copy(a.items[i:], a.items[i+1:])
a.items[len(a.items)-1].value = nil
a.items = a.items[:len(a.items)-1]
}
return true
}
func (a *sparseArrayObject) deleteStr(name unistring.String, throw bool) bool {
if idx := strToArrayIdx(name); idx != math.MaxUint32 {
return a._deleteIdxProp(idx, throw)
}
return a.baseObject.deleteStr(name, throw)
}
func (a *sparseArrayObject) deleteIdx(idx valueInt, throw bool) bool {
if idx := toIdx(idx); idx != math.MaxUint32 {
return a._deleteIdxProp(idx, throw)
}
return a.baseObject.deleteStr(idx.string(), throw)
}
func (a *sparseArrayObject) sortLen() int {
if len(a.items) > 0 {
return toIntStrict(int64(a.items[len(a.items)-1].idx) + 1)
}
return 0
}
func (a *sparseArrayObject) export(ctx *objectExportCtx) interface{} {
if v, exists := ctx.get(a.val); exists {
return v
}
arr := make([]interface{}, a.length)
ctx.put(a.val, arr)
var prevIdx uint32
for _, item := range a.items {
idx := item.idx
for i := prevIdx; i < idx; i++ {
if a.prototype != nil {
if v := a.prototype.self.getIdx(valueInt(i), nil); v != nil {
arr[i] = exportValue(v, ctx)
}
}
}
v := item.value
if v != nil {
if prop, ok := v.(*valueProperty); ok {
v = prop.get(a.val)
}
arr[idx] = exportValue(v, ctx)
}
prevIdx = idx + 1
}
for i := prevIdx; i < a.length; i++ {
if a.prototype != nil {
if v := a.prototype.self.getIdx(valueInt(i), nil); v != nil {
arr[i] = exportValue(v, ctx)
}
}
}
return arr
}
func (a *sparseArrayObject) exportType() reflect.Type {
return reflectTypeArray
}
func (a *sparseArrayObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
r := a.val.runtime
if iter := a.getSym(SymIterator, nil); iter == r.global.arrayValues || iter == nil {
l := toIntStrict(int64(a.length))
if typ.Kind() == reflect.Array {
if dst.Len() != l {
return fmt.Errorf("cannot convert an Array into an array, lengths mismatch (have %d, need %d)", l, dst.Len())
}
} else {
dst.Set(reflect.MakeSlice(typ, l, l))
}
ctx.putTyped(a.val, typ, dst.Interface())
for _, item := range a.items {
val := item.value
if p, ok := val.(*valueProperty); ok {
val = p.get(a.val)
}
idx := toIntStrict(int64(item.idx))
if idx >= l {
break
}
err := r.toReflectValue(val, dst.Index(idx), ctx)
if err != nil {
return fmt.Errorf("could not convert array element %v to %v at %d: %w", item.value, typ, idx, err)
}
}
return nil
}
return a.baseObject.exportToArrayOrSlice(dst, typ, ctx)
}

1068
server/vendor/github.com/dop251/goja/ast/README.markdown generated vendored Normal file

File diff suppressed because it is too large Load Diff

859
server/vendor/github.com/dop251/goja/ast/node.go generated vendored Normal file
View File

@@ -0,0 +1,859 @@
/*
Package ast declares types representing a JavaScript AST.
# Warning
The parser and AST interfaces are still works-in-progress (particularly where
node types are concerned) and may change in the future.
*/
package ast
import (
"github.com/dop251/goja/file"
"github.com/dop251/goja/token"
"github.com/dop251/goja/unistring"
)
type PropertyKind string
const (
PropertyKindValue PropertyKind = "value"
PropertyKindGet PropertyKind = "get"
PropertyKindSet PropertyKind = "set"
PropertyKindMethod PropertyKind = "method"
)
// All nodes implement the Node interface.
type Node interface {
Idx0() file.Idx // The index of the first character belonging to the node
Idx1() file.Idx // The index of the first character immediately after the node
}
// ========== //
// Expression //
// ========== //
type (
// All expression nodes implement the Expression interface.
Expression interface {
Node
_expressionNode()
}
BindingTarget interface {
Expression
_bindingTarget()
}
Binding struct {
Target BindingTarget
Initializer Expression
}
Pattern interface {
BindingTarget
_pattern()
}
YieldExpression struct {
Yield file.Idx
Argument Expression
Delegate bool
}
AwaitExpression struct {
Await file.Idx
Argument Expression
}
ArrayLiteral struct {
LeftBracket file.Idx
RightBracket file.Idx
Value []Expression
}
ArrayPattern struct {
LeftBracket file.Idx
RightBracket file.Idx
Elements []Expression
Rest Expression
}
AssignExpression struct {
Operator token.Token
Left Expression
Right Expression
}
BadExpression struct {
From file.Idx
To file.Idx
}
BinaryExpression struct {
Operator token.Token
Left Expression
Right Expression
Comparison bool
}
BooleanLiteral struct {
Idx file.Idx
Literal string
Value bool
}
BracketExpression struct {
Left Expression
Member Expression
LeftBracket file.Idx
RightBracket file.Idx
}
CallExpression struct {
Callee Expression
LeftParenthesis file.Idx
ArgumentList []Expression
RightParenthesis file.Idx
}
ConditionalExpression struct {
Test Expression
Consequent Expression
Alternate Expression
}
DotExpression struct {
Left Expression
Identifier Identifier
}
PrivateDotExpression struct {
Left Expression
Identifier PrivateIdentifier
}
OptionalChain struct {
Expression
}
Optional struct {
Expression
}
FunctionLiteral struct {
Function file.Idx
Name *Identifier
ParameterList *ParameterList
Body *BlockStatement
Source string
DeclarationList []*VariableDeclaration
Async, Generator bool
}
ClassLiteral struct {
Class file.Idx
RightBrace file.Idx
Name *Identifier
SuperClass Expression
Body []ClassElement
Source string
}
ConciseBody interface {
Node
_conciseBody()
}
ExpressionBody struct {
Expression Expression
}
ArrowFunctionLiteral struct {
Start file.Idx
ParameterList *ParameterList
Body ConciseBody
Source string
DeclarationList []*VariableDeclaration
Async bool
}
Identifier struct {
Name unistring.String
Idx file.Idx
}
PrivateIdentifier struct {
Identifier
}
NewExpression struct {
New file.Idx
Callee Expression
LeftParenthesis file.Idx
ArgumentList []Expression
RightParenthesis file.Idx
}
NullLiteral struct {
Idx file.Idx
Literal string
}
NumberLiteral struct {
Idx file.Idx
Literal string
Value interface{}
}
ObjectLiteral struct {
LeftBrace file.Idx
RightBrace file.Idx
Value []Property
}
ObjectPattern struct {
LeftBrace file.Idx
RightBrace file.Idx
Properties []Property
Rest Expression
}
ParameterList struct {
Opening file.Idx
List []*Binding
Rest Expression
Closing file.Idx
}
Property interface {
Expression
_property()
}
PropertyShort struct {
Name Identifier
Initializer Expression
}
PropertyKeyed struct {
Key Expression
Kind PropertyKind
Value Expression
Computed bool
}
SpreadElement struct {
Expression
}
RegExpLiteral struct {
Idx file.Idx
Literal string
Pattern string
Flags string
}
SequenceExpression struct {
Sequence []Expression
}
StringLiteral struct {
Idx file.Idx
Literal string
Value unistring.String
}
TemplateElement struct {
Idx file.Idx
Literal string
Parsed unistring.String
Valid bool
}
TemplateLiteral struct {
OpenQuote file.Idx
CloseQuote file.Idx
Tag Expression
Elements []*TemplateElement
Expressions []Expression
}
ThisExpression struct {
Idx file.Idx
}
SuperExpression struct {
Idx file.Idx
}
UnaryExpression struct {
Operator token.Token
Idx file.Idx // If a prefix operation
Operand Expression
Postfix bool
}
MetaProperty struct {
Meta, Property *Identifier
Idx file.Idx
}
)
// _expressionNode
func (*ArrayLiteral) _expressionNode() {}
func (*AssignExpression) _expressionNode() {}
func (*YieldExpression) _expressionNode() {}
func (*AwaitExpression) _expressionNode() {}
func (*BadExpression) _expressionNode() {}
func (*BinaryExpression) _expressionNode() {}
func (*BooleanLiteral) _expressionNode() {}
func (*BracketExpression) _expressionNode() {}
func (*CallExpression) _expressionNode() {}
func (*ConditionalExpression) _expressionNode() {}
func (*DotExpression) _expressionNode() {}
func (*PrivateDotExpression) _expressionNode() {}
func (*FunctionLiteral) _expressionNode() {}
func (*ClassLiteral) _expressionNode() {}
func (*ArrowFunctionLiteral) _expressionNode() {}
func (*Identifier) _expressionNode() {}
func (*NewExpression) _expressionNode() {}
func (*NullLiteral) _expressionNode() {}
func (*NumberLiteral) _expressionNode() {}
func (*ObjectLiteral) _expressionNode() {}
func (*RegExpLiteral) _expressionNode() {}
func (*SequenceExpression) _expressionNode() {}
func (*StringLiteral) _expressionNode() {}
func (*TemplateLiteral) _expressionNode() {}
func (*ThisExpression) _expressionNode() {}
func (*SuperExpression) _expressionNode() {}
func (*UnaryExpression) _expressionNode() {}
func (*MetaProperty) _expressionNode() {}
func (*ObjectPattern) _expressionNode() {}
func (*ArrayPattern) _expressionNode() {}
func (*Binding) _expressionNode() {}
func (*PropertyShort) _expressionNode() {}
func (*PropertyKeyed) _expressionNode() {}
// ========= //
// Statement //
// ========= //
type (
// All statement nodes implement the Statement interface.
Statement interface {
Node
_statementNode()
}
BadStatement struct {
From file.Idx
To file.Idx
}
BlockStatement struct {
LeftBrace file.Idx
List []Statement
RightBrace file.Idx
}
BranchStatement struct {
Idx file.Idx
Token token.Token
Label *Identifier
}
CaseStatement struct {
Case file.Idx
Test Expression
Consequent []Statement
}
CatchStatement struct {
Catch file.Idx
Parameter BindingTarget
Body *BlockStatement
}
DebuggerStatement struct {
Debugger file.Idx
}
DoWhileStatement struct {
Do file.Idx
Test Expression
Body Statement
}
EmptyStatement struct {
Semicolon file.Idx
}
ExpressionStatement struct {
Expression Expression
}
ForInStatement struct {
For file.Idx
Into ForInto
Source Expression
Body Statement
}
ForOfStatement struct {
For file.Idx
Into ForInto
Source Expression
Body Statement
}
ForStatement struct {
For file.Idx
Initializer ForLoopInitializer
Update Expression
Test Expression
Body Statement
}
IfStatement struct {
If file.Idx
Test Expression
Consequent Statement
Alternate Statement
}
LabelledStatement struct {
Label *Identifier
Colon file.Idx
Statement Statement
}
ReturnStatement struct {
Return file.Idx
Argument Expression
}
SwitchStatement struct {
Switch file.Idx
Discriminant Expression
Default int
Body []*CaseStatement
}
ThrowStatement struct {
Throw file.Idx
Argument Expression
}
TryStatement struct {
Try file.Idx
Body *BlockStatement
Catch *CatchStatement
Finally *BlockStatement
}
VariableStatement struct {
Var file.Idx
List []*Binding
}
LexicalDeclaration struct {
Idx file.Idx
Token token.Token
List []*Binding
}
WhileStatement struct {
While file.Idx
Test Expression
Body Statement
}
WithStatement struct {
With file.Idx
Object Expression
Body Statement
}
FunctionDeclaration struct {
Function *FunctionLiteral
}
ClassDeclaration struct {
Class *ClassLiteral
}
)
// _statementNode
func (*BadStatement) _statementNode() {}
func (*BlockStatement) _statementNode() {}
func (*BranchStatement) _statementNode() {}
func (*CaseStatement) _statementNode() {}
func (*CatchStatement) _statementNode() {}
func (*DebuggerStatement) _statementNode() {}
func (*DoWhileStatement) _statementNode() {}
func (*EmptyStatement) _statementNode() {}
func (*ExpressionStatement) _statementNode() {}
func (*ForInStatement) _statementNode() {}
func (*ForOfStatement) _statementNode() {}
func (*ForStatement) _statementNode() {}
func (*IfStatement) _statementNode() {}
func (*LabelledStatement) _statementNode() {}
func (*ReturnStatement) _statementNode() {}
func (*SwitchStatement) _statementNode() {}
func (*ThrowStatement) _statementNode() {}
func (*TryStatement) _statementNode() {}
func (*VariableStatement) _statementNode() {}
func (*WhileStatement) _statementNode() {}
func (*WithStatement) _statementNode() {}
func (*LexicalDeclaration) _statementNode() {}
func (*FunctionDeclaration) _statementNode() {}
func (*ClassDeclaration) _statementNode() {}
// =========== //
// Declaration //
// =========== //
type (
VariableDeclaration struct {
Var file.Idx
List []*Binding
}
ClassElement interface {
Node
_classElement()
}
FieldDefinition struct {
Idx file.Idx
Key Expression
Initializer Expression
Computed bool
Static bool
}
MethodDefinition struct {
Idx file.Idx
Key Expression
Kind PropertyKind // "method", "get" or "set"
Body *FunctionLiteral
Computed bool
Static bool
}
ClassStaticBlock struct {
Static file.Idx
Block *BlockStatement
Source string
DeclarationList []*VariableDeclaration
}
)
type (
ForLoopInitializer interface {
Node
_forLoopInitializer()
}
ForLoopInitializerExpression struct {
Expression Expression
}
ForLoopInitializerVarDeclList struct {
Var file.Idx
List []*Binding
}
ForLoopInitializerLexicalDecl struct {
LexicalDeclaration LexicalDeclaration
}
ForInto interface {
Node
_forInto()
}
ForIntoVar struct {
Binding *Binding
}
ForDeclaration struct {
Idx file.Idx
IsConst bool
Target BindingTarget
}
ForIntoExpression struct {
Expression Expression
}
)
func (*ForLoopInitializerExpression) _forLoopInitializer() {}
func (*ForLoopInitializerVarDeclList) _forLoopInitializer() {}
func (*ForLoopInitializerLexicalDecl) _forLoopInitializer() {}
func (*ForIntoVar) _forInto() {}
func (*ForDeclaration) _forInto() {}
func (*ForIntoExpression) _forInto() {}
func (*ArrayPattern) _pattern() {}
func (*ArrayPattern) _bindingTarget() {}
func (*ObjectPattern) _pattern() {}
func (*ObjectPattern) _bindingTarget() {}
func (*BadExpression) _bindingTarget() {}
func (*PropertyShort) _property() {}
func (*PropertyKeyed) _property() {}
func (*SpreadElement) _property() {}
func (*Identifier) _bindingTarget() {}
func (*BlockStatement) _conciseBody() {}
func (*ExpressionBody) _conciseBody() {}
func (*FieldDefinition) _classElement() {}
func (*MethodDefinition) _classElement() {}
func (*ClassStaticBlock) _classElement() {}
// ==== //
// Node //
// ==== //
type Program struct {
Body []Statement
DeclarationList []*VariableDeclaration
File *file.File
}
// ==== //
// Idx0 //
// ==== //
func (self *ArrayLiteral) Idx0() file.Idx { return self.LeftBracket }
func (self *ArrayPattern) Idx0() file.Idx { return self.LeftBracket }
func (self *YieldExpression) Idx0() file.Idx { return self.Yield }
func (self *AwaitExpression) Idx0() file.Idx { return self.Await }
func (self *ObjectPattern) Idx0() file.Idx { return self.LeftBrace }
func (self *ParameterList) Idx0() file.Idx { return self.Opening }
func (self *AssignExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *BadExpression) Idx0() file.Idx { return self.From }
func (self *BinaryExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *BooleanLiteral) Idx0() file.Idx { return self.Idx }
func (self *BracketExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *CallExpression) Idx0() file.Idx { return self.Callee.Idx0() }
func (self *ConditionalExpression) Idx0() file.Idx { return self.Test.Idx0() }
func (self *DotExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *PrivateDotExpression) Idx0() file.Idx { return self.Left.Idx0() }
func (self *FunctionLiteral) Idx0() file.Idx { return self.Function }
func (self *ClassLiteral) Idx0() file.Idx { return self.Class }
func (self *ArrowFunctionLiteral) Idx0() file.Idx { return self.Start }
func (self *Identifier) Idx0() file.Idx { return self.Idx }
func (self *NewExpression) Idx0() file.Idx { return self.New }
func (self *NullLiteral) Idx0() file.Idx { return self.Idx }
func (self *NumberLiteral) Idx0() file.Idx { return self.Idx }
func (self *ObjectLiteral) Idx0() file.Idx { return self.LeftBrace }
func (self *RegExpLiteral) Idx0() file.Idx { return self.Idx }
func (self *SequenceExpression) Idx0() file.Idx { return self.Sequence[0].Idx0() }
func (self *StringLiteral) Idx0() file.Idx { return self.Idx }
func (self *TemplateElement) Idx0() file.Idx { return self.Idx }
func (self *TemplateLiteral) Idx0() file.Idx { return self.OpenQuote }
func (self *ThisExpression) Idx0() file.Idx { return self.Idx }
func (self *SuperExpression) Idx0() file.Idx { return self.Idx }
func (self *UnaryExpression) Idx0() file.Idx { return self.Idx }
func (self *MetaProperty) Idx0() file.Idx { return self.Idx }
func (self *BadStatement) Idx0() file.Idx { return self.From }
func (self *BlockStatement) Idx0() file.Idx { return self.LeftBrace }
func (self *BranchStatement) Idx0() file.Idx { return self.Idx }
func (self *CaseStatement) Idx0() file.Idx { return self.Case }
func (self *CatchStatement) Idx0() file.Idx { return self.Catch }
func (self *DebuggerStatement) Idx0() file.Idx { return self.Debugger }
func (self *DoWhileStatement) Idx0() file.Idx { return self.Do }
func (self *EmptyStatement) Idx0() file.Idx { return self.Semicolon }
func (self *ExpressionStatement) Idx0() file.Idx { return self.Expression.Idx0() }
func (self *ForInStatement) Idx0() file.Idx { return self.For }
func (self *ForOfStatement) Idx0() file.Idx { return self.For }
func (self *ForStatement) Idx0() file.Idx { return self.For }
func (self *IfStatement) Idx0() file.Idx { return self.If }
func (self *LabelledStatement) Idx0() file.Idx { return self.Label.Idx0() }
func (self *Program) Idx0() file.Idx { return self.Body[0].Idx0() }
func (self *ReturnStatement) Idx0() file.Idx { return self.Return }
func (self *SwitchStatement) Idx0() file.Idx { return self.Switch }
func (self *ThrowStatement) Idx0() file.Idx { return self.Throw }
func (self *TryStatement) Idx0() file.Idx { return self.Try }
func (self *VariableStatement) Idx0() file.Idx { return self.Var }
func (self *WhileStatement) Idx0() file.Idx { return self.While }
func (self *WithStatement) Idx0() file.Idx { return self.With }
func (self *LexicalDeclaration) Idx0() file.Idx { return self.Idx }
func (self *FunctionDeclaration) Idx0() file.Idx { return self.Function.Idx0() }
func (self *ClassDeclaration) Idx0() file.Idx { return self.Class.Idx0() }
func (self *Binding) Idx0() file.Idx { return self.Target.Idx0() }
func (self *ForLoopInitializerExpression) Idx0() file.Idx { return self.Expression.Idx0() }
func (self *ForLoopInitializerVarDeclList) Idx0() file.Idx { return self.List[0].Idx0() }
func (self *ForLoopInitializerLexicalDecl) Idx0() file.Idx { return self.LexicalDeclaration.Idx0() }
func (self *PropertyShort) Idx0() file.Idx { return self.Name.Idx }
func (self *PropertyKeyed) Idx0() file.Idx { return self.Key.Idx0() }
func (self *ExpressionBody) Idx0() file.Idx { return self.Expression.Idx0() }
func (self *VariableDeclaration) Idx0() file.Idx { return self.Var }
func (self *FieldDefinition) Idx0() file.Idx { return self.Idx }
func (self *MethodDefinition) Idx0() file.Idx { return self.Idx }
func (self *ClassStaticBlock) Idx0() file.Idx { return self.Static }
func (self *ForDeclaration) Idx0() file.Idx { return self.Idx }
func (self *ForIntoVar) Idx0() file.Idx { return self.Binding.Idx0() }
func (self *ForIntoExpression) Idx0() file.Idx { return self.Expression.Idx0() }
// ==== //
// Idx1 //
// ==== //
func (self *ArrayLiteral) Idx1() file.Idx { return self.RightBracket + 1 }
func (self *ArrayPattern) Idx1() file.Idx { return self.RightBracket + 1 }
func (self *AssignExpression) Idx1() file.Idx { return self.Right.Idx1() }
func (self *AwaitExpression) Idx1() file.Idx { return self.Argument.Idx1() }
func (self *BadExpression) Idx1() file.Idx { return self.To }
func (self *BinaryExpression) Idx1() file.Idx { return self.Right.Idx1() }
func (self *BooleanLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *BracketExpression) Idx1() file.Idx { return self.RightBracket + 1 }
func (self *CallExpression) Idx1() file.Idx { return self.RightParenthesis + 1 }
func (self *ConditionalExpression) Idx1() file.Idx { return self.Test.Idx1() }
func (self *DotExpression) Idx1() file.Idx { return self.Identifier.Idx1() }
func (self *PrivateDotExpression) Idx1() file.Idx { return self.Identifier.Idx1() }
func (self *FunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() }
func (self *ClassLiteral) Idx1() file.Idx { return self.RightBrace + 1 }
func (self *ArrowFunctionLiteral) Idx1() file.Idx { return self.Body.Idx1() }
func (self *Identifier) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Name)) }
func (self *NewExpression) Idx1() file.Idx {
if self.ArgumentList != nil {
return self.RightParenthesis + 1
} else {
return self.Callee.Idx1()
}
}
func (self *NullLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + 4) } // "null"
func (self *NumberLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *ObjectLiteral) Idx1() file.Idx { return self.RightBrace + 1 }
func (self *ObjectPattern) Idx1() file.Idx { return self.RightBrace + 1 }
func (self *ParameterList) Idx1() file.Idx { return self.Closing + 1 }
func (self *RegExpLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *SequenceExpression) Idx1() file.Idx { return self.Sequence[len(self.Sequence)-1].Idx1() }
func (self *StringLiteral) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *TemplateElement) Idx1() file.Idx { return file.Idx(int(self.Idx) + len(self.Literal)) }
func (self *TemplateLiteral) Idx1() file.Idx { return self.CloseQuote + 1 }
func (self *ThisExpression) Idx1() file.Idx { return self.Idx + 4 }
func (self *SuperExpression) Idx1() file.Idx { return self.Idx + 5 }
func (self *UnaryExpression) Idx1() file.Idx {
if self.Postfix {
return self.Operand.Idx1() + 2 // ++ --
}
return self.Operand.Idx1()
}
func (self *MetaProperty) Idx1() file.Idx {
return self.Property.Idx1()
}
func (self *BadStatement) Idx1() file.Idx { return self.To }
func (self *BlockStatement) Idx1() file.Idx { return self.RightBrace + 1 }
func (self *BranchStatement) Idx1() file.Idx { return self.Idx }
func (self *CaseStatement) Idx1() file.Idx { return self.Consequent[len(self.Consequent)-1].Idx1() }
func (self *CatchStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *DebuggerStatement) Idx1() file.Idx { return self.Debugger + 8 }
func (self *DoWhileStatement) Idx1() file.Idx { return self.Test.Idx1() }
func (self *EmptyStatement) Idx1() file.Idx { return self.Semicolon + 1 }
func (self *ExpressionStatement) Idx1() file.Idx { return self.Expression.Idx1() }
func (self *ForInStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *ForOfStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *ForStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *IfStatement) Idx1() file.Idx {
if self.Alternate != nil {
return self.Alternate.Idx1()
}
return self.Consequent.Idx1()
}
func (self *LabelledStatement) Idx1() file.Idx { return self.Colon + 1 }
func (self *Program) Idx1() file.Idx { return self.Body[len(self.Body)-1].Idx1() }
func (self *ReturnStatement) Idx1() file.Idx { return self.Return + 6 }
func (self *SwitchStatement) Idx1() file.Idx { return self.Body[len(self.Body)-1].Idx1() }
func (self *ThrowStatement) Idx1() file.Idx { return self.Argument.Idx1() }
func (self *TryStatement) Idx1() file.Idx {
if self.Finally != nil {
return self.Finally.Idx1()
}
if self.Catch != nil {
return self.Catch.Idx1()
}
return self.Body.Idx1()
}
func (self *VariableStatement) Idx1() file.Idx { return self.List[len(self.List)-1].Idx1() }
func (self *WhileStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *WithStatement) Idx1() file.Idx { return self.Body.Idx1() }
func (self *LexicalDeclaration) Idx1() file.Idx { return self.List[len(self.List)-1].Idx1() }
func (self *FunctionDeclaration) Idx1() file.Idx { return self.Function.Idx1() }
func (self *ClassDeclaration) Idx1() file.Idx { return self.Class.Idx1() }
func (self *Binding) Idx1() file.Idx {
if self.Initializer != nil {
return self.Initializer.Idx1()
}
return self.Target.Idx1()
}
func (self *ForLoopInitializerExpression) Idx1() file.Idx { return self.Expression.Idx1() }
func (self *ForLoopInitializerVarDeclList) Idx1() file.Idx { return self.List[len(self.List)-1].Idx1() }
func (self *ForLoopInitializerLexicalDecl) Idx1() file.Idx { return self.LexicalDeclaration.Idx1() }
func (self *PropertyShort) Idx1() file.Idx {
if self.Initializer != nil {
return self.Initializer.Idx1()
}
return self.Name.Idx1()
}
func (self *PropertyKeyed) Idx1() file.Idx { return self.Value.Idx1() }
func (self *ExpressionBody) Idx1() file.Idx { return self.Expression.Idx1() }
func (self *VariableDeclaration) Idx1() file.Idx {
if len(self.List) > 0 {
return self.List[len(self.List)-1].Idx1()
}
return self.Var + 3
}
func (self *FieldDefinition) Idx1() file.Idx {
if self.Initializer != nil {
return self.Initializer.Idx1()
}
return self.Key.Idx1()
}
func (self *MethodDefinition) Idx1() file.Idx {
return self.Body.Idx1()
}
func (self *ClassStaticBlock) Idx1() file.Idx {
return self.Block.Idx1()
}
func (self *YieldExpression) Idx1() file.Idx {
if self.Argument != nil {
return self.Argument.Idx1()
}
return self.Yield + 5
}
func (self *ForDeclaration) Idx1() file.Idx { return self.Target.Idx1() }
func (self *ForIntoVar) Idx1() file.Idx { return self.Binding.Idx1() }
func (self *ForIntoExpression) Idx1() file.Idx { return self.Expression.Idx1() }

1567
server/vendor/github.com/dop251/goja/builtin_array.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
package goja
func (r *Runtime) booleanproto_toString(call FunctionCall) Value {
var b bool
switch o := call.This.(type) {
case valueBool:
b = bool(o)
goto success
case *Object:
if p, ok := o.self.(*primitiveValueObject); ok {
if b1, ok := p.pValue.(valueBool); ok {
b = bool(b1)
goto success
}
}
}
r.typeErrorResult(true, "Method Boolean.prototype.toString is called on incompatible receiver")
success:
if b {
return stringTrue
}
return stringFalse
}
func (r *Runtime) booleanproto_valueOf(call FunctionCall) Value {
switch o := call.This.(type) {
case valueBool:
return o
case *Object:
if p, ok := o.self.(*primitiveValueObject); ok {
if b, ok := p.pValue.(valueBool); ok {
return b
}
}
}
r.typeErrorResult(true, "Method Boolean.prototype.valueOf is called on incompatible receiver")
return nil
}
func (r *Runtime) initBoolean() {
r.global.BooleanPrototype = r.newPrimitiveObject(valueFalse, r.global.ObjectPrototype, classBoolean)
o := r.global.BooleanPrototype.self
o._putProp("toString", r.newNativeFunc(r.booleanproto_toString, nil, "toString", nil, 0), true, false, true)
o._putProp("valueOf", r.newNativeFunc(r.booleanproto_valueOf, nil, "valueOf", nil, 0), true, false, true)
r.global.Boolean = r.newNativeFunc(r.builtin_Boolean, r.builtin_newBoolean, "Boolean", r.global.BooleanPrototype, 1)
r.addToGlobal("Boolean", r.global.Boolean)
}

1015
server/vendor/github.com/dop251/goja/builtin_date.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

236
server/vendor/github.com/dop251/goja/builtin_error.go generated vendored Normal file
View File

@@ -0,0 +1,236 @@
package goja
import "github.com/dop251/goja/unistring"
const propNameStack = "stack"
type errorObject struct {
baseObject
stack []StackFrame
stackPropAdded bool
}
func (e *errorObject) formatStack() valueString {
var b valueStringBuilder
val := writeErrorString(&b, e.val)
if val != nil {
b.WriteString(val)
}
b.WriteRune('\n')
for _, frame := range e.stack {
b.WriteASCII("\tat ")
frame.WriteToValueBuilder(&b)
b.WriteRune('\n')
}
return b.String()
}
func (e *errorObject) addStackProp() Value {
if !e.stackPropAdded {
res := e._putProp(propNameStack, e.formatStack(), true, false, true)
if len(e.propNames) > 1 {
// reorder property names to ensure 'stack' is the first one
copy(e.propNames[1:], e.propNames)
e.propNames[0] = propNameStack
}
e.stackPropAdded = true
return res
}
return nil
}
func (e *errorObject) getStr(p unistring.String, receiver Value) Value {
return e.getStrWithOwnProp(e.getOwnPropStr(p), p, receiver)
}
func (e *errorObject) getOwnPropStr(name unistring.String) Value {
res := e.baseObject.getOwnPropStr(name)
if res == nil && name == propNameStack {
return e.addStackProp()
}
return res
}
func (e *errorObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
if name == propNameStack {
e.addStackProp()
}
return e.baseObject.setOwnStr(name, val, throw)
}
func (e *errorObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return e._setForeignStr(name, e.getOwnPropStr(name), val, receiver, throw)
}
func (e *errorObject) deleteStr(name unistring.String, throw bool) bool {
if name == propNameStack {
e.addStackProp()
}
return e.baseObject.deleteStr(name, throw)
}
func (e *errorObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
if name == propNameStack {
e.addStackProp()
}
return e.baseObject.defineOwnPropertyStr(name, desc, throw)
}
func (e *errorObject) hasOwnPropertyStr(name unistring.String) bool {
if e.baseObject.hasOwnPropertyStr(name) {
return true
}
return name == propNameStack && !e.stackPropAdded
}
func (e *errorObject) stringKeys(all bool, accum []Value) []Value {
if all && !e.stackPropAdded {
accum = append(accum, asciiString(propNameStack))
}
return e.baseObject.stringKeys(all, accum)
}
func (e *errorObject) iterateStringKeys() iterNextFunc {
e.addStackProp()
return e.baseObject.iterateStringKeys()
}
func (e *errorObject) init() {
e.baseObject.init()
vm := e.val.runtime.vm
e.stack = vm.captureStack(make([]StackFrame, 0, len(vm.callStack)+1), 0)
}
func (r *Runtime) newErrorObject(proto *Object, class string) *errorObject {
obj := &Object{runtime: r}
o := &errorObject{
baseObject: baseObject{
class: class,
val: obj,
extensible: true,
prototype: proto,
},
}
obj.self = o
o.init()
return o
}
func (r *Runtime) builtin_Error(args []Value, proto *Object) *Object {
obj := r.newErrorObject(proto, classError)
if len(args) > 0 && args[0] != _undefined {
obj._putProp("message", args[0], true, false, true)
}
return obj.val
}
func (r *Runtime) builtin_AggregateError(args []Value, proto *Object) *Object {
obj := r.newErrorObject(proto, classError)
if len(args) > 1 && args[1] != nil && args[1] != _undefined {
obj._putProp("message", args[1].toString(), true, false, true)
}
var errors []Value
if len(args) > 0 {
errors = r.iterableToList(args[0], nil)
}
obj._putProp("errors", r.newArrayValues(errors), true, false, true)
return obj.val
}
func writeErrorString(sb *valueStringBuilder, obj *Object) valueString {
var nameStr, msgStr valueString
name := obj.self.getStr("name", nil)
if name == nil || name == _undefined {
nameStr = asciiString("Error")
} else {
nameStr = name.toString()
}
msg := obj.self.getStr("message", nil)
if msg == nil || msg == _undefined {
msgStr = stringEmpty
} else {
msgStr = msg.toString()
}
if nameStr.length() == 0 {
return msgStr
}
if msgStr.length() == 0 {
return nameStr
}
sb.WriteString(nameStr)
sb.WriteString(asciiString(": "))
sb.WriteString(msgStr)
return nil
}
func (r *Runtime) error_toString(call FunctionCall) Value {
var sb valueStringBuilder
val := writeErrorString(&sb, r.toObject(call.This))
if val != nil {
return val
}
return sb.String()
}
func (r *Runtime) createErrorPrototype(name valueString) *Object {
o := r.newBaseObject(r.global.ErrorPrototype, classObject)
o._putProp("message", stringEmpty, true, false, true)
o._putProp("name", name, true, false, true)
return o.val
}
func (r *Runtime) initErrors() {
r.global.ErrorPrototype = r.NewObject()
o := r.global.ErrorPrototype.self
o._putProp("message", stringEmpty, true, false, true)
o._putProp("name", stringError, true, false, true)
o._putProp("toString", r.newNativeFunc(r.error_toString, nil, "toString", nil, 0), true, false, true)
r.global.Error = r.newNativeFuncConstruct(r.builtin_Error, "Error", r.global.ErrorPrototype, 1)
r.addToGlobal("Error", r.global.Error)
r.global.AggregateErrorPrototype = r.createErrorPrototype(stringAggregateError)
r.global.AggregateError = r.newNativeFuncConstructProto(r.builtin_AggregateError, "AggregateError", r.global.AggregateErrorPrototype, r.global.Error, 2)
r.addToGlobal("AggregateError", r.global.AggregateError)
r.global.TypeErrorPrototype = r.createErrorPrototype(stringTypeError)
r.global.TypeError = r.newNativeFuncConstructProto(r.builtin_Error, "TypeError", r.global.TypeErrorPrototype, r.global.Error, 1)
r.addToGlobal("TypeError", r.global.TypeError)
r.global.ReferenceErrorPrototype = r.createErrorPrototype(stringReferenceError)
r.global.ReferenceError = r.newNativeFuncConstructProto(r.builtin_Error, "ReferenceError", r.global.ReferenceErrorPrototype, r.global.Error, 1)
r.addToGlobal("ReferenceError", r.global.ReferenceError)
r.global.SyntaxErrorPrototype = r.createErrorPrototype(stringSyntaxError)
r.global.SyntaxError = r.newNativeFuncConstructProto(r.builtin_Error, "SyntaxError", r.global.SyntaxErrorPrototype, r.global.Error, 1)
r.addToGlobal("SyntaxError", r.global.SyntaxError)
r.global.RangeErrorPrototype = r.createErrorPrototype(stringRangeError)
r.global.RangeError = r.newNativeFuncConstructProto(r.builtin_Error, "RangeError", r.global.RangeErrorPrototype, r.global.Error, 1)
r.addToGlobal("RangeError", r.global.RangeError)
r.global.EvalErrorPrototype = r.createErrorPrototype(stringEvalError)
o = r.global.EvalErrorPrototype.self
o._putProp("name", stringEvalError, true, false, true)
r.global.EvalError = r.newNativeFuncConstructProto(r.builtin_Error, "EvalError", r.global.EvalErrorPrototype, r.global.Error, 1)
r.addToGlobal("EvalError", r.global.EvalError)
r.global.URIErrorPrototype = r.createErrorPrototype(stringURIError)
r.global.URIError = r.newNativeFuncConstructProto(r.builtin_Error, "URIError", r.global.URIErrorPrototype, r.global.Error, 1)
r.addToGlobal("URIError", r.global.URIError)
r.global.GoErrorPrototype = r.createErrorPrototype(stringGoError)
r.global.GoError = r.newNativeFuncConstructProto(r.builtin_Error, "GoError", r.global.GoErrorPrototype, r.global.Error, 1)
r.addToGlobal("GoError", r.global.GoError)
}

View File

@@ -0,0 +1,350 @@
package goja
import (
"math"
)
func (r *Runtime) functionCtor(args []Value, proto *Object, async, generator bool) *Object {
var sb valueStringBuilder
if async {
if generator {
sb.WriteString(asciiString("(async function* anonymous("))
} else {
sb.WriteString(asciiString("(async function anonymous("))
}
} else {
if generator {
sb.WriteString(asciiString("(function* anonymous("))
} else {
sb.WriteString(asciiString("(function anonymous("))
}
}
if len(args) > 1 {
ar := args[:len(args)-1]
for i, arg := range ar {
sb.WriteString(arg.toString())
if i < len(ar)-1 {
sb.WriteRune(',')
}
}
}
sb.WriteString(asciiString("\n) {\n"))
if len(args) > 0 {
sb.WriteString(args[len(args)-1].toString())
}
sb.WriteString(asciiString("\n})"))
ret := r.toObject(r.eval(sb.String(), false, false))
ret.self.setProto(proto, true)
return ret
}
func (r *Runtime) builtin_Function(args []Value, proto *Object) *Object {
return r.functionCtor(args, proto, false, false)
}
func (r *Runtime) builtin_asyncFunction(args []Value, proto *Object) *Object {
return r.functionCtor(args, proto, true, false)
}
func (r *Runtime) builtin_generatorFunction(args []Value, proto *Object) *Object {
return r.functionCtor(args, proto, false, true)
}
func (r *Runtime) functionproto_toString(call FunctionCall) Value {
obj := r.toObject(call.This)
if lazy, ok := obj.self.(*lazyObject); ok {
obj.self = lazy.create(obj)
}
switch f := obj.self.(type) {
case funcObjectImpl:
return f.source()
case *proxyObject:
if lazy, ok := f.target.self.(*lazyObject); ok {
f.target.self = lazy.create(f.target)
}
if _, ok := f.target.self.(funcObjectImpl); ok {
return asciiString("function () { [native code] }")
}
}
panic(r.NewTypeError("Function.prototype.toString requires that 'this' be a Function"))
}
func (r *Runtime) functionproto_hasInstance(call FunctionCall) Value {
if o, ok := call.This.(*Object); ok {
if _, ok = o.self.assertCallable(); ok {
return r.toBoolean(o.self.hasInstance(call.Argument(0)))
}
}
return valueFalse
}
func (r *Runtime) createListFromArrayLike(a Value) []Value {
o := r.toObject(a)
if arr := r.checkStdArrayObj(o); arr != nil {
return arr.values
}
l := toLength(o.self.getStr("length", nil))
res := make([]Value, 0, l)
for k := int64(0); k < l; k++ {
res = append(res, nilSafe(o.self.getIdx(valueInt(k), nil)))
}
return res
}
func (r *Runtime) functionproto_apply(call FunctionCall) Value {
var args []Value
if len(call.Arguments) >= 2 {
args = r.createListFromArrayLike(call.Arguments[1])
}
f := r.toCallable(call.This)
return f(FunctionCall{
This: call.Argument(0),
Arguments: args,
})
}
func (r *Runtime) functionproto_call(call FunctionCall) Value {
var args []Value
if len(call.Arguments) > 0 {
args = call.Arguments[1:]
}
f := r.toCallable(call.This)
return f(FunctionCall{
This: call.Argument(0),
Arguments: args,
})
}
func (r *Runtime) boundCallable(target func(FunctionCall) Value, boundArgs []Value) func(FunctionCall) Value {
var this Value
var args []Value
if len(boundArgs) > 0 {
this = boundArgs[0]
args = make([]Value, len(boundArgs)-1)
copy(args, boundArgs[1:])
} else {
this = _undefined
}
return func(call FunctionCall) Value {
a := append(args, call.Arguments...)
return target(FunctionCall{
This: this,
Arguments: a,
})
}
}
func (r *Runtime) boundConstruct(f *Object, target func([]Value, *Object) *Object, boundArgs []Value) func([]Value, *Object) *Object {
if target == nil {
return nil
}
var args []Value
if len(boundArgs) > 1 {
args = make([]Value, len(boundArgs)-1)
copy(args, boundArgs[1:])
}
return func(fargs []Value, newTarget *Object) *Object {
a := append(args, fargs...)
if newTarget == f {
newTarget = nil
}
return target(a, newTarget)
}
}
func (r *Runtime) functionproto_bind(call FunctionCall) Value {
obj := r.toObject(call.This)
fcall := r.toCallable(call.This)
construct := obj.self.assertConstructor()
var l = _positiveZero
if obj.self.hasOwnPropertyStr("length") {
var li int64
switch lenProp := nilSafe(obj.self.getStr("length", nil)).(type) {
case valueInt:
li = lenProp.ToInteger()
case valueFloat:
switch lenProp {
case _positiveInf:
l = lenProp
goto lenNotInt
case _negativeInf:
goto lenNotInt
case _negativeZero:
// no-op, li == 0
default:
if !math.IsNaN(float64(lenProp)) {
li = int64(math.Abs(float64(lenProp)))
} // else li = 0
}
}
if len(call.Arguments) > 1 {
li -= int64(len(call.Arguments)) - 1
}
if li < 0 {
li = 0
}
l = intToValue(li)
}
lenNotInt:
name := obj.self.getStr("name", nil)
nameStr := stringBound_
if s, ok := name.(valueString); ok {
nameStr = nameStr.concat(s)
}
v := &Object{runtime: r}
ff := r.newNativeFuncAndConstruct(v, r.boundCallable(fcall, call.Arguments), r.boundConstruct(v, construct, call.Arguments), nil, nameStr.string(), l)
bf := &boundFuncObject{
nativeFuncObject: *ff,
wrapped: obj,
}
bf.prototype = obj.self.proto()
v.self = bf
return v
}
func (r *Runtime) initFunction() {
o := r.global.FunctionPrototype.self.(*nativeFuncObject)
o.prototype = r.global.ObjectPrototype
o._putProp("name", stringEmpty, false, false, true)
o._putProp("apply", r.newNativeFunc(r.functionproto_apply, nil, "apply", nil, 2), true, false, true)
o._putProp("bind", r.newNativeFunc(r.functionproto_bind, nil, "bind", nil, 1), true, false, true)
o._putProp("call", r.newNativeFunc(r.functionproto_call, nil, "call", nil, 1), true, false, true)
o._putProp("toString", r.newNativeFunc(r.functionproto_toString, nil, "toString", nil, 0), true, false, true)
o._putSym(SymHasInstance, valueProp(r.newNativeFunc(r.functionproto_hasInstance, nil, "[Symbol.hasInstance]", nil, 1), false, false, false))
r.global.Function = r.newNativeFuncConstruct(r.builtin_Function, "Function", r.global.FunctionPrototype, 1)
r.addToGlobal("Function", r.global.Function)
}
func (r *Runtime) createAsyncFunctionProto(val *Object) objectImpl {
o := &baseObject{
class: classObject,
val: val,
extensible: true,
prototype: r.global.FunctionPrototype,
}
o.init()
o._putProp("constructor", r.getAsyncFunction(), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classAsyncFunction), false, false, true))
return o
}
func (r *Runtime) getAsyncFunctionPrototype() *Object {
var o *Object
if o = r.global.AsyncFunctionPrototype; o == nil {
o = r.newLazyObject(r.createAsyncFunctionProto)
r.global.AsyncFunctionPrototype = o
}
return o
}
func (r *Runtime) createAsyncFunction(val *Object) objectImpl {
o := r.newNativeFuncConstructObj(val, r.builtin_asyncFunction, "AsyncFunction", r.getAsyncFunctionPrototype(), 1)
return o
}
func (r *Runtime) getAsyncFunction() *Object {
var o *Object
if o = r.global.AsyncFunction; o == nil {
o = &Object{runtime: r}
r.global.AsyncFunction = o
o.self = r.createAsyncFunction(o)
}
return o
}
func (r *Runtime) builtin_genproto_next(call FunctionCall) Value {
if o, ok := call.This.(*Object); ok {
if gen, ok := o.self.(*generatorObject); ok {
return gen.next(call.Argument(0))
}
}
panic(r.NewTypeError("Method [Generator].prototype.next called on incompatible receiver"))
}
func (r *Runtime) builtin_genproto_return(call FunctionCall) Value {
if o, ok := call.This.(*Object); ok {
if gen, ok := o.self.(*generatorObject); ok {
return gen._return(call.Argument(0))
}
}
panic(r.NewTypeError("Method [Generator].prototype.return called on incompatible receiver"))
}
func (r *Runtime) builtin_genproto_throw(call FunctionCall) Value {
if o, ok := call.This.(*Object); ok {
if gen, ok := o.self.(*generatorObject); ok {
return gen.throw(call.Argument(0))
}
}
panic(r.NewTypeError("Method [Generator].prototype.throw called on incompatible receiver"))
}
func (r *Runtime) createGeneratorFunctionProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.FunctionPrototype, classObject)
o._putProp("constructor", r.getGeneratorFunction(), false, false, true)
o._putProp("prototype", r.getGeneratorPrototype(), false, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classGeneratorFunction), false, false, true))
return o
}
func (r *Runtime) getGeneratorFunctionPrototype() *Object {
var o *Object
if o = r.global.GeneratorFunctionPrototype; o == nil {
o = r.newLazyObject(r.createGeneratorFunctionProto)
r.global.GeneratorFunctionPrototype = o
}
return o
}
func (r *Runtime) createGeneratorFunction(val *Object) objectImpl {
o := r.newNativeFuncConstructObj(val, r.builtin_generatorFunction, "GeneratorFunction", r.getGeneratorFunctionPrototype(), 1)
return o
}
func (r *Runtime) getGeneratorFunction() *Object {
var o *Object
if o = r.global.GeneratorFunction; o == nil {
o = &Object{runtime: r}
r.global.GeneratorFunction = o
o.self = r.createGeneratorFunction(o)
}
return o
}
func (r *Runtime) createGeneratorProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
o._putProp("constructor", r.getGeneratorFunctionPrototype(), false, false, true)
o._putProp("next", r.newNativeFunc(r.builtin_genproto_next, nil, "next", nil, 1), true, false, true)
o._putProp("return", r.newNativeFunc(r.builtin_genproto_return, nil, "return", nil, 1), true, false, true)
o._putProp("throw", r.newNativeFunc(r.builtin_genproto_throw, nil, "throw", nil, 1), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classGenerator), false, false, true))
return o
}
func (r *Runtime) getGeneratorPrototype() *Object {
var o *Object
if o = r.global.GeneratorPrototype; o == nil {
o = &Object{runtime: r}
r.global.GeneratorPrototype = o
o.self = r.createGeneratorProto(o)
}
return o
}

517
server/vendor/github.com/dop251/goja/builtin_global.go generated vendored Normal file
View File

@@ -0,0 +1,517 @@
package goja
import (
"errors"
"github.com/dop251/goja/unistring"
"io"
"math"
"regexp"
"strconv"
"strings"
"unicode/utf8"
)
const hexUpper = "0123456789ABCDEF"
var (
parseFloatRegexp = regexp.MustCompile(`^([+-]?(?:Infinity|[0-9]*\.?[0-9]*(?:[eE][+-]?[0-9]+)?))`)
)
func (r *Runtime) builtin_isNaN(call FunctionCall) Value {
if math.IsNaN(call.Argument(0).ToFloat()) {
return valueTrue
} else {
return valueFalse
}
}
func (r *Runtime) builtin_parseInt(call FunctionCall) Value {
str := call.Argument(0).toString().toTrimmedUTF8()
radix := int(toInt32(call.Argument(1)))
v, _ := parseInt(str, radix)
return v
}
func (r *Runtime) builtin_parseFloat(call FunctionCall) Value {
m := parseFloatRegexp.FindStringSubmatch(call.Argument(0).toString().toTrimmedUTF8())
if len(m) == 2 {
if s := m[1]; s != "" && s != "+" && s != "-" {
switch s {
case "+", "-":
case "Infinity", "+Infinity":
return _positiveInf
case "-Infinity":
return _negativeInf
default:
f, err := strconv.ParseFloat(s, 64)
if err == nil || isRangeErr(err) {
return floatToValue(f)
}
}
}
}
return _NaN
}
func (r *Runtime) builtin_isFinite(call FunctionCall) Value {
f := call.Argument(0).ToFloat()
if math.IsNaN(f) || math.IsInf(f, 0) {
return valueFalse
}
return valueTrue
}
func (r *Runtime) _encode(uriString valueString, unescaped *[256]bool) valueString {
reader := uriString.reader()
utf8Buf := make([]byte, utf8.UTFMax)
needed := false
l := 0
for {
rn, _, err := reader.ReadRune()
if err != nil {
if err != io.EOF {
panic(r.newError(r.global.URIError, "Malformed URI"))
}
break
}
if rn >= utf8.RuneSelf {
needed = true
l += utf8.EncodeRune(utf8Buf, rn) * 3
} else if !unescaped[rn] {
needed = true
l += 3
} else {
l++
}
}
if !needed {
return uriString
}
buf := make([]byte, l)
i := 0
reader = uriString.reader()
for {
rn, _, err := reader.ReadRune()
if err == io.EOF {
break
}
if rn >= utf8.RuneSelf {
n := utf8.EncodeRune(utf8Buf, rn)
for _, b := range utf8Buf[:n] {
buf[i] = '%'
buf[i+1] = hexUpper[b>>4]
buf[i+2] = hexUpper[b&15]
i += 3
}
} else if !unescaped[rn] {
buf[i] = '%'
buf[i+1] = hexUpper[rn>>4]
buf[i+2] = hexUpper[rn&15]
i += 3
} else {
buf[i] = byte(rn)
i++
}
}
return asciiString(buf)
}
func (r *Runtime) _decode(sv valueString, reservedSet *[256]bool) valueString {
s := sv.String()
hexCount := 0
for i := 0; i < len(s); {
switch s[i] {
case '%':
if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
panic(r.newError(r.global.URIError, "Malformed URI"))
}
c := unhex(s[i+1])<<4 | unhex(s[i+2])
if !reservedSet[c] {
hexCount++
}
i += 3
default:
i++
}
}
if hexCount == 0 {
return sv
}
t := make([]byte, len(s)-hexCount*2)
j := 0
isUnicode := false
for i := 0; i < len(s); {
ch := s[i]
switch ch {
case '%':
c := unhex(s[i+1])<<4 | unhex(s[i+2])
if reservedSet[c] {
t[j] = s[i]
t[j+1] = s[i+1]
t[j+2] = s[i+2]
j += 3
} else {
t[j] = c
if c >= utf8.RuneSelf {
isUnicode = true
}
j++
}
i += 3
default:
if ch >= utf8.RuneSelf {
isUnicode = true
}
t[j] = ch
j++
i++
}
}
if !isUnicode {
return asciiString(t)
}
us := make([]rune, 0, len(s))
for len(t) > 0 {
rn, size := utf8.DecodeRune(t)
if rn == utf8.RuneError {
if size != 3 || t[0] != 0xef || t[1] != 0xbf || t[2] != 0xbd {
panic(r.newError(r.global.URIError, "Malformed URI"))
}
}
us = append(us, rn)
t = t[size:]
}
return unicodeStringFromRunes(us)
}
func ishex(c byte) bool {
switch {
case '0' <= c && c <= '9':
return true
case 'a' <= c && c <= 'f':
return true
case 'A' <= c && c <= 'F':
return true
}
return false
}
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
func (r *Runtime) builtin_decodeURI(call FunctionCall) Value {
uriString := call.Argument(0).toString()
return r._decode(uriString, &uriReservedHash)
}
func (r *Runtime) builtin_decodeURIComponent(call FunctionCall) Value {
uriString := call.Argument(0).toString()
return r._decode(uriString, &emptyEscapeSet)
}
func (r *Runtime) builtin_encodeURI(call FunctionCall) Value {
uriString := call.Argument(0).toString()
return r._encode(uriString, &uriReservedUnescapedHash)
}
func (r *Runtime) builtin_encodeURIComponent(call FunctionCall) Value {
uriString := call.Argument(0).toString()
return r._encode(uriString, &uriUnescaped)
}
func (r *Runtime) builtin_escape(call FunctionCall) Value {
s := call.Argument(0).toString()
var sb strings.Builder
l := s.length()
for i := 0; i < l; i++ {
r := uint16(s.charAt(i))
if r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || r >= '0' && r <= '9' ||
r == '@' || r == '*' || r == '_' || r == '+' || r == '-' || r == '.' || r == '/' {
sb.WriteByte(byte(r))
} else if r <= 0xff {
sb.WriteByte('%')
sb.WriteByte(hexUpper[r>>4])
sb.WriteByte(hexUpper[r&0xf])
} else {
sb.WriteString("%u")
sb.WriteByte(hexUpper[r>>12])
sb.WriteByte(hexUpper[(r>>8)&0xf])
sb.WriteByte(hexUpper[(r>>4)&0xf])
sb.WriteByte(hexUpper[r&0xf])
}
}
return asciiString(sb.String())
}
func (r *Runtime) builtin_unescape(call FunctionCall) Value {
s := call.Argument(0).toString()
l := s.length()
var asciiBuf []byte
var unicodeBuf []uint16
_, u := devirtualizeString(s)
unicode := u != nil
if unicode {
unicodeBuf = make([]uint16, 1, l+1)
unicodeBuf[0] = unistring.BOM
} else {
asciiBuf = make([]byte, 0, l)
}
for i := 0; i < l; {
r := s.charAt(i)
if r == '%' {
if i <= l-6 && s.charAt(i+1) == 'u' {
c0 := s.charAt(i + 2)
c1 := s.charAt(i + 3)
c2 := s.charAt(i + 4)
c3 := s.charAt(i + 5)
if c0 <= 0xff && ishex(byte(c0)) &&
c1 <= 0xff && ishex(byte(c1)) &&
c2 <= 0xff && ishex(byte(c2)) &&
c3 <= 0xff && ishex(byte(c3)) {
r = rune(unhex(byte(c0)))<<12 |
rune(unhex(byte(c1)))<<8 |
rune(unhex(byte(c2)))<<4 |
rune(unhex(byte(c3)))
i += 5
goto out
}
}
if i <= l-3 {
c0 := s.charAt(i + 1)
c1 := s.charAt(i + 2)
if c0 <= 0xff && ishex(byte(c0)) &&
c1 <= 0xff && ishex(byte(c1)) {
r = rune(unhex(byte(c0))<<4 | unhex(byte(c1)))
i += 2
}
}
}
out:
if r >= utf8.RuneSelf && !unicode {
unicodeBuf = make([]uint16, 1, l+1)
unicodeBuf[0] = unistring.BOM
for _, b := range asciiBuf {
unicodeBuf = append(unicodeBuf, uint16(b))
}
asciiBuf = nil
unicode = true
}
if unicode {
unicodeBuf = append(unicodeBuf, uint16(r))
} else {
asciiBuf = append(asciiBuf, byte(r))
}
i++
}
if unicode {
return unicodeString(unicodeBuf)
}
return asciiString(asciiBuf)
}
func (r *Runtime) initGlobalObject() {
o := r.globalObject.self
o._putProp("globalThis", r.globalObject, true, false, true)
o._putProp("NaN", _NaN, false, false, false)
o._putProp("undefined", _undefined, false, false, false)
o._putProp("Infinity", _positiveInf, false, false, false)
o._putProp("isNaN", r.newNativeFunc(r.builtin_isNaN, nil, "isNaN", nil, 1), true, false, true)
o._putProp("parseInt", r.newNativeFunc(r.builtin_parseInt, nil, "parseInt", nil, 2), true, false, true)
o._putProp("parseFloat", r.newNativeFunc(r.builtin_parseFloat, nil, "parseFloat", nil, 1), true, false, true)
o._putProp("isFinite", r.newNativeFunc(r.builtin_isFinite, nil, "isFinite", nil, 1), true, false, true)
o._putProp("decodeURI", r.newNativeFunc(r.builtin_decodeURI, nil, "decodeURI", nil, 1), true, false, true)
o._putProp("decodeURIComponent", r.newNativeFunc(r.builtin_decodeURIComponent, nil, "decodeURIComponent", nil, 1), true, false, true)
o._putProp("encodeURI", r.newNativeFunc(r.builtin_encodeURI, nil, "encodeURI", nil, 1), true, false, true)
o._putProp("encodeURIComponent", r.newNativeFunc(r.builtin_encodeURIComponent, nil, "encodeURIComponent", nil, 1), true, false, true)
o._putProp("escape", r.newNativeFunc(r.builtin_escape, nil, "escape", nil, 1), true, false, true)
o._putProp("unescape", r.newNativeFunc(r.builtin_unescape, nil, "unescape", nil, 1), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classGlobal), false, false, true))
// TODO: Annex B
}
func digitVal(d byte) int {
var v byte
switch {
case '0' <= d && d <= '9':
v = d - '0'
case 'a' <= d && d <= 'z':
v = d - 'a' + 10
case 'A' <= d && d <= 'Z':
v = d - 'A' + 10
default:
return 36
}
return int(v)
}
// ECMAScript compatible version of strconv.ParseInt
func parseInt(s string, base int) (Value, error) {
var n int64
var err error
var cutoff, maxVal int64
var sign bool
i := 0
if len(s) < 1 {
err = strconv.ErrSyntax
goto Error
}
switch s[0] {
case '-':
sign = true
s = s[1:]
case '+':
s = s[1:]
}
if len(s) < 1 {
err = strconv.ErrSyntax
goto Error
}
// Look for hex prefix.
if s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X') {
if base == 0 || base == 16 {
base = 16
s = s[2:]
}
}
switch {
case len(s) < 1:
err = strconv.ErrSyntax
goto Error
case 2 <= base && base <= 36:
// valid base; nothing to do
case base == 0:
// Look for hex prefix.
switch {
case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
if len(s) < 3 {
err = strconv.ErrSyntax
goto Error
}
base = 16
s = s[2:]
default:
base = 10
}
default:
err = errors.New("invalid base " + strconv.Itoa(base))
goto Error
}
// Cutoff is the smallest number such that cutoff*base > maxInt64.
// Use compile-time constants for common cases.
switch base {
case 10:
cutoff = math.MaxInt64/10 + 1
case 16:
cutoff = math.MaxInt64/16 + 1
default:
cutoff = math.MaxInt64/int64(base) + 1
}
maxVal = math.MaxInt64
for ; i < len(s); i++ {
if n >= cutoff {
// n*base overflows
return parseLargeInt(float64(n), s[i:], base, sign)
}
v := digitVal(s[i])
if v >= base {
break
}
n *= int64(base)
n1 := n + int64(v)
if n1 < n || n1 > maxVal {
// n+v overflows
return parseLargeInt(float64(n)+float64(v), s[i+1:], base, sign)
}
n = n1
}
if i == 0 {
err = strconv.ErrSyntax
goto Error
}
if sign {
n = -n
}
return intToValue(n), nil
Error:
return _NaN, err
}
func parseLargeInt(n float64, s string, base int, sign bool) (Value, error) {
i := 0
b := float64(base)
for ; i < len(s); i++ {
v := digitVal(s[i])
if v >= base {
break
}
n = n*b + float64(v)
}
if sign {
n = -n
}
// We know it can't be represented as int, so use valueFloat instead of floatToValue
return valueFloat(n), nil
}
var (
uriUnescaped [256]bool
uriReserved [256]bool
uriReservedHash [256]bool
uriReservedUnescapedHash [256]bool
emptyEscapeSet [256]bool
)
func init() {
for _, c := range "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()" {
uriUnescaped[c] = true
}
for _, c := range ";/?:@&=+$," {
uriReserved[c] = true
}
for i := 0; i < 256; i++ {
if uriUnescaped[i] || uriReserved[i] {
uriReservedUnescapedHash[i] = true
}
uriReservedHash[i] = uriReserved[i]
}
uriReservedUnescapedHash['#'] = true
uriReservedHash['#'] = true
}

528
server/vendor/github.com/dop251/goja/builtin_json.go generated vendored Normal file
View File

@@ -0,0 +1,528 @@
package goja
import (
"bytes"
"encoding/json"
"fmt"
"io"
"math"
"strconv"
"strings"
"unicode/utf16"
"unicode/utf8"
"github.com/dop251/goja/unistring"
)
const hex = "0123456789abcdef"
func (r *Runtime) builtinJSON_parse(call FunctionCall) Value {
d := json.NewDecoder(strings.NewReader(call.Argument(0).toString().String()))
value, err := r.builtinJSON_decodeValue(d)
if err != nil {
panic(r.newError(r.global.SyntaxError, err.Error()))
}
if tok, err := d.Token(); err != io.EOF {
panic(r.newError(r.global.SyntaxError, "Unexpected token at the end: %v", tok))
}
var reviver func(FunctionCall) Value
if arg1 := call.Argument(1); arg1 != _undefined {
reviver, _ = arg1.ToObject(r).self.assertCallable()
}
if reviver != nil {
root := r.NewObject()
createDataPropertyOrThrow(root, stringEmpty, value)
return r.builtinJSON_reviveWalk(reviver, root, stringEmpty)
}
return value
}
func (r *Runtime) builtinJSON_decodeToken(d *json.Decoder, tok json.Token) (Value, error) {
switch tok := tok.(type) {
case json.Delim:
switch tok {
case '{':
return r.builtinJSON_decodeObject(d)
case '[':
return r.builtinJSON_decodeArray(d)
}
case nil:
return _null, nil
case string:
return newStringValue(tok), nil
case float64:
return floatToValue(tok), nil
case bool:
if tok {
return valueTrue, nil
}
return valueFalse, nil
}
return nil, fmt.Errorf("Unexpected token (%T): %v", tok, tok)
}
func (r *Runtime) builtinJSON_decodeValue(d *json.Decoder) (Value, error) {
tok, err := d.Token()
if err != nil {
return nil, err
}
return r.builtinJSON_decodeToken(d, tok)
}
func (r *Runtime) builtinJSON_decodeObject(d *json.Decoder) (*Object, error) {
object := r.NewObject()
for {
key, end, err := r.builtinJSON_decodeObjectKey(d)
if err != nil {
return nil, err
}
if end {
break
}
value, err := r.builtinJSON_decodeValue(d)
if err != nil {
return nil, err
}
object.self._putProp(unistring.NewFromString(key), value, true, true, true)
}
return object, nil
}
func (r *Runtime) builtinJSON_decodeObjectKey(d *json.Decoder) (string, bool, error) {
tok, err := d.Token()
if err != nil {
return "", false, err
}
switch tok := tok.(type) {
case json.Delim:
if tok == '}' {
return "", true, nil
}
case string:
return tok, false, nil
}
return "", false, fmt.Errorf("Unexpected token (%T): %v", tok, tok)
}
func (r *Runtime) builtinJSON_decodeArray(d *json.Decoder) (*Object, error) {
var arrayValue []Value
for {
tok, err := d.Token()
if err != nil {
return nil, err
}
if delim, ok := tok.(json.Delim); ok {
if delim == ']' {
break
}
}
value, err := r.builtinJSON_decodeToken(d, tok)
if err != nil {
return nil, err
}
arrayValue = append(arrayValue, value)
}
return r.newArrayValues(arrayValue), nil
}
func (r *Runtime) builtinJSON_reviveWalk(reviver func(FunctionCall) Value, holder *Object, name Value) Value {
value := nilSafe(holder.get(name, nil))
if object, ok := value.(*Object); ok {
if isArray(object) {
length := toLength(object.self.getStr("length", nil))
for index := int64(0); index < length; index++ {
name := asciiString(strconv.FormatInt(index, 10))
value := r.builtinJSON_reviveWalk(reviver, object, name)
if value == _undefined {
object.delete(name, false)
} else {
createDataProperty(object, name, value)
}
}
} else {
for _, name := range object.self.stringKeys(false, nil) {
value := r.builtinJSON_reviveWalk(reviver, object, name)
if value == _undefined {
object.self.deleteStr(name.string(), false)
} else {
createDataProperty(object, name, value)
}
}
}
}
return reviver(FunctionCall{
This: holder,
Arguments: []Value{name, value},
})
}
type _builtinJSON_stringifyContext struct {
r *Runtime
stack []*Object
propertyList []Value
replacerFunction func(FunctionCall) Value
gap, indent string
buf bytes.Buffer
allAscii bool
}
func (r *Runtime) builtinJSON_stringify(call FunctionCall) Value {
ctx := _builtinJSON_stringifyContext{
r: r,
allAscii: true,
}
replacer, _ := call.Argument(1).(*Object)
if replacer != nil {
if isArray(replacer) {
length := toLength(replacer.self.getStr("length", nil))
seen := map[string]bool{}
propertyList := make([]Value, length)
length = 0
for index := range propertyList {
var name string
value := replacer.self.getIdx(valueInt(int64(index)), nil)
switch v := value.(type) {
case valueFloat, valueInt, valueString:
name = value.String()
case *Object:
switch v.self.className() {
case classNumber, classString:
name = value.String()
default:
continue
}
default:
continue
}
if seen[name] {
continue
}
seen[name] = true
propertyList[length] = newStringValue(name)
length += 1
}
ctx.propertyList = propertyList[0:length]
} else if c, ok := replacer.self.assertCallable(); ok {
ctx.replacerFunction = c
}
}
if spaceValue := call.Argument(2); spaceValue != _undefined {
if o, ok := spaceValue.(*Object); ok {
switch oImpl := o.self.(type) {
case *primitiveValueObject:
switch oImpl.pValue.(type) {
case valueInt, valueFloat:
spaceValue = o.ToNumber()
}
case *stringObject:
spaceValue = o.ToString()
}
}
isNum := false
var num int64
if i, ok := spaceValue.(valueInt); ok {
num = int64(i)
isNum = true
} else if f, ok := spaceValue.(valueFloat); ok {
num = int64(f)
isNum = true
}
if isNum {
if num > 0 {
if num > 10 {
num = 10
}
ctx.gap = strings.Repeat(" ", int(num))
}
} else {
if s, ok := spaceValue.(valueString); ok {
str := s.String()
if len(str) > 10 {
ctx.gap = str[:10]
} else {
ctx.gap = str
}
}
}
}
if ctx.do(call.Argument(0)) {
if ctx.allAscii {
return asciiString(ctx.buf.String())
} else {
return &importedString{
s: ctx.buf.String(),
}
}
}
return _undefined
}
func (ctx *_builtinJSON_stringifyContext) do(v Value) bool {
holder := ctx.r.NewObject()
createDataPropertyOrThrow(holder, stringEmpty, v)
return ctx.str(stringEmpty, holder)
}
func (ctx *_builtinJSON_stringifyContext) str(key Value, holder *Object) bool {
value := nilSafe(holder.get(key, nil))
if object, ok := value.(*Object); ok {
if toJSON, ok := object.self.getStr("toJSON", nil).(*Object); ok {
if c, ok := toJSON.self.assertCallable(); ok {
value = c(FunctionCall{
This: value,
Arguments: []Value{key},
})
}
}
}
if ctx.replacerFunction != nil {
value = ctx.replacerFunction(FunctionCall{
This: holder,
Arguments: []Value{key, value},
})
}
if o, ok := value.(*Object); ok {
switch o1 := o.self.(type) {
case *primitiveValueObject:
switch pValue := o1.pValue.(type) {
case valueInt, valueFloat:
value = o.ToNumber()
default:
value = pValue
}
case *stringObject:
value = o.toString()
case *objectGoReflect:
if o1.toJson != nil {
value = ctx.r.ToValue(o1.toJson())
} else if v, ok := o1.origValue.Interface().(json.Marshaler); ok {
b, err := v.MarshalJSON()
if err != nil {
panic(err)
}
ctx.buf.Write(b)
ctx.allAscii = false
return true
} else {
switch o1.className() {
case classNumber:
value = o1.toPrimitiveNumber()
case classString:
value = o1.toPrimitiveString()
case classBoolean:
if o.ToInteger() != 0 {
value = valueTrue
} else {
value = valueFalse
}
}
}
}
}
switch value1 := value.(type) {
case valueBool:
if value1 {
ctx.buf.WriteString("true")
} else {
ctx.buf.WriteString("false")
}
case valueString:
ctx.quote(value1)
case valueInt:
ctx.buf.WriteString(value.String())
case valueFloat:
if !math.IsNaN(float64(value1)) && !math.IsInf(float64(value1), 0) {
ctx.buf.WriteString(value.String())
} else {
ctx.buf.WriteString("null")
}
case valueNull:
ctx.buf.WriteString("null")
case *Object:
for _, object := range ctx.stack {
if value1 == object {
ctx.r.typeErrorResult(true, "Converting circular structure to JSON")
}
}
ctx.stack = append(ctx.stack, value1)
defer func() { ctx.stack = ctx.stack[:len(ctx.stack)-1] }()
if _, ok := value1.self.assertCallable(); !ok {
if isArray(value1) {
ctx.ja(value1)
} else {
ctx.jo(value1)
}
} else {
return false
}
default:
return false
}
return true
}
func (ctx *_builtinJSON_stringifyContext) ja(array *Object) {
var stepback string
if ctx.gap != "" {
stepback = ctx.indent
ctx.indent += ctx.gap
}
length := toLength(array.self.getStr("length", nil))
if length == 0 {
ctx.buf.WriteString("[]")
return
}
ctx.buf.WriteByte('[')
var separator string
if ctx.gap != "" {
ctx.buf.WriteByte('\n')
ctx.buf.WriteString(ctx.indent)
separator = ",\n" + ctx.indent
} else {
separator = ","
}
for i := int64(0); i < length; i++ {
if !ctx.str(asciiString(strconv.FormatInt(i, 10)), array) {
ctx.buf.WriteString("null")
}
if i < length-1 {
ctx.buf.WriteString(separator)
}
}
if ctx.gap != "" {
ctx.buf.WriteByte('\n')
ctx.buf.WriteString(stepback)
ctx.indent = stepback
}
ctx.buf.WriteByte(']')
}
func (ctx *_builtinJSON_stringifyContext) jo(object *Object) {
var stepback string
if ctx.gap != "" {
stepback = ctx.indent
ctx.indent += ctx.gap
}
ctx.buf.WriteByte('{')
mark := ctx.buf.Len()
var separator string
if ctx.gap != "" {
ctx.buf.WriteByte('\n')
ctx.buf.WriteString(ctx.indent)
separator = ",\n" + ctx.indent
} else {
separator = ","
}
var props []Value
if ctx.propertyList == nil {
props = object.self.stringKeys(false, nil)
} else {
props = ctx.propertyList
}
empty := true
for _, name := range props {
off := ctx.buf.Len()
if !empty {
ctx.buf.WriteString(separator)
}
ctx.quote(name.toString())
if ctx.gap != "" {
ctx.buf.WriteString(": ")
} else {
ctx.buf.WriteByte(':')
}
if ctx.str(name, object) {
if empty {
empty = false
}
} else {
ctx.buf.Truncate(off)
}
}
if empty {
ctx.buf.Truncate(mark)
} else {
if ctx.gap != "" {
ctx.buf.WriteByte('\n')
ctx.buf.WriteString(stepback)
ctx.indent = stepback
}
}
ctx.buf.WriteByte('}')
}
func (ctx *_builtinJSON_stringifyContext) quote(str valueString) {
ctx.buf.WriteByte('"')
reader := &lenientUtf16Decoder{utf16Reader: str.utf16Reader()}
for {
r, _, err := reader.ReadRune()
if err != nil {
break
}
switch r {
case '"', '\\':
ctx.buf.WriteByte('\\')
ctx.buf.WriteByte(byte(r))
case 0x08:
ctx.buf.WriteString(`\b`)
case 0x09:
ctx.buf.WriteString(`\t`)
case 0x0A:
ctx.buf.WriteString(`\n`)
case 0x0C:
ctx.buf.WriteString(`\f`)
case 0x0D:
ctx.buf.WriteString(`\r`)
default:
if r < 0x20 {
ctx.buf.WriteString(`\u00`)
ctx.buf.WriteByte(hex[r>>4])
ctx.buf.WriteByte(hex[r&0xF])
} else {
if utf16.IsSurrogate(r) {
ctx.buf.WriteString(`\u`)
ctx.buf.WriteByte(hex[r>>12])
ctx.buf.WriteByte(hex[(r>>8)&0xF])
ctx.buf.WriteByte(hex[(r>>4)&0xF])
ctx.buf.WriteByte(hex[r&0xF])
} else {
ctx.buf.WriteRune(r)
if ctx.allAscii && r >= utf8.RuneSelf {
ctx.allAscii = false
}
}
}
}
}
ctx.buf.WriteByte('"')
}
func (r *Runtime) initJSON() {
JSON := r.newBaseObject(r.global.ObjectPrototype, classObject)
JSON._putProp("parse", r.newNativeFunc(r.builtinJSON_parse, nil, "parse", nil, 2), true, false, true)
JSON._putProp("stringify", r.newNativeFunc(r.builtinJSON_stringify, nil, "stringify", nil, 3), true, false, true)
JSON._putSym(SymToStringTag, valueProp(asciiString(classJSON), false, false, true))
r.addToGlobal("JSON", JSON.val)
}

331
server/vendor/github.com/dop251/goja/builtin_map.go generated vendored Normal file
View File

@@ -0,0 +1,331 @@
package goja
import (
"reflect"
)
var mapExportType = reflect.TypeOf([][2]interface{}{})
type mapObject struct {
baseObject
m *orderedMap
}
type mapIterObject struct {
baseObject
iter *orderedMapIter
kind iterationKind
}
func (o *mapIterObject) next() Value {
if o.iter == nil {
return o.val.runtime.createIterResultObject(_undefined, true)
}
entry := o.iter.next()
if entry == nil {
o.iter = nil
return o.val.runtime.createIterResultObject(_undefined, true)
}
var result Value
switch o.kind {
case iterationKindKey:
result = entry.key
case iterationKindValue:
result = entry.value
default:
result = o.val.runtime.newArrayValues([]Value{entry.key, entry.value})
}
return o.val.runtime.createIterResultObject(result, false)
}
func (mo *mapObject) init() {
mo.baseObject.init()
mo.m = newOrderedMap(mo.val.runtime.getHash())
}
func (mo *mapObject) exportType() reflect.Type {
return mapExportType
}
func (mo *mapObject) export(ctx *objectExportCtx) interface{} {
m := make([][2]interface{}, mo.m.size)
ctx.put(mo.val, m)
iter := mo.m.newIter()
for i := 0; i < len(m); i++ {
entry := iter.next()
if entry == nil {
break
}
m[i][0] = exportValue(entry.key, ctx)
m[i][1] = exportValue(entry.value, ctx)
}
return m
}
func (mo *mapObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
dst.Set(reflect.MakeMap(typ))
ctx.putTyped(mo.val, typ, dst.Interface())
keyTyp := typ.Key()
elemTyp := typ.Elem()
iter := mo.m.newIter()
r := mo.val.runtime
for {
entry := iter.next()
if entry == nil {
break
}
keyVal := reflect.New(keyTyp).Elem()
err := r.toReflectValue(entry.key, keyVal, ctx)
if err != nil {
return err
}
elemVal := reflect.New(elemTyp).Elem()
err = r.toReflectValue(entry.value, elemVal, ctx)
if err != nil {
return err
}
dst.SetMapIndex(keyVal, elemVal)
}
return nil
}
func (r *Runtime) mapProto_clear(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method Map.prototype.clear called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
mo.m.clear()
return _undefined
}
func (r *Runtime) mapProto_delete(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method Map.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return r.toBoolean(mo.m.remove(call.Argument(0)))
}
func (r *Runtime) mapProto_get(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method Map.prototype.get called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return nilSafe(mo.m.get(call.Argument(0)))
}
func (r *Runtime) mapProto_has(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method Map.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
if mo.m.has(call.Argument(0)) {
return valueTrue
}
return valueFalse
}
func (r *Runtime) mapProto_set(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method Map.prototype.set called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
mo.m.set(call.Argument(0), call.Argument(1))
return call.This
}
func (r *Runtime) mapProto_entries(call FunctionCall) Value {
return r.createMapIterator(call.This, iterationKindKeyValue)
}
func (r *Runtime) mapProto_forEach(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method Map.prototype.forEach called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
callbackFn, ok := r.toObject(call.Argument(0)).self.assertCallable()
if !ok {
panic(r.NewTypeError("object is not a function %s"))
}
t := call.Argument(1)
iter := mo.m.newIter()
for {
entry := iter.next()
if entry == nil {
break
}
callbackFn(FunctionCall{This: t, Arguments: []Value{entry.value, entry.key, thisObj}})
}
return _undefined
}
func (r *Runtime) mapProto_keys(call FunctionCall) Value {
return r.createMapIterator(call.This, iterationKindKey)
}
func (r *Runtime) mapProto_values(call FunctionCall) Value {
return r.createMapIterator(call.This, iterationKindValue)
}
func (r *Runtime) mapProto_getSize(call FunctionCall) Value {
thisObj := r.toObject(call.This)
mo, ok := thisObj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Method get Map.prototype.size called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return intToValue(int64(mo.m.size))
}
func (r *Runtime) builtin_newMap(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("Map"))
}
proto := r.getPrototypeFromCtor(newTarget, r.global.Map, r.global.MapPrototype)
o := &Object{runtime: r}
mo := &mapObject{}
mo.class = classObject
mo.val = o
mo.extensible = true
o.self = mo
mo.prototype = proto
mo.init()
if len(args) > 0 {
if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
adder := mo.getStr("set", nil)
adderFn := toMethod(adder)
if adderFn == nil {
panic(r.NewTypeError("Map.set in missing"))
}
iter := r.getIterator(arg, nil)
i0 := valueInt(0)
i1 := valueInt(1)
if adder == r.global.mapAdder {
iter.iterate(func(item Value) {
itemObj := r.toObject(item)
k := nilSafe(itemObj.self.getIdx(i0, nil))
v := nilSafe(itemObj.self.getIdx(i1, nil))
mo.m.set(k, v)
})
} else {
iter.iterate(func(item Value) {
itemObj := r.toObject(item)
k := itemObj.self.getIdx(i0, nil)
v := itemObj.self.getIdx(i1, nil)
adderFn(FunctionCall{This: o, Arguments: []Value{k, v}})
})
}
}
}
return o
}
func (r *Runtime) createMapIterator(mapValue Value, kind iterationKind) Value {
obj := r.toObject(mapValue)
mapObj, ok := obj.self.(*mapObject)
if !ok {
panic(r.NewTypeError("Object is not a Map"))
}
o := &Object{runtime: r}
mi := &mapIterObject{
iter: mapObj.m.newIter(),
kind: kind,
}
mi.class = classObject
mi.val = o
mi.extensible = true
o.self = mi
mi.prototype = r.getMapIteratorPrototype()
mi.init()
return o
}
func (r *Runtime) mapIterProto_next(call FunctionCall) Value {
thisObj := r.toObject(call.This)
if iter, ok := thisObj.self.(*mapIterObject); ok {
return iter.next()
}
panic(r.NewTypeError("Method Map Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
func (r *Runtime) createMapProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("constructor", r.global.Map, true, false, true)
o._putProp("clear", r.newNativeFunc(r.mapProto_clear, nil, "clear", nil, 0), true, false, true)
r.global.mapAdder = r.newNativeFunc(r.mapProto_set, nil, "set", nil, 2)
o._putProp("set", r.global.mapAdder, true, false, true)
o._putProp("delete", r.newNativeFunc(r.mapProto_delete, nil, "delete", nil, 1), true, false, true)
o._putProp("forEach", r.newNativeFunc(r.mapProto_forEach, nil, "forEach", nil, 1), true, false, true)
o._putProp("has", r.newNativeFunc(r.mapProto_has, nil, "has", nil, 1), true, false, true)
o._putProp("get", r.newNativeFunc(r.mapProto_get, nil, "get", nil, 1), true, false, true)
o.setOwnStr("size", &valueProperty{
getterFunc: r.newNativeFunc(r.mapProto_getSize, nil, "get size", nil, 0),
accessor: true,
writable: true,
configurable: true,
}, true)
o._putProp("keys", r.newNativeFunc(r.mapProto_keys, nil, "keys", nil, 0), true, false, true)
o._putProp("values", r.newNativeFunc(r.mapProto_values, nil, "values", nil, 0), true, false, true)
entriesFunc := r.newNativeFunc(r.mapProto_entries, nil, "entries", nil, 0)
o._putProp("entries", entriesFunc, true, false, true)
o._putSym(SymIterator, valueProp(entriesFunc, true, false, true))
o._putSym(SymToStringTag, valueProp(asciiString(classMap), false, false, true))
return o
}
func (r *Runtime) createMap(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newMap, r.global.MapPrototype, "Map", 0)
r.putSpeciesReturnThis(o)
return o
}
func (r *Runtime) createMapIterProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
o._putProp("next", r.newNativeFunc(r.mapIterProto_next, nil, "next", nil, 0), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classMapIterator), false, false, true))
return o
}
func (r *Runtime) getMapIteratorPrototype() *Object {
var o *Object
if o = r.global.MapIteratorPrototype; o == nil {
o = &Object{runtime: r}
r.global.MapIteratorPrototype = o
o.self = r.createMapIterProto(o)
}
return o
}
func (r *Runtime) initMap() {
r.global.MapIteratorPrototype = r.newLazyObject(r.createMapIterProto)
r.global.MapPrototype = r.newLazyObject(r.createMapProto)
r.global.Map = r.newLazyObject(r.createMap)
r.addToGlobal("Map", r.global.Map)
}

343
server/vendor/github.com/dop251/goja/builtin_math.go generated vendored Normal file
View File

@@ -0,0 +1,343 @@
package goja
import (
"math"
"math/bits"
)
func (r *Runtime) math_abs(call FunctionCall) Value {
return floatToValue(math.Abs(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_acos(call FunctionCall) Value {
return floatToValue(math.Acos(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_acosh(call FunctionCall) Value {
return floatToValue(math.Acosh(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_asin(call FunctionCall) Value {
return floatToValue(math.Asin(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_asinh(call FunctionCall) Value {
return floatToValue(math.Asinh(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_atan(call FunctionCall) Value {
return floatToValue(math.Atan(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_atanh(call FunctionCall) Value {
return floatToValue(math.Atanh(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_atan2(call FunctionCall) Value {
y := call.Argument(0).ToFloat()
x := call.Argument(1).ToFloat()
return floatToValue(math.Atan2(y, x))
}
func (r *Runtime) math_cbrt(call FunctionCall) Value {
return floatToValue(math.Cbrt(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_ceil(call FunctionCall) Value {
return floatToValue(math.Ceil(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_clz32(call FunctionCall) Value {
return intToValue(int64(bits.LeadingZeros32(toUint32(call.Argument(0)))))
}
func (r *Runtime) math_cos(call FunctionCall) Value {
return floatToValue(math.Cos(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_cosh(call FunctionCall) Value {
return floatToValue(math.Cosh(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_exp(call FunctionCall) Value {
return floatToValue(math.Exp(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_expm1(call FunctionCall) Value {
return floatToValue(math.Expm1(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_floor(call FunctionCall) Value {
return floatToValue(math.Floor(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_fround(call FunctionCall) Value {
return floatToValue(float64(float32(call.Argument(0).ToFloat())))
}
func (r *Runtime) math_hypot(call FunctionCall) Value {
var max float64
var hasNaN bool
absValues := make([]float64, 0, len(call.Arguments))
for _, v := range call.Arguments {
arg := nilSafe(v).ToFloat()
if math.IsNaN(arg) {
hasNaN = true
} else {
abs := math.Abs(arg)
if abs > max {
max = abs
}
absValues = append(absValues, abs)
}
}
if math.IsInf(max, 1) {
return _positiveInf
}
if hasNaN {
return _NaN
}
if max == 0 {
return _positiveZero
}
// Kahan summation to avoid rounding errors.
// Normalize the numbers to the largest one to avoid overflow.
var sum, compensation float64
for _, n := range absValues {
n /= max
summand := n*n - compensation
preliminary := sum + summand
compensation = (preliminary - sum) - summand
sum = preliminary
}
return floatToValue(math.Sqrt(sum) * max)
}
func (r *Runtime) math_imul(call FunctionCall) Value {
x := toUint32(call.Argument(0))
y := toUint32(call.Argument(1))
return intToValue(int64(int32(x * y)))
}
func (r *Runtime) math_log(call FunctionCall) Value {
return floatToValue(math.Log(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_log1p(call FunctionCall) Value {
return floatToValue(math.Log1p(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_log10(call FunctionCall) Value {
return floatToValue(math.Log10(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_log2(call FunctionCall) Value {
return floatToValue(math.Log2(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_max(call FunctionCall) Value {
result := math.Inf(-1)
args := call.Arguments
for i, arg := range args {
n := nilSafe(arg).ToFloat()
if math.IsNaN(n) {
args = args[i+1:]
goto NaNLoop
}
result = math.Max(result, n)
}
return floatToValue(result)
NaNLoop:
// All arguments still need to be coerced to number according to the specs.
for _, arg := range args {
nilSafe(arg).ToFloat()
}
return _NaN
}
func (r *Runtime) math_min(call FunctionCall) Value {
result := math.Inf(1)
args := call.Arguments
for i, arg := range args {
n := nilSafe(arg).ToFloat()
if math.IsNaN(n) {
args = args[i+1:]
goto NaNLoop
}
result = math.Min(result, n)
}
return floatToValue(result)
NaNLoop:
// All arguments still need to be coerced to number according to the specs.
for _, arg := range args {
nilSafe(arg).ToFloat()
}
return _NaN
}
func pow(x, y Value) Value {
if x, ok := x.(valueInt); ok {
if y, ok := y.(valueInt); ok && y >= 0 && y < 64 {
if y == 0 {
return intToValue(1)
}
if x == 0 {
return intToValue(0)
}
ip := ipow(int64(x), int64(y))
if ip != 0 {
return intToValue(ip)
}
}
}
xf := x.ToFloat()
yf := y.ToFloat()
if math.Abs(xf) == 1 && math.IsInf(yf, 0) {
return _NaN
}
if xf == 1 && math.IsNaN(yf) {
return _NaN
}
return floatToValue(math.Pow(xf, yf))
}
func (r *Runtime) math_pow(call FunctionCall) Value {
return pow(call.Argument(0), call.Argument(1))
}
func (r *Runtime) math_random(call FunctionCall) Value {
return floatToValue(r.rand())
}
func (r *Runtime) math_round(call FunctionCall) Value {
f := call.Argument(0).ToFloat()
if math.IsNaN(f) {
return _NaN
}
if f == 0 && math.Signbit(f) {
return _negativeZero
}
t := math.Trunc(f)
if f >= 0 {
if f-t >= 0.5 {
return floatToValue(t + 1)
}
} else {
if t-f > 0.5 {
return floatToValue(t - 1)
}
}
return floatToValue(t)
}
func (r *Runtime) math_sign(call FunctionCall) Value {
arg := call.Argument(0)
num := arg.ToFloat()
if math.IsNaN(num) || num == 0 { // this will match -0 too
return arg
}
if num > 0 {
return intToValue(1)
}
return intToValue(-1)
}
func (r *Runtime) math_sin(call FunctionCall) Value {
return floatToValue(math.Sin(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_sinh(call FunctionCall) Value {
return floatToValue(math.Sinh(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_sqrt(call FunctionCall) Value {
return floatToValue(math.Sqrt(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_tan(call FunctionCall) Value {
return floatToValue(math.Tan(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_tanh(call FunctionCall) Value {
return floatToValue(math.Tanh(call.Argument(0).ToFloat()))
}
func (r *Runtime) math_trunc(call FunctionCall) Value {
arg := call.Argument(0)
if i, ok := arg.(valueInt); ok {
return i
}
return floatToValue(math.Trunc(arg.ToFloat()))
}
func (r *Runtime) createMath(val *Object) objectImpl {
m := &baseObject{
class: classObject,
val: val,
extensible: true,
prototype: r.global.ObjectPrototype,
}
m.init()
m._putProp("E", valueFloat(math.E), false, false, false)
m._putProp("LN10", valueFloat(math.Ln10), false, false, false)
m._putProp("LN2", valueFloat(math.Ln2), false, false, false)
m._putProp("LOG10E", valueFloat(math.Log10E), false, false, false)
m._putProp("LOG2E", valueFloat(math.Log2E), false, false, false)
m._putProp("PI", valueFloat(math.Pi), false, false, false)
m._putProp("SQRT1_2", valueFloat(sqrt1_2), false, false, false)
m._putProp("SQRT2", valueFloat(math.Sqrt2), false, false, false)
m._putSym(SymToStringTag, valueProp(asciiString(classMath), false, false, true))
m._putProp("abs", r.newNativeFunc(r.math_abs, nil, "abs", nil, 1), true, false, true)
m._putProp("acos", r.newNativeFunc(r.math_acos, nil, "acos", nil, 1), true, false, true)
m._putProp("acosh", r.newNativeFunc(r.math_acosh, nil, "acosh", nil, 1), true, false, true)
m._putProp("asin", r.newNativeFunc(r.math_asin, nil, "asin", nil, 1), true, false, true)
m._putProp("asinh", r.newNativeFunc(r.math_asinh, nil, "asinh", nil, 1), true, false, true)
m._putProp("atan", r.newNativeFunc(r.math_atan, nil, "atan", nil, 1), true, false, true)
m._putProp("atanh", r.newNativeFunc(r.math_atanh, nil, "atanh", nil, 1), true, false, true)
m._putProp("atan2", r.newNativeFunc(r.math_atan2, nil, "atan2", nil, 2), true, false, true)
m._putProp("cbrt", r.newNativeFunc(r.math_cbrt, nil, "cbrt", nil, 1), true, false, true)
m._putProp("ceil", r.newNativeFunc(r.math_ceil, nil, "ceil", nil, 1), true, false, true)
m._putProp("clz32", r.newNativeFunc(r.math_clz32, nil, "clz32", nil, 1), true, false, true)
m._putProp("cos", r.newNativeFunc(r.math_cos, nil, "cos", nil, 1), true, false, true)
m._putProp("cosh", r.newNativeFunc(r.math_cosh, nil, "cosh", nil, 1), true, false, true)
m._putProp("exp", r.newNativeFunc(r.math_exp, nil, "exp", nil, 1), true, false, true)
m._putProp("expm1", r.newNativeFunc(r.math_expm1, nil, "expm1", nil, 1), true, false, true)
m._putProp("floor", r.newNativeFunc(r.math_floor, nil, "floor", nil, 1), true, false, true)
m._putProp("fround", r.newNativeFunc(r.math_fround, nil, "fround", nil, 1), true, false, true)
m._putProp("hypot", r.newNativeFunc(r.math_hypot, nil, "hypot", nil, 2), true, false, true)
m._putProp("imul", r.newNativeFunc(r.math_imul, nil, "imul", nil, 2), true, false, true)
m._putProp("log", r.newNativeFunc(r.math_log, nil, "log", nil, 1), true, false, true)
m._putProp("log1p", r.newNativeFunc(r.math_log1p, nil, "log1p", nil, 1), true, false, true)
m._putProp("log10", r.newNativeFunc(r.math_log10, nil, "log10", nil, 1), true, false, true)
m._putProp("log2", r.newNativeFunc(r.math_log2, nil, "log2", nil, 1), true, false, true)
m._putProp("max", r.newNativeFunc(r.math_max, nil, "max", nil, 2), true, false, true)
m._putProp("min", r.newNativeFunc(r.math_min, nil, "min", nil, 2), true, false, true)
m._putProp("pow", r.newNativeFunc(r.math_pow, nil, "pow", nil, 2), true, false, true)
m._putProp("random", r.newNativeFunc(r.math_random, nil, "random", nil, 0), true, false, true)
m._putProp("round", r.newNativeFunc(r.math_round, nil, "round", nil, 1), true, false, true)
m._putProp("sign", r.newNativeFunc(r.math_sign, nil, "sign", nil, 1), true, false, true)
m._putProp("sin", r.newNativeFunc(r.math_sin, nil, "sin", nil, 1), true, false, true)
m._putProp("sinh", r.newNativeFunc(r.math_sinh, nil, "sinh", nil, 1), true, false, true)
m._putProp("sqrt", r.newNativeFunc(r.math_sqrt, nil, "sqrt", nil, 1), true, false, true)
m._putProp("tan", r.newNativeFunc(r.math_tan, nil, "tan", nil, 1), true, false, true)
m._putProp("tanh", r.newNativeFunc(r.math_tanh, nil, "tanh", nil, 1), true, false, true)
m._putProp("trunc", r.newNativeFunc(r.math_trunc, nil, "trunc", nil, 1), true, false, true)
return m
}
func (r *Runtime) initMath() {
r.addToGlobal("Math", r.newLazyObject(r.createMath))
}

210
server/vendor/github.com/dop251/goja/builtin_number.go generated vendored Normal file
View File

@@ -0,0 +1,210 @@
package goja
import (
"math"
"github.com/dop251/goja/ftoa"
)
func (r *Runtime) numberproto_valueOf(call FunctionCall) Value {
this := call.This
if !isNumber(this) {
r.typeErrorResult(true, "Value is not a number")
}
switch t := this.(type) {
case valueInt, valueFloat:
return this
case *Object:
if v, ok := t.self.(*primitiveValueObject); ok {
return v.pValue
}
}
panic(r.NewTypeError("Number.prototype.valueOf is not generic"))
}
func isNumber(v Value) bool {
switch t := v.(type) {
case valueFloat, valueInt:
return true
case *Object:
switch t := t.self.(type) {
case *primitiveValueObject:
return isNumber(t.pValue)
}
}
return false
}
func (r *Runtime) numberproto_toString(call FunctionCall) Value {
if !isNumber(call.This) {
r.typeErrorResult(true, "Value is not a number")
}
var radix int
if arg := call.Argument(0); arg != _undefined {
radix = int(arg.ToInteger())
} else {
radix = 10
}
if radix < 2 || radix > 36 {
panic(r.newError(r.global.RangeError, "toString() radix argument must be between 2 and 36"))
}
num := call.This.ToFloat()
if math.IsNaN(num) {
return stringNaN
}
if math.IsInf(num, 1) {
return stringInfinity
}
if math.IsInf(num, -1) {
return stringNegInfinity
}
if radix == 10 {
return asciiString(fToStr(num, ftoa.ModeStandard, 0))
}
return asciiString(ftoa.FToBaseStr(num, radix))
}
func (r *Runtime) numberproto_toFixed(call FunctionCall) Value {
num := r.toNumber(call.This).ToFloat()
prec := call.Argument(0).ToInteger()
if prec < 0 || prec > 100 {
panic(r.newError(r.global.RangeError, "toFixed() precision must be between 0 and 100"))
}
if math.IsNaN(num) {
return stringNaN
}
return asciiString(fToStr(num, ftoa.ModeFixed, int(prec)))
}
func (r *Runtime) numberproto_toExponential(call FunctionCall) Value {
num := r.toNumber(call.This).ToFloat()
precVal := call.Argument(0)
var prec int64
if precVal == _undefined {
return asciiString(fToStr(num, ftoa.ModeStandardExponential, 0))
} else {
prec = precVal.ToInteger()
}
if math.IsNaN(num) {
return stringNaN
}
if math.IsInf(num, 1) {
return stringInfinity
}
if math.IsInf(num, -1) {
return stringNegInfinity
}
if prec < 0 || prec > 100 {
panic(r.newError(r.global.RangeError, "toExponential() precision must be between 0 and 100"))
}
return asciiString(fToStr(num, ftoa.ModeExponential, int(prec+1)))
}
func (r *Runtime) numberproto_toPrecision(call FunctionCall) Value {
numVal := r.toNumber(call.This)
precVal := call.Argument(0)
if precVal == _undefined {
return numVal.toString()
}
num := numVal.ToFloat()
prec := precVal.ToInteger()
if math.IsNaN(num) {
return stringNaN
}
if math.IsInf(num, 1) {
return stringInfinity
}
if math.IsInf(num, -1) {
return stringNegInfinity
}
if prec < 1 || prec > 100 {
panic(r.newError(r.global.RangeError, "toPrecision() precision must be between 1 and 100"))
}
return asciiString(fToStr(num, ftoa.ModePrecision, int(prec)))
}
func (r *Runtime) number_isFinite(call FunctionCall) Value {
switch arg := call.Argument(0).(type) {
case valueInt:
return valueTrue
case valueFloat:
f := float64(arg)
return r.toBoolean(!math.IsInf(f, 0) && !math.IsNaN(f))
default:
return valueFalse
}
}
func (r *Runtime) number_isInteger(call FunctionCall) Value {
switch arg := call.Argument(0).(type) {
case valueInt:
return valueTrue
case valueFloat:
f := float64(arg)
return r.toBoolean(!math.IsNaN(f) && !math.IsInf(f, 0) && math.Floor(f) == f)
default:
return valueFalse
}
}
func (r *Runtime) number_isNaN(call FunctionCall) Value {
if f, ok := call.Argument(0).(valueFloat); ok && math.IsNaN(float64(f)) {
return valueTrue
}
return valueFalse
}
func (r *Runtime) number_isSafeInteger(call FunctionCall) Value {
arg := call.Argument(0)
if i, ok := arg.(valueInt); ok && i >= -(maxInt-1) && i <= maxInt-1 {
return valueTrue
}
if arg == _negativeZero {
return valueTrue
}
return valueFalse
}
func (r *Runtime) initNumber() {
r.global.NumberPrototype = r.newPrimitiveObject(valueInt(0), r.global.ObjectPrototype, classNumber)
o := r.global.NumberPrototype.self
o._putProp("toExponential", r.newNativeFunc(r.numberproto_toExponential, nil, "toExponential", nil, 1), true, false, true)
o._putProp("toFixed", r.newNativeFunc(r.numberproto_toFixed, nil, "toFixed", nil, 1), true, false, true)
o._putProp("toLocaleString", r.newNativeFunc(r.numberproto_toString, nil, "toLocaleString", nil, 0), true, false, true)
o._putProp("toPrecision", r.newNativeFunc(r.numberproto_toPrecision, nil, "toPrecision", nil, 1), true, false, true)
o._putProp("toString", r.newNativeFunc(r.numberproto_toString, nil, "toString", nil, 1), true, false, true)
o._putProp("valueOf", r.newNativeFunc(r.numberproto_valueOf, nil, "valueOf", nil, 0), true, false, true)
r.global.Number = r.newNativeFunc(r.builtin_Number, r.builtin_newNumber, "Number", r.global.NumberPrototype, 1)
o = r.global.Number.self
o._putProp("EPSILON", _epsilon, false, false, false)
o._putProp("isFinite", r.newNativeFunc(r.number_isFinite, nil, "isFinite", nil, 1), true, false, true)
o._putProp("isInteger", r.newNativeFunc(r.number_isInteger, nil, "isInteger", nil, 1), true, false, true)
o._putProp("isNaN", r.newNativeFunc(r.number_isNaN, nil, "isNaN", nil, 1), true, false, true)
o._putProp("isSafeInteger", r.newNativeFunc(r.number_isSafeInteger, nil, "isSafeInteger", nil, 1), true, false, true)
o._putProp("MAX_SAFE_INTEGER", valueInt(maxInt-1), false, false, false)
o._putProp("MIN_SAFE_INTEGER", valueInt(-(maxInt - 1)), false, false, false)
o._putProp("MIN_VALUE", valueFloat(math.SmallestNonzeroFloat64), false, false, false)
o._putProp("MAX_VALUE", valueFloat(math.MaxFloat64), false, false, false)
o._putProp("NaN", _NaN, false, false, false)
o._putProp("NEGATIVE_INFINITY", _negativeInf, false, false, false)
o._putProp("parseFloat", r.Get("parseFloat"), true, false, true)
o._putProp("parseInt", r.Get("parseInt"), true, false, true)
o._putProp("POSITIVE_INFINITY", _positiveInf, false, false, false)
r.addToGlobal("Number", r.global.Number)
}

634
server/vendor/github.com/dop251/goja/builtin_object.go generated vendored Normal file
View File

@@ -0,0 +1,634 @@
package goja
import (
"fmt"
)
func (r *Runtime) builtin_Object(args []Value, newTarget *Object) *Object {
if newTarget != nil && newTarget != r.global.Object {
proto := r.getPrototypeFromCtor(newTarget, nil, r.global.ObjectPrototype)
return r.newBaseObject(proto, classObject).val
}
if len(args) > 0 {
arg := args[0]
if arg != _undefined && arg != _null {
return arg.ToObject(r)
}
}
return r.NewObject()
}
func (r *Runtime) object_getPrototypeOf(call FunctionCall) Value {
o := call.Argument(0).ToObject(r)
p := o.self.proto()
if p == nil {
return _null
}
return p
}
func (r *Runtime) valuePropToDescriptorObject(desc Value) Value {
if desc == nil {
return _undefined
}
var writable, configurable, enumerable, accessor bool
var get, set *Object
var value Value
if v, ok := desc.(*valueProperty); ok {
writable = v.writable
configurable = v.configurable
enumerable = v.enumerable
accessor = v.accessor
value = v.value
get = v.getterFunc
set = v.setterFunc
} else {
writable = true
configurable = true
enumerable = true
value = desc
}
ret := r.NewObject()
obj := ret.self
if !accessor {
obj.setOwnStr("value", value, false)
obj.setOwnStr("writable", r.toBoolean(writable), false)
} else {
if get != nil {
obj.setOwnStr("get", get, false)
} else {
obj.setOwnStr("get", _undefined, false)
}
if set != nil {
obj.setOwnStr("set", set, false)
} else {
obj.setOwnStr("set", _undefined, false)
}
}
obj.setOwnStr("enumerable", r.toBoolean(enumerable), false)
obj.setOwnStr("configurable", r.toBoolean(configurable), false)
return ret
}
func (r *Runtime) object_getOwnPropertyDescriptor(call FunctionCall) Value {
o := call.Argument(0).ToObject(r)
propName := toPropertyKey(call.Argument(1))
return r.valuePropToDescriptorObject(o.getOwnProp(propName))
}
func (r *Runtime) object_getOwnPropertyDescriptors(call FunctionCall) Value {
o := call.Argument(0).ToObject(r)
result := r.newBaseObject(r.global.ObjectPrototype, classObject).val
for item, next := o.self.iterateKeys()(); next != nil; item, next = next() {
var prop Value
if item.value == nil {
prop = o.getOwnProp(item.name)
if prop == nil {
continue
}
} else {
prop = item.value
}
descriptor := r.valuePropToDescriptorObject(prop)
if descriptor != _undefined {
createDataPropertyOrThrow(result, item.name, descriptor)
}
}
return result
}
func (r *Runtime) object_getOwnPropertyNames(call FunctionCall) Value {
obj := call.Argument(0).ToObject(r)
return r.newArrayValues(obj.self.stringKeys(true, nil))
}
func (r *Runtime) object_getOwnPropertySymbols(call FunctionCall) Value {
obj := call.Argument(0).ToObject(r)
return r.newArrayValues(obj.self.symbols(true, nil))
}
func (r *Runtime) toValueProp(v Value) *valueProperty {
if v == nil || v == _undefined {
return nil
}
obj := r.toObject(v)
getter := obj.self.getStr("get", nil)
setter := obj.self.getStr("set", nil)
writable := obj.self.getStr("writable", nil)
value := obj.self.getStr("value", nil)
if (getter != nil || setter != nil) && (value != nil || writable != nil) {
r.typeErrorResult(true, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute")
}
ret := &valueProperty{}
if writable != nil && writable.ToBoolean() {
ret.writable = true
}
if e := obj.self.getStr("enumerable", nil); e != nil && e.ToBoolean() {
ret.enumerable = true
}
if c := obj.self.getStr("configurable", nil); c != nil && c.ToBoolean() {
ret.configurable = true
}
ret.value = value
if getter != nil && getter != _undefined {
o := r.toObject(getter)
if _, ok := o.self.assertCallable(); !ok {
r.typeErrorResult(true, "getter must be a function")
}
ret.getterFunc = o
}
if setter != nil && setter != _undefined {
o := r.toObject(setter)
if _, ok := o.self.assertCallable(); !ok {
r.typeErrorResult(true, "setter must be a function")
}
ret.setterFunc = o
}
if ret.getterFunc != nil || ret.setterFunc != nil {
ret.accessor = true
}
return ret
}
func (r *Runtime) toPropertyDescriptor(v Value) (ret PropertyDescriptor) {
if o, ok := v.(*Object); ok {
descr := o.self
// Save the original descriptor for reference
ret.jsDescriptor = o
ret.Value = descr.getStr("value", nil)
if p := descr.getStr("writable", nil); p != nil {
ret.Writable = ToFlag(p.ToBoolean())
}
if p := descr.getStr("enumerable", nil); p != nil {
ret.Enumerable = ToFlag(p.ToBoolean())
}
if p := descr.getStr("configurable", nil); p != nil {
ret.Configurable = ToFlag(p.ToBoolean())
}
ret.Getter = descr.getStr("get", nil)
ret.Setter = descr.getStr("set", nil)
if ret.Getter != nil && ret.Getter != _undefined {
if _, ok := r.toObject(ret.Getter).self.assertCallable(); !ok {
r.typeErrorResult(true, "getter must be a function")
}
}
if ret.Setter != nil && ret.Setter != _undefined {
if _, ok := r.toObject(ret.Setter).self.assertCallable(); !ok {
r.typeErrorResult(true, "setter must be a function")
}
}
if (ret.Getter != nil || ret.Setter != nil) && (ret.Value != nil || ret.Writable != FLAG_NOT_SET) {
r.typeErrorResult(true, "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute")
}
} else {
r.typeErrorResult(true, "Property description must be an object: %s", v.String())
}
return
}
func (r *Runtime) _defineProperties(o *Object, p Value) {
type propItem struct {
name Value
prop PropertyDescriptor
}
props := p.ToObject(r)
var list []propItem
for item, next := iterateEnumerableProperties(props)(); next != nil; item, next = next() {
list = append(list, propItem{
name: item.name,
prop: r.toPropertyDescriptor(item.value),
})
}
for _, prop := range list {
o.defineOwnProperty(prop.name, prop.prop, true)
}
}
func (r *Runtime) object_create(call FunctionCall) Value {
var proto *Object
if arg := call.Argument(0); arg != _null {
if o, ok := arg.(*Object); ok {
proto = o
} else {
r.typeErrorResult(true, "Object prototype may only be an Object or null: %s", arg.String())
}
}
o := r.newBaseObject(proto, classObject).val
if props := call.Argument(1); props != _undefined {
r._defineProperties(o, props)
}
return o
}
func (r *Runtime) object_defineProperty(call FunctionCall) (ret Value) {
if obj, ok := call.Argument(0).(*Object); ok {
descr := r.toPropertyDescriptor(call.Argument(2))
obj.defineOwnProperty(toPropertyKey(call.Argument(1)), descr, true)
ret = call.Argument(0)
} else {
r.typeErrorResult(true, "Object.defineProperty called on non-object")
}
return
}
func (r *Runtime) object_defineProperties(call FunctionCall) Value {
obj := r.toObject(call.Argument(0))
r._defineProperties(obj, call.Argument(1))
return obj
}
func (r *Runtime) object_seal(call FunctionCall) Value {
// ES6
arg := call.Argument(0)
if obj, ok := arg.(*Object); ok {
obj.self.preventExtensions(true)
descr := PropertyDescriptor{
Configurable: FLAG_FALSE,
}
for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
if prop, ok := item.value.(*valueProperty); ok {
prop.configurable = false
} else {
obj.defineOwnProperty(item.name, descr, true)
}
}
return obj
}
return arg
}
func (r *Runtime) object_freeze(call FunctionCall) Value {
arg := call.Argument(0)
if obj, ok := arg.(*Object); ok {
obj.self.preventExtensions(true)
for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
if prop, ok := item.value.(*valueProperty); ok {
prop.configurable = false
if !prop.accessor {
prop.writable = false
}
} else {
prop := obj.getOwnProp(item.name)
descr := PropertyDescriptor{
Configurable: FLAG_FALSE,
}
if prop, ok := prop.(*valueProperty); ok && prop.accessor {
// no-op
} else {
descr.Writable = FLAG_FALSE
}
obj.defineOwnProperty(item.name, descr, true)
}
}
return obj
} else {
// ES6 behavior
return arg
}
}
func (r *Runtime) object_preventExtensions(call FunctionCall) (ret Value) {
arg := call.Argument(0)
if obj, ok := arg.(*Object); ok {
obj.self.preventExtensions(true)
}
return arg
}
func (r *Runtime) object_isSealed(call FunctionCall) Value {
if obj, ok := call.Argument(0).(*Object); ok {
if obj.self.isExtensible() {
return valueFalse
}
for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
var prop Value
if item.value == nil {
prop = obj.getOwnProp(item.name)
if prop == nil {
continue
}
} else {
prop = item.value
}
if prop, ok := prop.(*valueProperty); ok {
if prop.configurable {
return valueFalse
}
} else {
return valueFalse
}
}
}
return valueTrue
}
func (r *Runtime) object_isFrozen(call FunctionCall) Value {
if obj, ok := call.Argument(0).(*Object); ok {
if obj.self.isExtensible() {
return valueFalse
}
for item, next := obj.self.iterateKeys()(); next != nil; item, next = next() {
var prop Value
if item.value == nil {
prop = obj.getOwnProp(item.name)
if prop == nil {
continue
}
} else {
prop = item.value
}
if prop, ok := prop.(*valueProperty); ok {
if prop.configurable || prop.value != nil && prop.writable {
return valueFalse
}
} else {
return valueFalse
}
}
}
return valueTrue
}
func (r *Runtime) object_isExtensible(call FunctionCall) Value {
if obj, ok := call.Argument(0).(*Object); ok {
if obj.self.isExtensible() {
return valueTrue
}
return valueFalse
} else {
// ES6
//r.typeErrorResult(true, "Object.isExtensible called on non-object")
return valueFalse
}
}
func (r *Runtime) object_keys(call FunctionCall) Value {
obj := call.Argument(0).ToObject(r)
return r.newArrayValues(obj.self.stringKeys(false, nil))
}
func (r *Runtime) object_entries(call FunctionCall) Value {
obj := call.Argument(0).ToObject(r)
var values []Value
for item, next := iterateEnumerableStringProperties(obj)(); next != nil; item, next = next() {
values = append(values, r.newArrayValues([]Value{item.name, item.value}))
}
return r.newArrayValues(values)
}
func (r *Runtime) object_values(call FunctionCall) Value {
obj := call.Argument(0).ToObject(r)
var values []Value
for item, next := iterateEnumerableStringProperties(obj)(); next != nil; item, next = next() {
values = append(values, item.value)
}
return r.newArrayValues(values)
}
func (r *Runtime) objectproto_hasOwnProperty(call FunctionCall) Value {
p := toPropertyKey(call.Argument(0))
o := call.This.ToObject(r)
if o.hasOwnProperty(p) {
return valueTrue
} else {
return valueFalse
}
}
func (r *Runtime) objectproto_isPrototypeOf(call FunctionCall) Value {
if v, ok := call.Argument(0).(*Object); ok {
o := call.This.ToObject(r)
for {
v = v.self.proto()
if v == nil {
break
}
if v == o {
return valueTrue
}
}
}
return valueFalse
}
func (r *Runtime) objectproto_propertyIsEnumerable(call FunctionCall) Value {
p := toPropertyKey(call.Argument(0))
o := call.This.ToObject(r)
pv := o.getOwnProp(p)
if pv == nil {
return valueFalse
}
if prop, ok := pv.(*valueProperty); ok {
if !prop.enumerable {
return valueFalse
}
}
return valueTrue
}
func (r *Runtime) objectproto_toString(call FunctionCall) Value {
switch o := call.This.(type) {
case valueNull:
return stringObjectNull
case valueUndefined:
return stringObjectUndefined
default:
obj := o.ToObject(r)
var clsName string
if isArray(obj) {
clsName = classArray
} else {
clsName = obj.self.className()
}
if tag := obj.self.getSym(SymToStringTag, nil); tag != nil {
if str, ok := tag.(valueString); ok {
clsName = str.String()
}
}
return newStringValue(fmt.Sprintf("[object %s]", clsName))
}
}
func (r *Runtime) objectproto_toLocaleString(call FunctionCall) Value {
toString := toMethod(r.getVStr(call.This, "toString"))
return toString(FunctionCall{This: call.This})
}
func (r *Runtime) objectproto_getProto(call FunctionCall) Value {
proto := call.This.ToObject(r).self.proto()
if proto != nil {
return proto
}
return _null
}
func (r *Runtime) setObjectProto(o, arg Value) {
r.checkObjectCoercible(o)
var proto *Object
if arg != _null {
if obj, ok := arg.(*Object); ok {
proto = obj
} else {
return
}
}
if o, ok := o.(*Object); ok {
o.self.setProto(proto, true)
}
}
func (r *Runtime) objectproto_setProto(call FunctionCall) Value {
r.setObjectProto(call.This, call.Argument(0))
return _undefined
}
func (r *Runtime) objectproto_valueOf(call FunctionCall) Value {
return call.This.ToObject(r)
}
func (r *Runtime) object_assign(call FunctionCall) Value {
to := call.Argument(0).ToObject(r)
if len(call.Arguments) > 1 {
for _, arg := range call.Arguments[1:] {
if arg != _undefined && arg != _null {
source := arg.ToObject(r)
for item, next := iterateEnumerableProperties(source)(); next != nil; item, next = next() {
to.setOwn(item.name, item.value, true)
}
}
}
}
return to
}
func (r *Runtime) object_is(call FunctionCall) Value {
return r.toBoolean(call.Argument(0).SameAs(call.Argument(1)))
}
func (r *Runtime) toProto(proto Value) *Object {
if proto != _null {
if obj, ok := proto.(*Object); ok {
return obj
} else {
panic(r.NewTypeError("Object prototype may only be an Object or null: %s", proto))
}
}
return nil
}
func (r *Runtime) object_setPrototypeOf(call FunctionCall) Value {
o := call.Argument(0)
r.checkObjectCoercible(o)
proto := r.toProto(call.Argument(1))
if o, ok := o.(*Object); ok {
o.self.setProto(proto, true)
}
return o
}
func (r *Runtime) object_fromEntries(call FunctionCall) Value {
o := call.Argument(0)
r.checkObjectCoercible(o)
result := r.newBaseObject(r.global.ObjectPrototype, classObject).val
iter := r.getIterator(o, nil)
iter.iterate(func(nextValue Value) {
i0 := valueInt(0)
i1 := valueInt(1)
itemObj := r.toObject(nextValue)
k := itemObj.self.getIdx(i0, nil)
v := itemObj.self.getIdx(i1, nil)
key := toPropertyKey(k)
createDataPropertyOrThrow(result, key, v)
})
return result
}
func (r *Runtime) object_hasOwn(call FunctionCall) Value {
o := call.Argument(0)
obj := o.ToObject(r)
p := toPropertyKey(call.Argument(1))
if obj.hasOwnProperty(p) {
return valueTrue
} else {
return valueFalse
}
}
func (r *Runtime) initObject() {
o := r.global.ObjectPrototype.self
o._putProp("toString", r.newNativeFunc(r.objectproto_toString, nil, "toString", nil, 0), true, false, true)
o._putProp("toLocaleString", r.newNativeFunc(r.objectproto_toLocaleString, nil, "toLocaleString", nil, 0), true, false, true)
o._putProp("valueOf", r.newNativeFunc(r.objectproto_valueOf, nil, "valueOf", nil, 0), true, false, true)
o._putProp("hasOwnProperty", r.newNativeFunc(r.objectproto_hasOwnProperty, nil, "hasOwnProperty", nil, 1), true, false, true)
o._putProp("isPrototypeOf", r.newNativeFunc(r.objectproto_isPrototypeOf, nil, "isPrototypeOf", nil, 1), true, false, true)
o._putProp("propertyIsEnumerable", r.newNativeFunc(r.objectproto_propertyIsEnumerable, nil, "propertyIsEnumerable", nil, 1), true, false, true)
o.defineOwnPropertyStr(__proto__, PropertyDescriptor{
Getter: r.newNativeFunc(r.objectproto_getProto, nil, "get __proto__", nil, 0),
Setter: r.newNativeFunc(r.objectproto_setProto, nil, "set __proto__", nil, 1),
Configurable: FLAG_TRUE,
}, true)
r.global.Object = r.newNativeConstructOnly(nil, r.builtin_Object, r.global.ObjectPrototype, "Object", 1).val
r.global.ObjectPrototype.self._putProp("constructor", r.global.Object, true, false, true)
o = r.global.Object.self
o._putProp("assign", r.newNativeFunc(r.object_assign, nil, "assign", nil, 2), true, false, true)
o._putProp("defineProperty", r.newNativeFunc(r.object_defineProperty, nil, "defineProperty", nil, 3), true, false, true)
o._putProp("defineProperties", r.newNativeFunc(r.object_defineProperties, nil, "defineProperties", nil, 2), true, false, true)
o._putProp("entries", r.newNativeFunc(r.object_entries, nil, "entries", nil, 1), true, false, true)
o._putProp("getOwnPropertyDescriptor", r.newNativeFunc(r.object_getOwnPropertyDescriptor, nil, "getOwnPropertyDescriptor", nil, 2), true, false, true)
o._putProp("getOwnPropertyDescriptors", r.newNativeFunc(r.object_getOwnPropertyDescriptors, nil, "getOwnPropertyDescriptors", nil, 1), true, false, true)
o._putProp("getPrototypeOf", r.newNativeFunc(r.object_getPrototypeOf, nil, "getPrototypeOf", nil, 1), true, false, true)
o._putProp("is", r.newNativeFunc(r.object_is, nil, "is", nil, 2), true, false, true)
o._putProp("getOwnPropertyNames", r.newNativeFunc(r.object_getOwnPropertyNames, nil, "getOwnPropertyNames", nil, 1), true, false, true)
o._putProp("getOwnPropertySymbols", r.newNativeFunc(r.object_getOwnPropertySymbols, nil, "getOwnPropertySymbols", nil, 1), true, false, true)
o._putProp("create", r.newNativeFunc(r.object_create, nil, "create", nil, 2), true, false, true)
o._putProp("seal", r.newNativeFunc(r.object_seal, nil, "seal", nil, 1), true, false, true)
o._putProp("freeze", r.newNativeFunc(r.object_freeze, nil, "freeze", nil, 1), true, false, true)
o._putProp("preventExtensions", r.newNativeFunc(r.object_preventExtensions, nil, "preventExtensions", nil, 1), true, false, true)
o._putProp("isSealed", r.newNativeFunc(r.object_isSealed, nil, "isSealed", nil, 1), true, false, true)
o._putProp("isFrozen", r.newNativeFunc(r.object_isFrozen, nil, "isFrozen", nil, 1), true, false, true)
o._putProp("isExtensible", r.newNativeFunc(r.object_isExtensible, nil, "isExtensible", nil, 1), true, false, true)
o._putProp("keys", r.newNativeFunc(r.object_keys, nil, "keys", nil, 1), true, false, true)
o._putProp("setPrototypeOf", r.newNativeFunc(r.object_setPrototypeOf, nil, "setPrototypeOf", nil, 2), true, false, true)
o._putProp("values", r.newNativeFunc(r.object_values, nil, "values", nil, 1), true, false, true)
o._putProp("fromEntries", r.newNativeFunc(r.object_fromEntries, nil, "fromEntries", nil, 1), true, false, true)
o._putProp("hasOwn", r.newNativeFunc(r.object_hasOwn, nil, "hasOwn", nil, 2), true, false, true)
r.addToGlobal("Object", r.global.Object)
}

633
server/vendor/github.com/dop251/goja/builtin_promise.go generated vendored Normal file
View File

@@ -0,0 +1,633 @@
package goja
import (
"github.com/dop251/goja/unistring"
"reflect"
)
type PromiseState int
type PromiseRejectionOperation int
type promiseReactionType int
const (
PromiseStatePending PromiseState = iota
PromiseStateFulfilled
PromiseStateRejected
)
const (
PromiseRejectionReject PromiseRejectionOperation = iota
PromiseRejectionHandle
)
const (
promiseReactionFulfill promiseReactionType = iota
promiseReactionReject
)
type PromiseRejectionTracker func(p *Promise, operation PromiseRejectionOperation)
type jobCallback struct {
callback func(FunctionCall) Value
}
type promiseCapability struct {
promise *Object
resolveObj, rejectObj *Object
}
type promiseReaction struct {
capability *promiseCapability
typ promiseReactionType
handler *jobCallback
asyncRunner *asyncRunner
asyncCtx interface{}
}
var typePromise = reflect.TypeOf((*Promise)(nil))
// Promise is a Go wrapper around ECMAScript Promise. Calling Runtime.ToValue() on it
// returns the underlying Object. Calling Export() on a Promise Object returns a Promise.
//
// Use Runtime.NewPromise() to create one. Calling Runtime.ToValue() on a zero object or nil returns null Value.
//
// WARNING: Instances of Promise are not goroutine-safe. See Runtime.NewPromise() for more details.
type Promise struct {
baseObject
state PromiseState
result Value
fulfillReactions []*promiseReaction
rejectReactions []*promiseReaction
handled bool
}
func (p *Promise) State() PromiseState {
return p.state
}
func (p *Promise) Result() Value {
return p.result
}
func (p *Promise) toValue(r *Runtime) Value {
if p == nil || p.val == nil {
return _null
}
promise := p.val
if promise.runtime != r {
panic(r.NewTypeError("Illegal runtime transition of a Promise"))
}
return promise
}
func (p *Promise) createResolvingFunctions() (resolve, reject *Object) {
r := p.val.runtime
alreadyResolved := false
return p.val.runtime.newNativeFunc(func(call FunctionCall) Value {
if alreadyResolved {
return _undefined
}
alreadyResolved = true
resolution := call.Argument(0)
if resolution.SameAs(p.val) {
return p.reject(r.NewTypeError("Promise self-resolution"))
}
if obj, ok := resolution.(*Object); ok {
var thenAction Value
ex := r.vm.try(func() {
thenAction = obj.self.getStr("then", nil)
})
if ex != nil {
return p.reject(ex.val)
}
if call, ok := assertCallable(thenAction); ok {
job := r.newPromiseResolveThenableJob(p, resolution, &jobCallback{callback: call})
r.enqueuePromiseJob(job)
return _undefined
}
}
return p.fulfill(resolution)
}, nil, "", nil, 1),
p.val.runtime.newNativeFunc(func(call FunctionCall) Value {
if alreadyResolved {
return _undefined
}
alreadyResolved = true
reason := call.Argument(0)
return p.reject(reason)
}, nil, "", nil, 1)
}
func (p *Promise) reject(reason Value) Value {
reactions := p.rejectReactions
p.result = reason
p.fulfillReactions, p.rejectReactions = nil, nil
p.state = PromiseStateRejected
r := p.val.runtime
if !p.handled {
r.trackPromiseRejection(p, PromiseRejectionReject)
}
r.triggerPromiseReactions(reactions, reason)
return _undefined
}
func (p *Promise) fulfill(value Value) Value {
reactions := p.fulfillReactions
p.result = value
p.fulfillReactions, p.rejectReactions = nil, nil
p.state = PromiseStateFulfilled
p.val.runtime.triggerPromiseReactions(reactions, value)
return _undefined
}
func (p *Promise) exportType() reflect.Type {
return typePromise
}
func (p *Promise) export(*objectExportCtx) interface{} {
return p
}
func (p *Promise) addReactions(fulfillReaction *promiseReaction, rejectReaction *promiseReaction) {
r := p.val.runtime
if tracker := r.asyncContextTracker; tracker != nil {
ctx := tracker.Grab()
fulfillReaction.asyncCtx = ctx
rejectReaction.asyncCtx = ctx
}
switch p.state {
case PromiseStatePending:
p.fulfillReactions = append(p.fulfillReactions, fulfillReaction)
p.rejectReactions = append(p.rejectReactions, rejectReaction)
case PromiseStateFulfilled:
r.enqueuePromiseJob(r.newPromiseReactionJob(fulfillReaction, p.result))
default:
reason := p.result
if !p.handled {
r.trackPromiseRejection(p, PromiseRejectionHandle)
}
r.enqueuePromiseJob(r.newPromiseReactionJob(rejectReaction, reason))
}
p.handled = true
}
func (r *Runtime) newPromiseResolveThenableJob(p *Promise, thenable Value, then *jobCallback) func() {
return func() {
resolve, reject := p.createResolvingFunctions()
ex := r.vm.try(func() {
r.callJobCallback(then, thenable, resolve, reject)
})
if ex != nil {
if fn, ok := reject.self.assertCallable(); ok {
fn(FunctionCall{Arguments: []Value{ex.val}})
}
}
}
}
func (r *Runtime) enqueuePromiseJob(job func()) {
r.jobQueue = append(r.jobQueue, job)
}
func (r *Runtime) triggerPromiseReactions(reactions []*promiseReaction, argument Value) {
for _, reaction := range reactions {
r.enqueuePromiseJob(r.newPromiseReactionJob(reaction, argument))
}
}
func (r *Runtime) newPromiseReactionJob(reaction *promiseReaction, argument Value) func() {
return func() {
var handlerResult Value
fulfill := false
if reaction.handler == nil {
handlerResult = argument
if reaction.typ == promiseReactionFulfill {
fulfill = true
}
} else {
if tracker := r.asyncContextTracker; tracker != nil {
tracker.Resumed(reaction.asyncCtx)
}
ex := r.vm.try(func() {
handlerResult = r.callJobCallback(reaction.handler, _undefined, argument)
fulfill = true
})
if ex != nil {
handlerResult = ex.val
}
if tracker := r.asyncContextTracker; tracker != nil {
tracker.Exited()
}
}
if reaction.capability != nil {
if fulfill {
reaction.capability.resolve(handlerResult)
} else {
reaction.capability.reject(handlerResult)
}
}
}
}
func (r *Runtime) newPromise(proto *Object) *Promise {
o := &Object{runtime: r}
po := &Promise{}
po.class = classObject
po.val = o
po.extensible = true
o.self = po
po.prototype = proto
po.init()
return po
}
func (r *Runtime) builtin_newPromise(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("Promise"))
}
var arg0 Value
if len(args) > 0 {
arg0 = args[0]
}
executor := r.toCallable(arg0)
proto := r.getPrototypeFromCtor(newTarget, r.global.Promise, r.global.PromisePrototype)
po := r.newPromise(proto)
resolve, reject := po.createResolvingFunctions()
ex := r.vm.try(func() {
executor(FunctionCall{Arguments: []Value{resolve, reject}})
})
if ex != nil {
if fn, ok := reject.self.assertCallable(); ok {
fn(FunctionCall{Arguments: []Value{ex.val}})
}
}
return po.val
}
func (r *Runtime) promiseProto_then(call FunctionCall) Value {
thisObj := r.toObject(call.This)
if p, ok := thisObj.self.(*Promise); ok {
c := r.speciesConstructorObj(thisObj, r.global.Promise)
resultCapability := r.newPromiseCapability(c)
return r.performPromiseThen(p, call.Argument(0), call.Argument(1), resultCapability)
}
panic(r.NewTypeError("Method Promise.prototype.then called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
func (r *Runtime) newPromiseCapability(c *Object) *promiseCapability {
pcap := new(promiseCapability)
if c == r.global.Promise {
p := r.newPromise(r.global.PromisePrototype)
pcap.resolveObj, pcap.rejectObj = p.createResolvingFunctions()
pcap.promise = p.val
} else {
var resolve, reject Value
executor := r.newNativeFunc(func(call FunctionCall) Value {
if resolve != nil {
panic(r.NewTypeError("resolve is already set"))
}
if reject != nil {
panic(r.NewTypeError("reject is already set"))
}
if arg := call.Argument(0); arg != _undefined {
resolve = arg
}
if arg := call.Argument(1); arg != _undefined {
reject = arg
}
return nil
}, nil, "", nil, 2)
pcap.promise = r.toConstructor(c)([]Value{executor}, c)
pcap.resolveObj = r.toObject(resolve)
r.toCallable(pcap.resolveObj) // make sure it's callable
pcap.rejectObj = r.toObject(reject)
r.toCallable(pcap.rejectObj)
}
return pcap
}
func (r *Runtime) performPromiseThen(p *Promise, onFulfilled, onRejected Value, resultCapability *promiseCapability) Value {
var onFulfilledJobCallback, onRejectedJobCallback *jobCallback
if f, ok := assertCallable(onFulfilled); ok {
onFulfilledJobCallback = &jobCallback{callback: f}
}
if f, ok := assertCallable(onRejected); ok {
onRejectedJobCallback = &jobCallback{callback: f}
}
fulfillReaction := &promiseReaction{
capability: resultCapability,
typ: promiseReactionFulfill,
handler: onFulfilledJobCallback,
}
rejectReaction := &promiseReaction{
capability: resultCapability,
typ: promiseReactionReject,
handler: onRejectedJobCallback,
}
p.addReactions(fulfillReaction, rejectReaction)
if resultCapability == nil {
return _undefined
}
return resultCapability.promise
}
func (r *Runtime) promiseProto_catch(call FunctionCall) Value {
return r.invoke(call.This, "then", _undefined, call.Argument(0))
}
func (r *Runtime) promiseResolve(c *Object, x Value) *Object {
if obj, ok := x.(*Object); ok {
xConstructor := nilSafe(obj.self.getStr("constructor", nil))
if xConstructor.SameAs(c) {
return obj
}
}
pcap := r.newPromiseCapability(c)
pcap.resolve(x)
return pcap.promise
}
func (r *Runtime) promiseProto_finally(call FunctionCall) Value {
promise := r.toObject(call.This)
c := r.speciesConstructorObj(promise, r.global.Promise)
onFinally := call.Argument(0)
var thenFinally, catchFinally Value
if onFinallyFn, ok := assertCallable(onFinally); !ok {
thenFinally, catchFinally = onFinally, onFinally
} else {
thenFinally = r.newNativeFunc(func(call FunctionCall) Value {
value := call.Argument(0)
result := onFinallyFn(FunctionCall{})
promise := r.promiseResolve(c, result)
valueThunk := r.newNativeFunc(func(call FunctionCall) Value {
return value
}, nil, "", nil, 0)
return r.invoke(promise, "then", valueThunk)
}, nil, "", nil, 1)
catchFinally = r.newNativeFunc(func(call FunctionCall) Value {
reason := call.Argument(0)
result := onFinallyFn(FunctionCall{})
promise := r.promiseResolve(c, result)
thrower := r.newNativeFunc(func(call FunctionCall) Value {
panic(reason)
}, nil, "", nil, 0)
return r.invoke(promise, "then", thrower)
}, nil, "", nil, 1)
}
return r.invoke(promise, "then", thenFinally, catchFinally)
}
func (pcap *promiseCapability) resolve(result Value) {
pcap.promise.runtime.toCallable(pcap.resolveObj)(FunctionCall{Arguments: []Value{result}})
}
func (pcap *promiseCapability) reject(reason Value) {
pcap.promise.runtime.toCallable(pcap.rejectObj)(FunctionCall{Arguments: []Value{reason}})
}
func (pcap *promiseCapability) try(f func()) bool {
ex := pcap.promise.runtime.vm.try(f)
if ex != nil {
pcap.reject(ex.val)
return false
}
return true
}
func (r *Runtime) promise_all(call FunctionCall) Value {
c := r.toObject(call.This)
pcap := r.newPromiseCapability(c)
pcap.try(func() {
promiseResolve := r.toCallable(c.self.getStr("resolve", nil))
iter := r.getIterator(call.Argument(0), nil)
var values []Value
remainingElementsCount := 1
iter.iterate(func(nextValue Value) {
index := len(values)
values = append(values, _undefined)
nextPromise := promiseResolve(FunctionCall{This: c, Arguments: []Value{nextValue}})
alreadyCalled := false
onFulfilled := r.newNativeFunc(func(call FunctionCall) Value {
if alreadyCalled {
return _undefined
}
alreadyCalled = true
values[index] = call.Argument(0)
remainingElementsCount--
if remainingElementsCount == 0 {
pcap.resolve(r.newArrayValues(values))
}
return _undefined
}, nil, "", nil, 1)
remainingElementsCount++
r.invoke(nextPromise, "then", onFulfilled, pcap.rejectObj)
})
remainingElementsCount--
if remainingElementsCount == 0 {
pcap.resolve(r.newArrayValues(values))
}
})
return pcap.promise
}
func (r *Runtime) promise_allSettled(call FunctionCall) Value {
c := r.toObject(call.This)
pcap := r.newPromiseCapability(c)
pcap.try(func() {
promiseResolve := r.toCallable(c.self.getStr("resolve", nil))
iter := r.getIterator(call.Argument(0), nil)
var values []Value
remainingElementsCount := 1
iter.iterate(func(nextValue Value) {
index := len(values)
values = append(values, _undefined)
nextPromise := promiseResolve(FunctionCall{This: c, Arguments: []Value{nextValue}})
alreadyCalled := false
reaction := func(status Value, valueKey unistring.String) *Object {
return r.newNativeFunc(func(call FunctionCall) Value {
if alreadyCalled {
return _undefined
}
alreadyCalled = true
obj := r.NewObject()
obj.self._putProp("status", status, true, true, true)
obj.self._putProp(valueKey, call.Argument(0), true, true, true)
values[index] = obj
remainingElementsCount--
if remainingElementsCount == 0 {
pcap.resolve(r.newArrayValues(values))
}
return _undefined
}, nil, "", nil, 1)
}
onFulfilled := reaction(asciiString("fulfilled"), "value")
onRejected := reaction(asciiString("rejected"), "reason")
remainingElementsCount++
r.invoke(nextPromise, "then", onFulfilled, onRejected)
})
remainingElementsCount--
if remainingElementsCount == 0 {
pcap.resolve(r.newArrayValues(values))
}
})
return pcap.promise
}
func (r *Runtime) promise_any(call FunctionCall) Value {
c := r.toObject(call.This)
pcap := r.newPromiseCapability(c)
pcap.try(func() {
promiseResolve := r.toCallable(c.self.getStr("resolve", nil))
iter := r.getIterator(call.Argument(0), nil)
var errors []Value
remainingElementsCount := 1
iter.iterate(func(nextValue Value) {
index := len(errors)
errors = append(errors, _undefined)
nextPromise := promiseResolve(FunctionCall{This: c, Arguments: []Value{nextValue}})
alreadyCalled := false
onRejected := r.newNativeFunc(func(call FunctionCall) Value {
if alreadyCalled {
return _undefined
}
alreadyCalled = true
errors[index] = call.Argument(0)
remainingElementsCount--
if remainingElementsCount == 0 {
_error := r.builtin_new(r.global.AggregateError, nil)
_error.self._putProp("errors", r.newArrayValues(errors), true, false, true)
pcap.reject(_error)
}
return _undefined
}, nil, "", nil, 1)
remainingElementsCount++
r.invoke(nextPromise, "then", pcap.resolveObj, onRejected)
})
remainingElementsCount--
if remainingElementsCount == 0 {
_error := r.builtin_new(r.global.AggregateError, nil)
_error.self._putProp("errors", r.newArrayValues(errors), true, false, true)
pcap.reject(_error)
}
})
return pcap.promise
}
func (r *Runtime) promise_race(call FunctionCall) Value {
c := r.toObject(call.This)
pcap := r.newPromiseCapability(c)
pcap.try(func() {
promiseResolve := r.toCallable(c.self.getStr("resolve", nil))
iter := r.getIterator(call.Argument(0), nil)
iter.iterate(func(nextValue Value) {
nextPromise := promiseResolve(FunctionCall{This: c, Arguments: []Value{nextValue}})
r.invoke(nextPromise, "then", pcap.resolveObj, pcap.rejectObj)
})
})
return pcap.promise
}
func (r *Runtime) promise_reject(call FunctionCall) Value {
pcap := r.newPromiseCapability(r.toObject(call.This))
pcap.reject(call.Argument(0))
return pcap.promise
}
func (r *Runtime) promise_resolve(call FunctionCall) Value {
return r.promiseResolve(r.toObject(call.This), call.Argument(0))
}
func (r *Runtime) createPromiseProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("constructor", r.global.Promise, true, false, true)
o._putProp("catch", r.newNativeFunc(r.promiseProto_catch, nil, "catch", nil, 1), true, false, true)
o._putProp("finally", r.newNativeFunc(r.promiseProto_finally, nil, "finally", nil, 1), true, false, true)
o._putProp("then", r.newNativeFunc(r.promiseProto_then, nil, "then", nil, 2), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classPromise), false, false, true))
return o
}
func (r *Runtime) createPromise(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newPromise, r.global.PromisePrototype, "Promise", 1)
o._putProp("all", r.newNativeFunc(r.promise_all, nil, "all", nil, 1), true, false, true)
o._putProp("allSettled", r.newNativeFunc(r.promise_allSettled, nil, "allSettled", nil, 1), true, false, true)
o._putProp("any", r.newNativeFunc(r.promise_any, nil, "any", nil, 1), true, false, true)
o._putProp("race", r.newNativeFunc(r.promise_race, nil, "race", nil, 1), true, false, true)
o._putProp("reject", r.newNativeFunc(r.promise_reject, nil, "reject", nil, 1), true, false, true)
o._putProp("resolve", r.newNativeFunc(r.promise_resolve, nil, "resolve", nil, 1), true, false, true)
r.putSpeciesReturnThis(o)
return o
}
func (r *Runtime) initPromise() {
r.global.PromisePrototype = r.newLazyObject(r.createPromiseProto)
r.global.Promise = r.newLazyObject(r.createPromise)
r.addToGlobal("Promise", r.global.Promise)
}
func (r *Runtime) wrapPromiseReaction(fObj *Object) func(interface{}) {
f, _ := AssertFunction(fObj)
return func(x interface{}) {
_, _ = f(nil, r.ToValue(x))
}
}
// NewPromise creates and returns a Promise and resolving functions for it.
//
// WARNING: The returned values are not goroutine-safe and must not be called in parallel with VM running.
// In order to make use of this method you need an event loop such as the one in goja_nodejs (https://github.com/dop251/goja_nodejs)
// where it can be used like this:
//
// loop := NewEventLoop()
// loop.Start()
// defer loop.Stop()
// loop.RunOnLoop(func(vm *goja.Runtime) {
// p, resolve, _ := vm.NewPromise()
// vm.Set("p", p)
// go func() {
// time.Sleep(500 * time.Millisecond) // or perform any other blocking operation
// loop.RunOnLoop(func(*goja.Runtime) { // resolve() must be called on the loop, cannot call it here
// resolve(result)
// })
// }()
// }
func (r *Runtime) NewPromise() (promise *Promise, resolve func(result interface{}), reject func(reason interface{})) {
p := r.newPromise(r.global.PromisePrototype)
resolveF, rejectF := p.createResolvingFunctions()
return p, r.wrapPromiseReaction(resolveF), r.wrapPromiseReaction(rejectF)
}
// SetPromiseRejectionTracker registers a function that will be called in two scenarios: when a promise is rejected
// without any handlers (with operation argument set to PromiseRejectionReject), and when a handler is added to a
// rejected promise for the first time (with operation argument set to PromiseRejectionHandle).
//
// Setting a tracker replaces any existing one. Setting it to nil disables the functionality.
//
// See https://tc39.es/ecma262/#sec-host-promise-rejection-tracker for more details.
func (r *Runtime) SetPromiseRejectionTracker(tracker PromiseRejectionTracker) {
r.promiseRejectionTracker = tracker
}
// SetAsyncContextTracker registers a handler that allows to track async execution contexts. See AsyncContextTracker
// documentation for more details. Setting it to nil disables the functionality.
// This method (as Runtime in general) is not goroutine-safe.
func (r *Runtime) SetAsyncContextTracker(tracker AsyncContextTracker) {
r.asyncContextTracker = tracker
}

391
server/vendor/github.com/dop251/goja/builtin_proxy.go generated vendored Normal file
View File

@@ -0,0 +1,391 @@
package goja
import (
"github.com/dop251/goja/unistring"
)
type nativeProxyHandler struct {
handler *ProxyTrapConfig
}
func (h *nativeProxyHandler) getPrototypeOf(target *Object) (Value, bool) {
if trap := h.handler.GetPrototypeOf; trap != nil {
return trap(target), true
}
return nil, false
}
func (h *nativeProxyHandler) setPrototypeOf(target *Object, proto *Object) (bool, bool) {
if trap := h.handler.SetPrototypeOf; trap != nil {
return trap(target, proto), true
}
return false, false
}
func (h *nativeProxyHandler) isExtensible(target *Object) (bool, bool) {
if trap := h.handler.IsExtensible; trap != nil {
return trap(target), true
}
return false, false
}
func (h *nativeProxyHandler) preventExtensions(target *Object) (bool, bool) {
if trap := h.handler.PreventExtensions; trap != nil {
return trap(target), true
}
return false, false
}
func (h *nativeProxyHandler) getOwnPropertyDescriptorStr(target *Object, prop unistring.String) (Value, bool) {
if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil {
if idx, ok := strToInt(prop); ok {
desc := trap(target, idx)
return desc.toValue(target.runtime), true
}
}
if trap := h.handler.GetOwnPropertyDescriptor; trap != nil {
desc := trap(target, prop.String())
return desc.toValue(target.runtime), true
}
return nil, false
}
func (h *nativeProxyHandler) getOwnPropertyDescriptorIdx(target *Object, prop valueInt) (Value, bool) {
if trap := h.handler.GetOwnPropertyDescriptorIdx; trap != nil {
desc := trap(target, toIntStrict(int64(prop)))
return desc.toValue(target.runtime), true
}
if trap := h.handler.GetOwnPropertyDescriptor; trap != nil {
desc := trap(target, prop.String())
return desc.toValue(target.runtime), true
}
return nil, false
}
func (h *nativeProxyHandler) getOwnPropertyDescriptorSym(target *Object, prop *Symbol) (Value, bool) {
if trap := h.handler.GetOwnPropertyDescriptorSym; trap != nil {
desc := trap(target, prop)
return desc.toValue(target.runtime), true
}
return nil, false
}
func (h *nativeProxyHandler) definePropertyStr(target *Object, prop unistring.String, desc PropertyDescriptor) (bool, bool) {
if trap := h.handler.DefinePropertyIdx; trap != nil {
if idx, ok := strToInt(prop); ok {
return trap(target, idx, desc), true
}
}
if trap := h.handler.DefineProperty; trap != nil {
return trap(target, prop.String(), desc), true
}
return false, false
}
func (h *nativeProxyHandler) definePropertyIdx(target *Object, prop valueInt, desc PropertyDescriptor) (bool, bool) {
if trap := h.handler.DefinePropertyIdx; trap != nil {
return trap(target, toIntStrict(int64(prop)), desc), true
}
if trap := h.handler.DefineProperty; trap != nil {
return trap(target, prop.String(), desc), true
}
return false, false
}
func (h *nativeProxyHandler) definePropertySym(target *Object, prop *Symbol, desc PropertyDescriptor) (bool, bool) {
if trap := h.handler.DefinePropertySym; trap != nil {
return trap(target, prop, desc), true
}
return false, false
}
func (h *nativeProxyHandler) hasStr(target *Object, prop unistring.String) (bool, bool) {
if trap := h.handler.HasIdx; trap != nil {
if idx, ok := strToInt(prop); ok {
return trap(target, idx), true
}
}
if trap := h.handler.Has; trap != nil {
return trap(target, prop.String()), true
}
return false, false
}
func (h *nativeProxyHandler) hasIdx(target *Object, prop valueInt) (bool, bool) {
if trap := h.handler.HasIdx; trap != nil {
return trap(target, toIntStrict(int64(prop))), true
}
if trap := h.handler.Has; trap != nil {
return trap(target, prop.String()), true
}
return false, false
}
func (h *nativeProxyHandler) hasSym(target *Object, prop *Symbol) (bool, bool) {
if trap := h.handler.HasSym; trap != nil {
return trap(target, prop), true
}
return false, false
}
func (h *nativeProxyHandler) getStr(target *Object, prop unistring.String, receiver Value) (Value, bool) {
if trap := h.handler.GetIdx; trap != nil {
if idx, ok := strToInt(prop); ok {
return trap(target, idx, receiver), true
}
}
if trap := h.handler.Get; trap != nil {
return trap(target, prop.String(), receiver), true
}
return nil, false
}
func (h *nativeProxyHandler) getIdx(target *Object, prop valueInt, receiver Value) (Value, bool) {
if trap := h.handler.GetIdx; trap != nil {
return trap(target, toIntStrict(int64(prop)), receiver), true
}
if trap := h.handler.Get; trap != nil {
return trap(target, prop.String(), receiver), true
}
return nil, false
}
func (h *nativeProxyHandler) getSym(target *Object, prop *Symbol, receiver Value) (Value, bool) {
if trap := h.handler.GetSym; trap != nil {
return trap(target, prop, receiver), true
}
return nil, false
}
func (h *nativeProxyHandler) setStr(target *Object, prop unistring.String, value Value, receiver Value) (bool, bool) {
if trap := h.handler.SetIdx; trap != nil {
if idx, ok := strToInt(prop); ok {
return trap(target, idx, value, receiver), true
}
}
if trap := h.handler.Set; trap != nil {
return trap(target, prop.String(), value, receiver), true
}
return false, false
}
func (h *nativeProxyHandler) setIdx(target *Object, prop valueInt, value Value, receiver Value) (bool, bool) {
if trap := h.handler.SetIdx; trap != nil {
return trap(target, toIntStrict(int64(prop)), value, receiver), true
}
if trap := h.handler.Set; trap != nil {
return trap(target, prop.String(), value, receiver), true
}
return false, false
}
func (h *nativeProxyHandler) setSym(target *Object, prop *Symbol, value Value, receiver Value) (bool, bool) {
if trap := h.handler.SetSym; trap != nil {
return trap(target, prop, value, receiver), true
}
return false, false
}
func (h *nativeProxyHandler) deleteStr(target *Object, prop unistring.String) (bool, bool) {
if trap := h.handler.DeletePropertyIdx; trap != nil {
if idx, ok := strToInt(prop); ok {
return trap(target, idx), true
}
}
if trap := h.handler.DeleteProperty; trap != nil {
return trap(target, prop.String()), true
}
return false, false
}
func (h *nativeProxyHandler) deleteIdx(target *Object, prop valueInt) (bool, bool) {
if trap := h.handler.DeletePropertyIdx; trap != nil {
return trap(target, toIntStrict(int64(prop))), true
}
if trap := h.handler.DeleteProperty; trap != nil {
return trap(target, prop.String()), true
}
return false, false
}
func (h *nativeProxyHandler) deleteSym(target *Object, prop *Symbol) (bool, bool) {
if trap := h.handler.DeletePropertySym; trap != nil {
return trap(target, prop), true
}
return false, false
}
func (h *nativeProxyHandler) ownKeys(target *Object) (*Object, bool) {
if trap := h.handler.OwnKeys; trap != nil {
return trap(target), true
}
return nil, false
}
func (h *nativeProxyHandler) apply(target *Object, this Value, args []Value) (Value, bool) {
if trap := h.handler.Apply; trap != nil {
return trap(target, this, args), true
}
return nil, false
}
func (h *nativeProxyHandler) construct(target *Object, args []Value, newTarget *Object) (Value, bool) {
if trap := h.handler.Construct; trap != nil {
return trap(target, args, newTarget), true
}
return nil, false
}
func (h *nativeProxyHandler) toObject(runtime *Runtime) *Object {
return runtime.ToValue(h.handler).ToObject(runtime)
}
func (r *Runtime) newNativeProxyHandler(nativeHandler *ProxyTrapConfig) proxyHandler {
return &nativeProxyHandler{handler: nativeHandler}
}
// ProxyTrapConfig provides a simplified Go-friendly API for implementing Proxy traps.
// If an *Idx trap is defined it gets called for integer property keys, including negative ones. Note that
// this only includes string property keys that represent a canonical integer
// (i.e. "0", "123", but not "00", "01", " 1" or "-0").
// For efficiency strings representing integers exceeding 2^53 are not checked to see if they are canonical,
// i.e. the *Idx traps will receive "9007199254740993" as well as "9007199254740994", even though the former is not
// a canonical representation in ECMAScript (Number("9007199254740993") === 9007199254740992).
// See https://262.ecma-international.org/#sec-canonicalnumericindexstring
// If an *Idx trap is not set, the corresponding string one is used.
type ProxyTrapConfig struct {
// A trap for Object.getPrototypeOf, Reflect.getPrototypeOf, __proto__, Object.prototype.isPrototypeOf, instanceof
GetPrototypeOf func(target *Object) (prototype *Object)
// A trap for Object.setPrototypeOf, Reflect.setPrototypeOf
SetPrototypeOf func(target *Object, prototype *Object) (success bool)
// A trap for Object.isExtensible, Reflect.isExtensible
IsExtensible func(target *Object) (success bool)
// A trap for Object.preventExtensions, Reflect.preventExtensions
PreventExtensions func(target *Object) (success bool)
// A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (string properties)
GetOwnPropertyDescriptor func(target *Object, prop string) (propertyDescriptor PropertyDescriptor)
// A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (integer properties)
GetOwnPropertyDescriptorIdx func(target *Object, prop int) (propertyDescriptor PropertyDescriptor)
// A trap for Object.getOwnPropertyDescriptor, Reflect.getOwnPropertyDescriptor (Symbol properties)
GetOwnPropertyDescriptorSym func(target *Object, prop *Symbol) (propertyDescriptor PropertyDescriptor)
// A trap for Object.defineProperty, Reflect.defineProperty (string properties)
DefineProperty func(target *Object, key string, propertyDescriptor PropertyDescriptor) (success bool)
// A trap for Object.defineProperty, Reflect.defineProperty (integer properties)
DefinePropertyIdx func(target *Object, key int, propertyDescriptor PropertyDescriptor) (success bool)
// A trap for Object.defineProperty, Reflect.defineProperty (Symbol properties)
DefinePropertySym func(target *Object, key *Symbol, propertyDescriptor PropertyDescriptor) (success bool)
// A trap for the in operator, with operator, Reflect.has (string properties)
Has func(target *Object, property string) (available bool)
// A trap for the in operator, with operator, Reflect.has (integer properties)
HasIdx func(target *Object, property int) (available bool)
// A trap for the in operator, with operator, Reflect.has (Symbol properties)
HasSym func(target *Object, property *Symbol) (available bool)
// A trap for getting property values, Reflect.get (string properties)
Get func(target *Object, property string, receiver Value) (value Value)
// A trap for getting property values, Reflect.get (integer properties)
GetIdx func(target *Object, property int, receiver Value) (value Value)
// A trap for getting property values, Reflect.get (Symbol properties)
GetSym func(target *Object, property *Symbol, receiver Value) (value Value)
// A trap for setting property values, Reflect.set (string properties)
Set func(target *Object, property string, value Value, receiver Value) (success bool)
// A trap for setting property values, Reflect.set (integer properties)
SetIdx func(target *Object, property int, value Value, receiver Value) (success bool)
// A trap for setting property values, Reflect.set (Symbol properties)
SetSym func(target *Object, property *Symbol, value Value, receiver Value) (success bool)
// A trap for the delete operator, Reflect.deleteProperty (string properties)
DeleteProperty func(target *Object, property string) (success bool)
// A trap for the delete operator, Reflect.deleteProperty (integer properties)
DeletePropertyIdx func(target *Object, property int) (success bool)
// A trap for the delete operator, Reflect.deleteProperty (Symbol properties)
DeletePropertySym func(target *Object, property *Symbol) (success bool)
// A trap for Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.keys, Reflect.ownKeys
OwnKeys func(target *Object) (object *Object)
// A trap for a function call, Function.prototype.apply, Function.prototype.call, Reflect.apply
Apply func(target *Object, this Value, argumentsList []Value) (value Value)
// A trap for the new operator, Reflect.construct
Construct func(target *Object, argumentsList []Value, newTarget *Object) (value *Object)
}
func (r *Runtime) newProxy(args []Value, proto *Object) *Object {
if len(args) >= 2 {
if target, ok := args[0].(*Object); ok {
if proxyHandler, ok := args[1].(*Object); ok {
return r.newProxyObject(target, proxyHandler, proto).val
}
}
}
panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler"))
}
func (r *Runtime) builtin_newProxy(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("Proxy"))
}
return r.newProxy(args, r.getPrototypeFromCtor(newTarget, r.global.Proxy, r.global.ObjectPrototype))
}
func (r *Runtime) NewProxy(target *Object, nativeHandler *ProxyTrapConfig) Proxy {
if p, ok := target.self.(*proxyObject); ok {
if p.handler == nil {
panic(r.NewTypeError("Cannot create proxy with a revoked proxy as target"))
}
}
handler := r.newNativeProxyHandler(nativeHandler)
proxy := r._newProxyObject(target, handler, nil)
return Proxy{proxy: proxy}
}
func (r *Runtime) builtin_proxy_revocable(call FunctionCall) Value {
if len(call.Arguments) >= 2 {
if target, ok := call.Argument(0).(*Object); ok {
if proxyHandler, ok := call.Argument(1).(*Object); ok {
proxy := r.newProxyObject(target, proxyHandler, nil)
revoke := r.newNativeFunc(func(FunctionCall) Value {
proxy.revoke()
return _undefined
}, nil, "", nil, 0)
ret := r.NewObject()
ret.self._putProp("proxy", proxy.val, true, true, true)
ret.self._putProp("revoke", revoke, true, true, true)
return ret
}
}
}
panic(r.NewTypeError("Cannot create proxy with a non-object as target or handler"))
}
func (r *Runtime) createProxy(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newProxy, nil, "Proxy", 2)
o._putProp("revocable", r.newNativeFunc(r.builtin_proxy_revocable, nil, "revocable", nil, 2), true, false, true)
return o
}
func (r *Runtime) initProxy() {
r.global.Proxy = r.newLazyObject(r.createProxy)
r.addToGlobal("Proxy", r.global.Proxy)
}

134
server/vendor/github.com/dop251/goja/builtin_reflect.go generated vendored Normal file
View File

@@ -0,0 +1,134 @@
package goja
func (r *Runtime) builtin_reflect_apply(call FunctionCall) Value {
return r.toCallable(call.Argument(0))(FunctionCall{
This: call.Argument(1),
Arguments: r.createListFromArrayLike(call.Argument(2))})
}
func (r *Runtime) toConstructor(v Value) func(args []Value, newTarget *Object) *Object {
if ctor := r.toObject(v).self.assertConstructor(); ctor != nil {
return ctor
}
panic(r.NewTypeError("Value is not a constructor"))
}
func (r *Runtime) builtin_reflect_construct(call FunctionCall) Value {
target := call.Argument(0)
ctor := r.toConstructor(target)
var newTarget Value
if len(call.Arguments) > 2 {
newTarget = call.Argument(2)
r.toConstructor(newTarget)
} else {
newTarget = target
}
return ctor(r.createListFromArrayLike(call.Argument(1)), r.toObject(newTarget))
}
func (r *Runtime) builtin_reflect_defineProperty(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
key := toPropertyKey(call.Argument(1))
desc := r.toPropertyDescriptor(call.Argument(2))
return r.toBoolean(target.defineOwnProperty(key, desc, false))
}
func (r *Runtime) builtin_reflect_deleteProperty(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
key := toPropertyKey(call.Argument(1))
return r.toBoolean(target.delete(key, false))
}
func (r *Runtime) builtin_reflect_get(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
key := toPropertyKey(call.Argument(1))
var receiver Value
if len(call.Arguments) > 2 {
receiver = call.Arguments[2]
}
return target.get(key, receiver)
}
func (r *Runtime) builtin_reflect_getOwnPropertyDescriptor(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
key := toPropertyKey(call.Argument(1))
return r.valuePropToDescriptorObject(target.getOwnProp(key))
}
func (r *Runtime) builtin_reflect_getPrototypeOf(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
if proto := target.self.proto(); proto != nil {
return proto
}
return _null
}
func (r *Runtime) builtin_reflect_has(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
key := toPropertyKey(call.Argument(1))
return r.toBoolean(target.hasProperty(key))
}
func (r *Runtime) builtin_reflect_isExtensible(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
return r.toBoolean(target.self.isExtensible())
}
func (r *Runtime) builtin_reflect_ownKeys(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
return r.newArrayValues(target.self.keys(true, nil))
}
func (r *Runtime) builtin_reflect_preventExtensions(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
return r.toBoolean(target.self.preventExtensions(false))
}
func (r *Runtime) builtin_reflect_set(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
var receiver Value
if len(call.Arguments) >= 4 {
receiver = call.Argument(3)
} else {
receiver = target
}
return r.toBoolean(target.set(call.Argument(1), call.Argument(2), receiver, false))
}
func (r *Runtime) builtin_reflect_setPrototypeOf(call FunctionCall) Value {
target := r.toObject(call.Argument(0))
var proto *Object
if arg := call.Argument(1); arg != _null {
proto = r.toObject(arg)
}
return r.toBoolean(target.self.setProto(proto, false))
}
func (r *Runtime) createReflect(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("apply", r.newNativeFunc(r.builtin_reflect_apply, nil, "apply", nil, 3), true, false, true)
o._putProp("construct", r.newNativeFunc(r.builtin_reflect_construct, nil, "construct", nil, 2), true, false, true)
o._putProp("defineProperty", r.newNativeFunc(r.builtin_reflect_defineProperty, nil, "defineProperty", nil, 3), true, false, true)
o._putProp("deleteProperty", r.newNativeFunc(r.builtin_reflect_deleteProperty, nil, "deleteProperty", nil, 2), true, false, true)
o._putProp("get", r.newNativeFunc(r.builtin_reflect_get, nil, "get", nil, 2), true, false, true)
o._putProp("getOwnPropertyDescriptor", r.newNativeFunc(r.builtin_reflect_getOwnPropertyDescriptor, nil, "getOwnPropertyDescriptor", nil, 2), true, false, true)
o._putProp("getPrototypeOf", r.newNativeFunc(r.builtin_reflect_getPrototypeOf, nil, "getPrototypeOf", nil, 1), true, false, true)
o._putProp("has", r.newNativeFunc(r.builtin_reflect_has, nil, "has", nil, 2), true, false, true)
o._putProp("isExtensible", r.newNativeFunc(r.builtin_reflect_isExtensible, nil, "isExtensible", nil, 1), true, false, true)
o._putProp("ownKeys", r.newNativeFunc(r.builtin_reflect_ownKeys, nil, "ownKeys", nil, 1), true, false, true)
o._putProp("preventExtensions", r.newNativeFunc(r.builtin_reflect_preventExtensions, nil, "preventExtensions", nil, 1), true, false, true)
o._putProp("set", r.newNativeFunc(r.builtin_reflect_set, nil, "set", nil, 3), true, false, true)
o._putProp("setPrototypeOf", r.newNativeFunc(r.builtin_reflect_setPrototypeOf, nil, "setPrototypeOf", nil, 2), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString("Reflect"), false, false, true))
return o
}
func (r *Runtime) initReflect() {
r.addToGlobal("Reflect", r.newLazyObject(r.createReflect))
}

1289
server/vendor/github.com/dop251/goja/builtin_regexp.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

333
server/vendor/github.com/dop251/goja/builtin_set.go generated vendored Normal file
View File

@@ -0,0 +1,333 @@
package goja
import (
"fmt"
"reflect"
)
var setExportType = reflectTypeArray
type setObject struct {
baseObject
m *orderedMap
}
type setIterObject struct {
baseObject
iter *orderedMapIter
kind iterationKind
}
func (o *setIterObject) next() Value {
if o.iter == nil {
return o.val.runtime.createIterResultObject(_undefined, true)
}
entry := o.iter.next()
if entry == nil {
o.iter = nil
return o.val.runtime.createIterResultObject(_undefined, true)
}
var result Value
switch o.kind {
case iterationKindValue:
result = entry.key
default:
result = o.val.runtime.newArrayValues([]Value{entry.key, entry.key})
}
return o.val.runtime.createIterResultObject(result, false)
}
func (so *setObject) init() {
so.baseObject.init()
so.m = newOrderedMap(so.val.runtime.getHash())
}
func (so *setObject) exportType() reflect.Type {
return setExportType
}
func (so *setObject) export(ctx *objectExportCtx) interface{} {
a := make([]interface{}, so.m.size)
ctx.put(so.val, a)
iter := so.m.newIter()
for i := 0; i < len(a); i++ {
entry := iter.next()
if entry == nil {
break
}
a[i] = exportValue(entry.key, ctx)
}
return a
}
func (so *setObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
l := so.m.size
if typ.Kind() == reflect.Array {
if dst.Len() != l {
return fmt.Errorf("cannot convert a Set into an array, lengths mismatch: have %d, need %d)", l, dst.Len())
}
} else {
dst.Set(reflect.MakeSlice(typ, l, l))
}
ctx.putTyped(so.val, typ, dst.Interface())
iter := so.m.newIter()
r := so.val.runtime
for i := 0; i < l; i++ {
entry := iter.next()
if entry == nil {
break
}
err := r.toReflectValue(entry.key, dst.Index(i), ctx)
if err != nil {
return err
}
}
return nil
}
func (so *setObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
dst.Set(reflect.MakeMap(typ))
keyTyp := typ.Key()
elemTyp := typ.Elem()
iter := so.m.newIter()
r := so.val.runtime
for {
entry := iter.next()
if entry == nil {
break
}
keyVal := reflect.New(keyTyp).Elem()
err := r.toReflectValue(entry.key, keyVal, ctx)
if err != nil {
return err
}
dst.SetMapIndex(keyVal, reflect.Zero(elemTyp))
}
return nil
}
func (r *Runtime) setProto_add(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.add called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
so.m.set(call.Argument(0), nil)
return call.This
}
func (r *Runtime) setProto_clear(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.clear called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
so.m.clear()
return _undefined
}
func (r *Runtime) setProto_delete(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return r.toBoolean(so.m.remove(call.Argument(0)))
}
func (r *Runtime) setProto_entries(call FunctionCall) Value {
return r.createSetIterator(call.This, iterationKindKeyValue)
}
func (r *Runtime) setProto_forEach(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.forEach called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
callbackFn, ok := r.toObject(call.Argument(0)).self.assertCallable()
if !ok {
panic(r.NewTypeError("object is not a function %s"))
}
t := call.Argument(1)
iter := so.m.newIter()
for {
entry := iter.next()
if entry == nil {
break
}
callbackFn(FunctionCall{This: t, Arguments: []Value{entry.key, entry.key, thisObj}})
}
return _undefined
}
func (r *Runtime) setProto_has(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method Set.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return r.toBoolean(so.m.has(call.Argument(0)))
}
func (r *Runtime) setProto_getSize(call FunctionCall) Value {
thisObj := r.toObject(call.This)
so, ok := thisObj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Method get Set.prototype.size called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
return intToValue(int64(so.m.size))
}
func (r *Runtime) setProto_values(call FunctionCall) Value {
return r.createSetIterator(call.This, iterationKindValue)
}
func (r *Runtime) builtin_newSet(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("Set"))
}
proto := r.getPrototypeFromCtor(newTarget, r.global.Set, r.global.SetPrototype)
o := &Object{runtime: r}
so := &setObject{}
so.class = classObject
so.val = o
so.extensible = true
o.self = so
so.prototype = proto
so.init()
if len(args) > 0 {
if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
adder := so.getStr("add", nil)
stdArr := r.checkStdArrayIter(arg)
if adder == r.global.setAdder {
if stdArr != nil {
for _, v := range stdArr.values {
so.m.set(v, nil)
}
} else {
r.getIterator(arg, nil).iterate(func(item Value) {
so.m.set(item, nil)
})
}
} else {
adderFn := toMethod(adder)
if adderFn == nil {
panic(r.NewTypeError("Set.add in missing"))
}
if stdArr != nil {
for _, item := range stdArr.values {
adderFn(FunctionCall{This: o, Arguments: []Value{item}})
}
} else {
r.getIterator(arg, nil).iterate(func(item Value) {
adderFn(FunctionCall{This: o, Arguments: []Value{item}})
})
}
}
}
}
return o
}
func (r *Runtime) createSetIterator(setValue Value, kind iterationKind) Value {
obj := r.toObject(setValue)
setObj, ok := obj.self.(*setObject)
if !ok {
panic(r.NewTypeError("Object is not a Set"))
}
o := &Object{runtime: r}
si := &setIterObject{
iter: setObj.m.newIter(),
kind: kind,
}
si.class = classObject
si.val = o
si.extensible = true
o.self = si
si.prototype = r.getSetIteratorPrototype()
si.init()
return o
}
func (r *Runtime) setIterProto_next(call FunctionCall) Value {
thisObj := r.toObject(call.This)
if iter, ok := thisObj.self.(*setIterObject); ok {
return iter.next()
}
panic(r.NewTypeError("Method Set Iterator.prototype.next called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
func (r *Runtime) createSetProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("constructor", r.global.Set, true, false, true)
r.global.setAdder = r.newNativeFunc(r.setProto_add, nil, "add", nil, 1)
o._putProp("add", r.global.setAdder, true, false, true)
o._putProp("clear", r.newNativeFunc(r.setProto_clear, nil, "clear", nil, 0), true, false, true)
o._putProp("delete", r.newNativeFunc(r.setProto_delete, nil, "delete", nil, 1), true, false, true)
o._putProp("forEach", r.newNativeFunc(r.setProto_forEach, nil, "forEach", nil, 1), true, false, true)
o._putProp("has", r.newNativeFunc(r.setProto_has, nil, "has", nil, 1), true, false, true)
o.setOwnStr("size", &valueProperty{
getterFunc: r.newNativeFunc(r.setProto_getSize, nil, "get size", nil, 0),
accessor: true,
writable: true,
configurable: true,
}, true)
valuesFunc := r.newNativeFunc(r.setProto_values, nil, "values", nil, 0)
o._putProp("values", valuesFunc, true, false, true)
o._putProp("keys", valuesFunc, true, false, true)
o._putProp("entries", r.newNativeFunc(r.setProto_entries, nil, "entries", nil, 0), true, false, true)
o._putSym(SymIterator, valueProp(valuesFunc, true, false, true))
o._putSym(SymToStringTag, valueProp(asciiString(classSet), false, false, true))
return o
}
func (r *Runtime) createSet(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newSet, r.global.SetPrototype, "Set", 0)
r.putSpeciesReturnThis(o)
return o
}
func (r *Runtime) createSetIterProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.getIteratorPrototype(), classObject)
o._putProp("next", r.newNativeFunc(r.setIterProto_next, nil, "next", nil, 0), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classSetIterator), false, false, true))
return o
}
func (r *Runtime) getSetIteratorPrototype() *Object {
var o *Object
if o = r.global.SetIteratorPrototype; o == nil {
o = &Object{runtime: r}
r.global.SetIteratorPrototype = o
o.self = r.createSetIterProto(o)
}
return o
}
func (r *Runtime) initSet() {
r.global.SetPrototype = r.newLazyObject(r.createSetProto)
r.global.Set = r.newLazyObject(r.createSet)
r.addToGlobal("Set", r.global.Set)
}

1004
server/vendor/github.com/dop251/goja/builtin_string.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

165
server/vendor/github.com/dop251/goja/builtin_symbol.go generated vendored Normal file
View File

@@ -0,0 +1,165 @@
package goja
import "github.com/dop251/goja/unistring"
var (
SymHasInstance = newSymbol(asciiString("Symbol.hasInstance"))
SymIsConcatSpreadable = newSymbol(asciiString("Symbol.isConcatSpreadable"))
SymIterator = newSymbol(asciiString("Symbol.iterator"))
SymMatch = newSymbol(asciiString("Symbol.match"))
SymMatchAll = newSymbol(asciiString("Symbol.matchAll"))
SymReplace = newSymbol(asciiString("Symbol.replace"))
SymSearch = newSymbol(asciiString("Symbol.search"))
SymSpecies = newSymbol(asciiString("Symbol.species"))
SymSplit = newSymbol(asciiString("Symbol.split"))
SymToPrimitive = newSymbol(asciiString("Symbol.toPrimitive"))
SymToStringTag = newSymbol(asciiString("Symbol.toStringTag"))
SymUnscopables = newSymbol(asciiString("Symbol.unscopables"))
)
func (r *Runtime) builtin_symbol(call FunctionCall) Value {
var desc valueString
if arg := call.Argument(0); !IsUndefined(arg) {
desc = arg.toString()
}
return newSymbol(desc)
}
func (r *Runtime) symbolproto_tostring(call FunctionCall) Value {
sym, ok := call.This.(*Symbol)
if !ok {
if obj, ok := call.This.(*Object); ok {
if v, ok := obj.self.(*primitiveValueObject); ok {
if sym1, ok := v.pValue.(*Symbol); ok {
sym = sym1
}
}
}
}
if sym == nil {
panic(r.NewTypeError("Method Symbol.prototype.toString is called on incompatible receiver"))
}
return sym.descriptiveString()
}
func (r *Runtime) symbolproto_valueOf(call FunctionCall) Value {
_, ok := call.This.(*Symbol)
if ok {
return call.This
}
if obj, ok := call.This.(*Object); ok {
if v, ok := obj.self.(*primitiveValueObject); ok {
if sym, ok := v.pValue.(*Symbol); ok {
return sym
}
}
}
panic(r.NewTypeError("Symbol.prototype.valueOf requires that 'this' be a Symbol"))
}
func (r *Runtime) symbol_for(call FunctionCall) Value {
key := call.Argument(0).toString()
keyStr := key.string()
if v := r.symbolRegistry[keyStr]; v != nil {
return v
}
if r.symbolRegistry == nil {
r.symbolRegistry = make(map[unistring.String]*Symbol)
}
v := newSymbol(key)
r.symbolRegistry[keyStr] = v
return v
}
func (r *Runtime) symbol_keyfor(call FunctionCall) Value {
arg := call.Argument(0)
sym, ok := arg.(*Symbol)
if !ok {
panic(r.NewTypeError("%s is not a symbol", arg.String()))
}
for key, s := range r.symbolRegistry {
if s == sym {
return stringValueFromRaw(key)
}
}
return _undefined
}
func (r *Runtime) thisSymbolValue(v Value) *Symbol {
if sym, ok := v.(*Symbol); ok {
return sym
}
if obj, ok := v.(*Object); ok {
if pVal, ok := obj.self.(*primitiveValueObject); ok {
if sym, ok := pVal.pValue.(*Symbol); ok {
return sym
}
}
}
panic(r.NewTypeError("Value is not a Symbol"))
}
func (r *Runtime) createSymbolProto(val *Object) objectImpl {
o := &baseObject{
class: classObject,
val: val,
extensible: true,
prototype: r.global.ObjectPrototype,
}
o.init()
o._putProp("constructor", r.global.Symbol, true, false, true)
o.setOwnStr("description", &valueProperty{
configurable: true,
getterFunc: r.newNativeFunc(func(call FunctionCall) Value {
return r.thisSymbolValue(call.This).desc
}, nil, "get description", nil, 0),
accessor: true,
}, false)
o._putProp("toString", r.newNativeFunc(r.symbolproto_tostring, nil, "toString", nil, 0), true, false, true)
o._putProp("valueOf", r.newNativeFunc(r.symbolproto_valueOf, nil, "valueOf", nil, 0), true, false, true)
o._putSym(SymToPrimitive, valueProp(r.newNativeFunc(r.symbolproto_valueOf, nil, "[Symbol.toPrimitive]", nil, 1), false, false, true))
o._putSym(SymToStringTag, valueProp(newStringValue("Symbol"), false, false, true))
return o
}
func (r *Runtime) createSymbol(val *Object) objectImpl {
o := r.newNativeFuncObj(val, r.builtin_symbol, func(args []Value, proto *Object) *Object {
panic(r.NewTypeError("Symbol is not a constructor"))
}, "Symbol", r.global.SymbolPrototype, _positiveZero)
o._putProp("for", r.newNativeFunc(r.symbol_for, nil, "for", nil, 1), true, false, true)
o._putProp("keyFor", r.newNativeFunc(r.symbol_keyfor, nil, "keyFor", nil, 1), true, false, true)
for _, s := range []*Symbol{
SymHasInstance,
SymIsConcatSpreadable,
SymIterator,
SymMatch,
SymMatchAll,
SymReplace,
SymSearch,
SymSpecies,
SymSplit,
SymToPrimitive,
SymToStringTag,
SymUnscopables,
} {
n := s.desc.(asciiString)
n = n[len("Symbol."):]
o._putProp(unistring.String(n), s, false, false, false)
}
return o
}
func (r *Runtime) initSymbol() {
r.global.SymbolPrototype = r.newLazyObject(r.createSymbolProto)
r.global.Symbol = r.newLazyObject(r.createSymbol)
r.addToGlobal("Symbol", r.global.Symbol)
}

File diff suppressed because it is too large Load Diff

174
server/vendor/github.com/dop251/goja/builtin_weakmap.go generated vendored Normal file
View File

@@ -0,0 +1,174 @@
package goja
type weakMap uint64
type weakMapObject struct {
baseObject
m weakMap
}
func (wmo *weakMapObject) init() {
wmo.baseObject.init()
wmo.m = weakMap(wmo.val.runtime.genId())
}
func (wm weakMap) set(key *Object, value Value) {
key.getWeakRefs()[wm] = value
}
func (wm weakMap) get(key *Object) Value {
return key.weakRefs[wm]
}
func (wm weakMap) remove(key *Object) bool {
if _, exists := key.weakRefs[wm]; exists {
delete(key.weakRefs, wm)
return true
}
return false
}
func (wm weakMap) has(key *Object) bool {
_, exists := key.weakRefs[wm]
return exists
}
func (r *Runtime) weakMapProto_delete(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wmo, ok := thisObj.self.(*weakMapObject)
if !ok {
panic(r.NewTypeError("Method WeakMap.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
key, ok := call.Argument(0).(*Object)
if ok && wmo.m.remove(key) {
return valueTrue
}
return valueFalse
}
func (r *Runtime) weakMapProto_get(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wmo, ok := thisObj.self.(*weakMapObject)
if !ok {
panic(r.NewTypeError("Method WeakMap.prototype.get called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
var res Value
if key, ok := call.Argument(0).(*Object); ok {
res = wmo.m.get(key)
}
if res == nil {
return _undefined
}
return res
}
func (r *Runtime) weakMapProto_has(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wmo, ok := thisObj.self.(*weakMapObject)
if !ok {
panic(r.NewTypeError("Method WeakMap.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
key, ok := call.Argument(0).(*Object)
if ok && wmo.m.has(key) {
return valueTrue
}
return valueFalse
}
func (r *Runtime) weakMapProto_set(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wmo, ok := thisObj.self.(*weakMapObject)
if !ok {
panic(r.NewTypeError("Method WeakMap.prototype.set called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
key := r.toObject(call.Argument(0))
wmo.m.set(key, call.Argument(1))
return call.This
}
func (r *Runtime) needNew(name string) *Object {
return r.NewTypeError("Constructor %s requires 'new'", name)
}
func (r *Runtime) getPrototypeFromCtor(newTarget, defCtor, defProto *Object) *Object {
if newTarget == defCtor {
return defProto
}
proto := newTarget.self.getStr("prototype", nil)
if obj, ok := proto.(*Object); ok {
return obj
}
return defProto
}
func (r *Runtime) builtin_newWeakMap(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("WeakMap"))
}
proto := r.getPrototypeFromCtor(newTarget, r.global.WeakMap, r.global.WeakMapPrototype)
o := &Object{runtime: r}
wmo := &weakMapObject{}
wmo.class = classObject
wmo.val = o
wmo.extensible = true
o.self = wmo
wmo.prototype = proto
wmo.init()
if len(args) > 0 {
if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
adder := wmo.getStr("set", nil)
adderFn := toMethod(adder)
if adderFn == nil {
panic(r.NewTypeError("WeakMap.set in missing"))
}
iter := r.getIterator(arg, nil)
i0 := valueInt(0)
i1 := valueInt(1)
if adder == r.global.weakMapAdder {
iter.iterate(func(item Value) {
itemObj := r.toObject(item)
k := itemObj.self.getIdx(i0, nil)
v := nilSafe(itemObj.self.getIdx(i1, nil))
wmo.m.set(r.toObject(k), v)
})
} else {
iter.iterate(func(item Value) {
itemObj := r.toObject(item)
k := itemObj.self.getIdx(i0, nil)
v := itemObj.self.getIdx(i1, nil)
adderFn(FunctionCall{This: o, Arguments: []Value{k, v}})
})
}
}
}
return o
}
func (r *Runtime) createWeakMapProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("constructor", r.global.WeakMap, true, false, true)
r.global.weakMapAdder = r.newNativeFunc(r.weakMapProto_set, nil, "set", nil, 2)
o._putProp("set", r.global.weakMapAdder, true, false, true)
o._putProp("delete", r.newNativeFunc(r.weakMapProto_delete, nil, "delete", nil, 1), true, false, true)
o._putProp("has", r.newNativeFunc(r.weakMapProto_has, nil, "has", nil, 1), true, false, true)
o._putProp("get", r.newNativeFunc(r.weakMapProto_get, nil, "get", nil, 1), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classWeakMap), false, false, true))
return o
}
func (r *Runtime) createWeakMap(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newWeakMap, r.global.WeakMapPrototype, "WeakMap", 0)
return o
}
func (r *Runtime) initWeakMap() {
r.global.WeakMapPrototype = r.newLazyObject(r.createWeakMapProto)
r.global.WeakMap = r.newLazyObject(r.createWeakMap)
r.addToGlobal("WeakMap", r.global.WeakMap)
}

122
server/vendor/github.com/dop251/goja/builtin_weakset.go generated vendored Normal file
View File

@@ -0,0 +1,122 @@
package goja
type weakSetObject struct {
baseObject
s weakMap
}
func (ws *weakSetObject) init() {
ws.baseObject.init()
ws.s = weakMap(ws.val.runtime.genId())
}
func (r *Runtime) weakSetProto_add(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wso, ok := thisObj.self.(*weakSetObject)
if !ok {
panic(r.NewTypeError("Method WeakSet.prototype.add called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
wso.s.set(r.toObject(call.Argument(0)), nil)
return call.This
}
func (r *Runtime) weakSetProto_delete(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wso, ok := thisObj.self.(*weakSetObject)
if !ok {
panic(r.NewTypeError("Method WeakSet.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
obj, ok := call.Argument(0).(*Object)
if ok && wso.s.remove(obj) {
return valueTrue
}
return valueFalse
}
func (r *Runtime) weakSetProto_has(call FunctionCall) Value {
thisObj := r.toObject(call.This)
wso, ok := thisObj.self.(*weakSetObject)
if !ok {
panic(r.NewTypeError("Method WeakSet.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj})))
}
obj, ok := call.Argument(0).(*Object)
if ok && wso.s.has(obj) {
return valueTrue
}
return valueFalse
}
func (r *Runtime) builtin_newWeakSet(args []Value, newTarget *Object) *Object {
if newTarget == nil {
panic(r.needNew("WeakSet"))
}
proto := r.getPrototypeFromCtor(newTarget, r.global.WeakSet, r.global.WeakSetPrototype)
o := &Object{runtime: r}
wso := &weakSetObject{}
wso.class = classObject
wso.val = o
wso.extensible = true
o.self = wso
wso.prototype = proto
wso.init()
if len(args) > 0 {
if arg := args[0]; arg != nil && arg != _undefined && arg != _null {
adder := wso.getStr("add", nil)
stdArr := r.checkStdArrayIter(arg)
if adder == r.global.weakSetAdder {
if stdArr != nil {
for _, v := range stdArr.values {
wso.s.set(r.toObject(v), nil)
}
} else {
r.getIterator(arg, nil).iterate(func(item Value) {
wso.s.set(r.toObject(item), nil)
})
}
} else {
adderFn := toMethod(adder)
if adderFn == nil {
panic(r.NewTypeError("WeakSet.add in missing"))
}
if stdArr != nil {
for _, item := range stdArr.values {
adderFn(FunctionCall{This: o, Arguments: []Value{item}})
}
} else {
r.getIterator(arg, nil).iterate(func(item Value) {
adderFn(FunctionCall{This: o, Arguments: []Value{item}})
})
}
}
}
}
return o
}
func (r *Runtime) createWeakSetProto(val *Object) objectImpl {
o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject)
o._putProp("constructor", r.global.WeakSet, true, false, true)
r.global.weakSetAdder = r.newNativeFunc(r.weakSetProto_add, nil, "add", nil, 1)
o._putProp("add", r.global.weakSetAdder, true, false, true)
o._putProp("delete", r.newNativeFunc(r.weakSetProto_delete, nil, "delete", nil, 1), true, false, true)
o._putProp("has", r.newNativeFunc(r.weakSetProto_has, nil, "has", nil, 1), true, false, true)
o._putSym(SymToStringTag, valueProp(asciiString(classWeakSet), false, false, true))
return o
}
func (r *Runtime) createWeakSet(val *Object) objectImpl {
o := r.newNativeConstructOnly(val, r.builtin_newWeakSet, r.global.WeakSetPrototype, "WeakSet", 0)
return o
}
func (r *Runtime) initWeakSet() {
r.global.WeakSetPrototype = r.newLazyObject(r.createWeakSetProto)
r.global.WeakSet = r.newLazyObject(r.createWeakSet)
r.addToGlobal("WeakSet", r.global.WeakSet)
}

1463
server/vendor/github.com/dop251/goja/compiler.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

3608
server/vendor/github.com/dop251/goja/compiler_expr.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1127
server/vendor/github.com/dop251/goja/compiler_stmt.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

174
server/vendor/github.com/dop251/goja/date.go generated vendored Normal file
View File

@@ -0,0 +1,174 @@
package goja
import (
"math"
"reflect"
"time"
)
const (
dateTimeLayout = "Mon Jan 02 2006 15:04:05 GMT-0700 (MST)"
utcDateTimeLayout = "Mon, 02 Jan 2006 15:04:05 GMT"
isoDateTimeLayout = "2006-01-02T15:04:05.000Z"
dateLayout = "Mon Jan 02 2006"
timeLayout = "15:04:05 GMT-0700 (MST)"
datetimeLayout_en_GB = "01/02/2006, 15:04:05"
dateLayout_en_GB = "01/02/2006"
timeLayout_en_GB = "15:04:05"
maxTime = 8.64e15
timeUnset = math.MinInt64
)
type dateObject struct {
baseObject
msec int64
}
type dateLayoutDesc struct {
layout string
dateOnly bool
}
var (
dateLayoutsNumeric = []dateLayoutDesc{
{layout: "2006-01-02T15:04:05Z0700"},
{layout: "2006-01-02T15:04:05"},
{layout: "2006-01-02", dateOnly: true},
{layout: "2006-01-02 15:04:05"},
{layout: "2006", dateOnly: true},
{layout: "2006-01", dateOnly: true},
{layout: "2006T15:04"},
{layout: "2006-01T15:04"},
{layout: "2006-01-02T15:04"},
{layout: "2006T15:04:05"},
{layout: "2006-01T15:04:05"},
{layout: "2006T15:04Z0700"},
{layout: "2006-01T15:04Z0700"},
{layout: "2006-01-02T15:04Z0700"},
{layout: "2006T15:04:05Z0700"},
{layout: "2006-01T15:04:05Z0700"},
}
dateLayoutsAlpha = []dateLayoutDesc{
{layout: time.RFC1123},
{layout: time.RFC1123Z},
{layout: dateTimeLayout},
{layout: time.UnixDate},
{layout: time.ANSIC},
{layout: time.RubyDate},
{layout: "Mon, _2 Jan 2006 15:04:05 GMT-0700 (MST)"},
{layout: "Mon, _2 Jan 2006 15:04:05 -0700 (MST)"},
{layout: "Jan _2, 2006", dateOnly: true},
}
)
func dateParse(date string) (time.Time, bool) {
var t time.Time
var err error
var layouts []dateLayoutDesc
if len(date) > 0 {
first := date[0]
if first <= '9' && (first >= '0' || first == '-' || first == '+') {
layouts = dateLayoutsNumeric
} else {
layouts = dateLayoutsAlpha
}
} else {
return time.Time{}, false
}
for _, desc := range layouts {
var defLoc *time.Location
if desc.dateOnly {
defLoc = time.UTC
} else {
defLoc = time.Local
}
t, err = parseDate(desc.layout, date, defLoc)
if err == nil {
break
}
}
if err != nil {
return time.Time{}, false
}
unix := timeToMsec(t)
return t, unix >= -maxTime && unix <= maxTime
}
func (r *Runtime) newDateObject(t time.Time, isSet bool, proto *Object) *Object {
v := &Object{runtime: r}
d := &dateObject{}
v.self = d
d.val = v
d.class = classDate
d.prototype = proto
d.extensible = true
d.init()
if isSet {
d.msec = timeToMsec(t)
} else {
d.msec = timeUnset
}
return v
}
func dateFormat(t time.Time) string {
return t.Local().Format(dateTimeLayout)
}
func timeFromMsec(msec int64) time.Time {
sec := msec / 1000
nsec := (msec % 1000) * 1e6
return time.Unix(sec, nsec)
}
func timeToMsec(t time.Time) int64 {
return t.Unix()*1000 + int64(t.Nanosecond())/1e6
}
func (d *dateObject) toPrimitive() Value {
return d.toPrimitiveString()
}
func (d *dateObject) exportType() reflect.Type {
return typeTime
}
func (d *dateObject) export(*objectExportCtx) interface{} {
if d.isSet() {
return d.time()
}
return nil
}
func (d *dateObject) setTimeMs(ms int64) Value {
if ms >= 0 && ms <= maxTime || ms < 0 && ms >= -maxTime {
d.msec = ms
return intToValue(ms)
}
d.unset()
return _NaN
}
func (d *dateObject) isSet() bool {
return d.msec != timeUnset
}
func (d *dateObject) unset() {
d.msec = timeUnset
}
func (d *dateObject) time() time.Time {
return timeFromMsec(d.msec)
}
func (d *dateObject) timeUTC() time.Time {
return timeFromMsec(d.msec).In(time.UTC)
}

865
server/vendor/github.com/dop251/goja/date_parser.go generated vendored Normal file
View File

@@ -0,0 +1,865 @@
package goja
// This is a slightly modified version of the standard Go parser to make it more compatible with ECMAScript 5.1
// Changes:
// - 6-digit extended years are supported in place of long year (2006) in the form of +123456
// - Timezone formats tolerate colons, e.g. -0700 will parse -07:00
// - Short week day will also parse long week day
// - Short month ("Jan") will also parse long month ("January")
// - Long day ("02") will also parse short day ("2").
// - Timezone in brackets, "(MST)", will match any string in brackets (e.g. "(GMT Standard Time)")
// - If offset is not set and timezone name is unknown, an error is returned
// - If offset and timezone name are both set the offset takes precedence and the resulting Location will be FixedZone("", offset)
// Original copyright message:
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import (
"errors"
"time"
)
const (
_ = iota
stdLongMonth = iota + stdNeedDate // "January"
stdMonth // "Jan"
stdNumMonth // "1"
stdZeroMonth // "01"
stdLongWeekDay // "Monday"
stdWeekDay // "Mon"
stdDay // "2"
stdUnderDay // "_2"
stdZeroDay // "02"
stdHour = iota + stdNeedClock // "15"
stdHour12 // "3"
stdZeroHour12 // "03"
stdMinute // "4"
stdZeroMinute // "04"
stdSecond // "5"
stdZeroSecond // "05"
stdLongYear = iota + stdNeedDate // "2006"
stdYear // "06"
stdPM = iota + stdNeedClock // "PM"
stdpm // "pm"
stdTZ = iota // "MST"
stdBracketTZ // "(MST)"
stdISO8601TZ // "Z0700" // prints Z for UTC
stdISO8601SecondsTZ // "Z070000"
stdISO8601ShortTZ // "Z07"
stdISO8601ColonTZ // "Z07:00" // prints Z for UTC
stdISO8601ColonSecondsTZ // "Z07:00:00"
stdNumTZ // "-0700" // always numeric
stdNumSecondsTz // "-070000"
stdNumShortTZ // "-07" // always numeric
stdNumColonTZ // "-07:00" // always numeric
stdNumColonSecondsTZ // "-07:00:00"
stdFracSecond0 // ".0", ".00", ... , trailing zeros included
stdFracSecond9 // ".9", ".99", ..., trailing zeros omitted
stdNeedDate = 1 << 8 // need month, day, year
stdNeedClock = 2 << 8 // need hour, minute, second
stdArgShift = 16 // extra argument in high bits, above low stdArgShift
stdMask = 1<<stdArgShift - 1 // mask out argument
)
var errBad = errors.New("bad value for field") // placeholder not passed to user
func parseDate(layout, value string, defaultLocation *time.Location) (time.Time, error) {
alayout, avalue := layout, value
rangeErrString := "" // set if a value is out of range
amSet := false // do we need to subtract 12 from the hour for midnight?
pmSet := false // do we need to add 12 to the hour?
// Time being constructed.
var (
year int
month int = 1 // January
day int = 1
hour int
min int
sec int
nsec int
z *time.Location
zoneOffset int = -1
zoneName string
)
// Each iteration processes one std value.
for {
var err error
prefix, std, suffix := nextStdChunk(layout)
stdstr := layout[len(prefix) : len(layout)-len(suffix)]
value, err = skip(value, prefix)
if err != nil {
return time.Time{}, &time.ParseError{Layout: alayout, Value: avalue, LayoutElem: prefix, ValueElem: value}
}
if std == 0 {
if len(value) != 0 {
return time.Time{}, &time.ParseError{Layout: alayout, Value: avalue, ValueElem: value, Message: ": extra text: " + value}
}
break
}
layout = suffix
var p string
switch std & stdMask {
case stdYear:
if len(value) < 2 {
err = errBad
break
}
p, value = value[0:2], value[2:]
year, err = atoi(p)
if year >= 69 { // Unix time starts Dec 31 1969 in some time zones
year += 1900
} else {
year += 2000
}
case stdLongYear:
if len(value) >= 7 && (value[0] == '-' || value[0] == '+') { // extended year
neg := value[0] == '-'
p, value = value[1:7], value[7:]
year, err = atoi(p)
if neg {
year = -year
}
} else {
if len(value) < 4 || !isDigit(value, 0) {
err = errBad
break
}
p, value = value[0:4], value[4:]
year, err = atoi(p)
}
case stdMonth:
month, value, err = lookup(longMonthNames, value)
if err != nil {
month, value, err = lookup(shortMonthNames, value)
}
month++
case stdLongMonth:
month, value, err = lookup(longMonthNames, value)
month++
case stdNumMonth, stdZeroMonth:
month, value, err = getnum(value, std == stdZeroMonth)
if month <= 0 || 12 < month {
rangeErrString = "month"
}
case stdWeekDay:
// Ignore weekday except for error checking.
_, value, err = lookup(longDayNames, value)
if err != nil {
_, value, err = lookup(shortDayNames, value)
}
case stdLongWeekDay:
_, value, err = lookup(longDayNames, value)
case stdDay, stdUnderDay, stdZeroDay:
if std == stdUnderDay && len(value) > 0 && value[0] == ' ' {
value = value[1:]
}
day, value, err = getnum(value, false)
if day < 0 {
// Note that we allow any one- or two-digit day here.
rangeErrString = "day"
}
case stdHour:
hour, value, err = getnum(value, false)
if hour < 0 || 24 <= hour {
rangeErrString = "hour"
}
case stdHour12, stdZeroHour12:
hour, value, err = getnum(value, std == stdZeroHour12)
if hour < 0 || 12 < hour {
rangeErrString = "hour"
}
case stdMinute, stdZeroMinute:
min, value, err = getnum(value, std == stdZeroMinute)
if min < 0 || 60 <= min {
rangeErrString = "minute"
}
case stdSecond, stdZeroSecond:
sec, value, err = getnum(value, std == stdZeroSecond)
if sec < 0 || 60 <= sec {
rangeErrString = "second"
break
}
// Special case: do we have a fractional second but no
// fractional second in the format?
if len(value) >= 2 && value[0] == '.' && isDigit(value, 1) {
_, std, _ = nextStdChunk(layout)
std &= stdMask
if std == stdFracSecond0 || std == stdFracSecond9 {
// Fractional second in the layout; proceed normally
break
}
// No fractional second in the layout but we have one in the input.
n := 2
for ; n < len(value) && isDigit(value, n); n++ {
}
nsec, rangeErrString, err = parseNanoseconds(value, n)
value = value[n:]
}
case stdPM:
if len(value) < 2 {
err = errBad
break
}
p, value = value[0:2], value[2:]
switch p {
case "PM":
pmSet = true
case "AM":
amSet = true
default:
err = errBad
}
case stdpm:
if len(value) < 2 {
err = errBad
break
}
p, value = value[0:2], value[2:]
switch p {
case "pm":
pmSet = true
case "am":
amSet = true
default:
err = errBad
}
case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ:
if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ ||
std == stdISO8601SecondsTZ || std == stdISO8601ColonSecondsTZ) && len(value) >= 1 && value[0] == 'Z' {
value = value[1:]
z = time.UTC
break
}
var sign, hour, min, seconds string
if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdNumTZ || std == stdISO8601TZ {
if len(value) < 4 {
err = errBad
break
}
if value[3] != ':' {
if std == stdNumColonTZ || std == stdISO8601ColonTZ || len(value) < 5 {
err = errBad
break
}
sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], "00", value[5:]
} else {
if len(value) < 6 {
err = errBad
break
}
sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], "00", value[6:]
}
} else if std == stdNumShortTZ || std == stdISO8601ShortTZ {
if len(value) < 3 {
err = errBad
break
}
sign, hour, min, seconds, value = value[0:1], value[1:3], "00", "00", value[3:]
} else if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ || std == stdISO8601SecondsTZ || std == stdNumSecondsTz {
if len(value) < 7 {
err = errBad
break
}
if value[3] != ':' || value[6] != ':' {
if std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ || len(value) < 7 {
err = errBad
break
}
sign, hour, min, seconds, value = value[0:1], value[1:3], value[3:5], value[5:7], value[7:]
} else {
if len(value) < 9 {
err = errBad
break
}
sign, hour, min, seconds, value = value[0:1], value[1:3], value[4:6], value[7:9], value[9:]
}
}
var hr, mm, ss int
hr, err = atoi(hour)
if err == nil {
mm, err = atoi(min)
}
if err == nil {
ss, err = atoi(seconds)
}
zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds
switch sign[0] {
case '+':
case '-':
zoneOffset = -zoneOffset
default:
err = errBad
}
case stdTZ:
// Does it look like a time zone?
if len(value) >= 3 && value[0:3] == "UTC" {
z = time.UTC
value = value[3:]
break
}
n, ok := parseTimeZone(value)
if !ok {
err = errBad
break
}
zoneName, value = value[:n], value[n:]
case stdBracketTZ:
if len(value) < 3 || value[0] != '(' {
err = errBad
break
}
i := 1
for ; ; i++ {
if i >= len(value) {
err = errBad
break
}
if value[i] == ')' {
zoneName, value = value[1:i], value[i+1:]
break
}
}
case stdFracSecond0:
// stdFracSecond0 requires the exact number of digits as specified in
// the layout.
ndigit := 1 + (std >> stdArgShift)
if len(value) < ndigit {
err = errBad
break
}
nsec, rangeErrString, err = parseNanoseconds(value, ndigit)
value = value[ndigit:]
case stdFracSecond9:
if len(value) < 2 || value[0] != '.' || value[1] < '0' || '9' < value[1] {
// Fractional second omitted.
break
}
// Take any number of digits, even more than asked for,
// because it is what the stdSecond case would do.
i := 0
for i < 9 && i+1 < len(value) && '0' <= value[i+1] && value[i+1] <= '9' {
i++
}
nsec, rangeErrString, err = parseNanoseconds(value, 1+i)
value = value[1+i:]
}
if rangeErrString != "" {
return time.Time{}, &time.ParseError{Layout: alayout, Value: avalue, LayoutElem: stdstr, ValueElem: value, Message: ": " + rangeErrString + " out of range"}
}
if err != nil {
return time.Time{}, &time.ParseError{Layout: alayout, Value: avalue, LayoutElem: stdstr, ValueElem: value}
}
}
if pmSet && hour < 12 {
hour += 12
} else if amSet && hour == 12 {
hour = 0
}
// Validate the day of the month.
if day < 1 || day > daysIn(time.Month(month), year) {
return time.Time{}, &time.ParseError{Layout: alayout, Value: avalue, ValueElem: value, Message: ": day out of range"}
}
if z == nil {
if zoneOffset == -1 {
if zoneName != "" {
if z1, err := time.LoadLocation(zoneName); err == nil {
z = z1
} else {
return time.Time{}, &time.ParseError{Layout: alayout, Value: avalue, ValueElem: value, Message: ": unknown timezone"}
}
} else {
z = defaultLocation
}
} else if zoneOffset == 0 {
z = time.UTC
} else {
z = time.FixedZone("", zoneOffset)
}
}
return time.Date(year, time.Month(month), day, hour, min, sec, nsec, z), nil
}
var errLeadingInt = errors.New("time: bad [0-9]*") // never printed
func signedLeadingInt(s string) (x int64, rem string, err error) {
neg := false
if s != "" && (s[0] == '-' || s[0] == '+') {
neg = s[0] == '-'
s = s[1:]
}
x, rem, err = leadingInt(s)
if err != nil {
return
}
if neg {
x = -x
}
return
}
// leadingInt consumes the leading [0-9]* from s.
func leadingInt(s string) (x int64, rem string, err error) {
i := 0
for ; i < len(s); i++ {
c := s[i]
if c < '0' || c > '9' {
break
}
if x > (1<<63-1)/10 {
// overflow
return 0, "", errLeadingInt
}
x = x*10 + int64(c) - '0'
if x < 0 {
// overflow
return 0, "", errLeadingInt
}
}
return x, s[i:], nil
}
// nextStdChunk finds the first occurrence of a std string in
// layout and returns the text before, the std string, and the text after.
func nextStdChunk(layout string) (prefix string, std int, suffix string) {
for i := 0; i < len(layout); i++ {
switch c := int(layout[i]); c {
case 'J': // January, Jan
if len(layout) >= i+3 && layout[i:i+3] == "Jan" {
if len(layout) >= i+7 && layout[i:i+7] == "January" {
return layout[0:i], stdLongMonth, layout[i+7:]
}
if !startsWithLowerCase(layout[i+3:]) {
return layout[0:i], stdMonth, layout[i+3:]
}
}
case 'M': // Monday, Mon, MST
if len(layout) >= i+3 {
if layout[i:i+3] == "Mon" {
if len(layout) >= i+6 && layout[i:i+6] == "Monday" {
return layout[0:i], stdLongWeekDay, layout[i+6:]
}
if !startsWithLowerCase(layout[i+3:]) {
return layout[0:i], stdWeekDay, layout[i+3:]
}
}
if layout[i:i+3] == "MST" {
return layout[0:i], stdTZ, layout[i+3:]
}
}
case '0': // 01, 02, 03, 04, 05, 06
if len(layout) >= i+2 && '1' <= layout[i+1] && layout[i+1] <= '6' {
return layout[0:i], std0x[layout[i+1]-'1'], layout[i+2:]
}
case '1': // 15, 1
if len(layout) >= i+2 && layout[i+1] == '5' {
return layout[0:i], stdHour, layout[i+2:]
}
return layout[0:i], stdNumMonth, layout[i+1:]
case '2': // 2006, 2
if len(layout) >= i+4 && layout[i:i+4] == "2006" {
return layout[0:i], stdLongYear, layout[i+4:]
}
return layout[0:i], stdDay, layout[i+1:]
case '_': // _2, _2006
if len(layout) >= i+2 && layout[i+1] == '2' {
//_2006 is really a literal _, followed by stdLongYear
if len(layout) >= i+5 && layout[i+1:i+5] == "2006" {
return layout[0 : i+1], stdLongYear, layout[i+5:]
}
return layout[0:i], stdUnderDay, layout[i+2:]
}
case '3':
return layout[0:i], stdHour12, layout[i+1:]
case '4':
return layout[0:i], stdMinute, layout[i+1:]
case '5':
return layout[0:i], stdSecond, layout[i+1:]
case 'P': // PM
if len(layout) >= i+2 && layout[i+1] == 'M' {
return layout[0:i], stdPM, layout[i+2:]
}
case 'p': // pm
if len(layout) >= i+2 && layout[i+1] == 'm' {
return layout[0:i], stdpm, layout[i+2:]
}
case '-': // -070000, -07:00:00, -0700, -07:00, -07
if len(layout) >= i+7 && layout[i:i+7] == "-070000" {
return layout[0:i], stdNumSecondsTz, layout[i+7:]
}
if len(layout) >= i+9 && layout[i:i+9] == "-07:00:00" {
return layout[0:i], stdNumColonSecondsTZ, layout[i+9:]
}
if len(layout) >= i+5 && layout[i:i+5] == "-0700" {
return layout[0:i], stdNumTZ, layout[i+5:]
}
if len(layout) >= i+6 && layout[i:i+6] == "-07:00" {
return layout[0:i], stdNumColonTZ, layout[i+6:]
}
if len(layout) >= i+3 && layout[i:i+3] == "-07" {
return layout[0:i], stdNumShortTZ, layout[i+3:]
}
case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00,
if len(layout) >= i+7 && layout[i:i+7] == "Z070000" {
return layout[0:i], stdISO8601SecondsTZ, layout[i+7:]
}
if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" {
return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:]
}
if len(layout) >= i+5 && layout[i:i+5] == "Z0700" {
return layout[0:i], stdISO8601TZ, layout[i+5:]
}
if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" {
return layout[0:i], stdISO8601ColonTZ, layout[i+6:]
}
if len(layout) >= i+3 && layout[i:i+3] == "Z07" {
return layout[0:i], stdISO8601ShortTZ, layout[i+3:]
}
case '.': // .000 or .999 - repeated digits for fractional seconds.
if i+1 < len(layout) && (layout[i+1] == '0' || layout[i+1] == '9') {
ch := layout[i+1]
j := i + 1
for j < len(layout) && layout[j] == ch {
j++
}
// String of digits must end here - only fractional second is all digits.
if !isDigit(layout, j) {
std := stdFracSecond0
if layout[i+1] == '9' {
std = stdFracSecond9
}
std |= (j - (i + 1)) << stdArgShift
return layout[0:i], std, layout[j:]
}
}
case '(':
if len(layout) >= i+5 && layout[i:i+5] == "(MST)" {
return layout[0:i], stdBracketTZ, layout[i+5:]
}
}
}
return layout, 0, ""
}
var longDayNames = []string{
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
}
var shortDayNames = []string{
"Sun",
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
}
var shortMonthNames = []string{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
}
var longMonthNames = []string{
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
}
// isDigit reports whether s[i] is in range and is a decimal digit.
func isDigit(s string, i int) bool {
if len(s) <= i {
return false
}
c := s[i]
return '0' <= c && c <= '9'
}
// getnum parses s[0:1] or s[0:2] (fixed forces the latter)
// as a decimal integer and returns the integer and the
// remainder of the string.
func getnum(s string, fixed bool) (int, string, error) {
if !isDigit(s, 0) {
return 0, s, errBad
}
if !isDigit(s, 1) {
if fixed {
return 0, s, errBad
}
return int(s[0] - '0'), s[1:], nil
}
return int(s[0]-'0')*10 + int(s[1]-'0'), s[2:], nil
}
func cutspace(s string) string {
for len(s) > 0 && s[0] == ' ' {
s = s[1:]
}
return s
}
// skip removes the given prefix from value,
// treating runs of space characters as equivalent.
func skip(value, prefix string) (string, error) {
for len(prefix) > 0 {
if prefix[0] == ' ' {
if len(value) > 0 && value[0] != ' ' {
return value, errBad
}
prefix = cutspace(prefix)
value = cutspace(value)
continue
}
if len(value) == 0 || value[0] != prefix[0] {
return value, errBad
}
prefix = prefix[1:]
value = value[1:]
}
return value, nil
}
// Never printed, just needs to be non-nil for return by atoi.
var atoiError = errors.New("time: invalid number")
// Duplicates functionality in strconv, but avoids dependency.
func atoi(s string) (x int, err error) {
q, rem, err := signedLeadingInt(s)
x = int(q)
if err != nil || rem != "" {
return 0, atoiError
}
return x, nil
}
// match reports whether s1 and s2 match ignoring case.
// It is assumed s1 and s2 are the same length.
func match(s1, s2 string) bool {
for i := 0; i < len(s1); i++ {
c1 := s1[i]
c2 := s2[i]
if c1 != c2 {
// Switch to lower-case; 'a'-'A' is known to be a single bit.
c1 |= 'a' - 'A'
c2 |= 'a' - 'A'
if c1 != c2 || c1 < 'a' || c1 > 'z' {
return false
}
}
}
return true
}
func lookup(tab []string, val string) (int, string, error) {
for i, v := range tab {
if len(val) >= len(v) && match(val[0:len(v)], v) {
return i, val[len(v):], nil
}
}
return -1, val, errBad
}
// daysBefore[m] counts the number of days in a non-leap year
// before month m begins. There is an entry for m=12, counting
// the number of days before January of next year (365).
var daysBefore = [...]int32{
0,
31,
31 + 28,
31 + 28 + 31,
31 + 28 + 31 + 30,
31 + 28 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
}
func isLeap(year int) bool {
return year%4 == 0 && (year%100 != 0 || year%400 == 0)
}
func daysIn(m time.Month, year int) int {
if m == time.February && isLeap(year) {
return 29
}
return int(daysBefore[m] - daysBefore[m-1])
}
// parseTimeZone parses a time zone string and returns its length. Time zones
// are human-generated and unpredictable. We can't do precise error checking.
// On the other hand, for a correct parse there must be a time zone at the
// beginning of the string, so it's almost always true that there's one
// there. We look at the beginning of the string for a run of upper-case letters.
// If there are more than 5, it's an error.
// If there are 4 or 5 and the last is a T, it's a time zone.
// If there are 3, it's a time zone.
// Otherwise, other than special cases, it's not a time zone.
// GMT is special because it can have an hour offset.
func parseTimeZone(value string) (length int, ok bool) {
if len(value) < 3 {
return 0, false
}
// Special case 1: ChST and MeST are the only zones with a lower-case letter.
if len(value) >= 4 && (value[:4] == "ChST" || value[:4] == "MeST") {
return 4, true
}
// Special case 2: GMT may have an hour offset; treat it specially.
if value[:3] == "GMT" {
length = parseGMT(value)
return length, true
}
// Special Case 3: Some time zones are not named, but have +/-00 format
if value[0] == '+' || value[0] == '-' {
length = parseSignedOffset(value)
return length, true
}
// How many upper-case letters are there? Need at least three, at most five.
var nUpper int
for nUpper = 0; nUpper < 6; nUpper++ {
if nUpper >= len(value) {
break
}
if c := value[nUpper]; c < 'A' || 'Z' < c {
break
}
}
switch nUpper {
case 0, 1, 2, 6:
return 0, false
case 5: // Must end in T to match.
if value[4] == 'T' {
return 5, true
}
case 4:
// Must end in T, except one special case.
if value[3] == 'T' || value[:4] == "WITA" {
return 4, true
}
case 3:
return 3, true
}
return 0, false
}
// parseGMT parses a GMT time zone. The input string is known to start "GMT".
// The function checks whether that is followed by a sign and a number in the
// range -14 through 12 excluding zero.
func parseGMT(value string) int {
value = value[3:]
if len(value) == 0 {
return 3
}
return 3 + parseSignedOffset(value)
}
// parseSignedOffset parses a signed timezone offset (e.g. "+03" or "-04").
// The function checks for a signed number in the range -14 through +12 excluding zero.
// Returns length of the found offset string or 0 otherwise
func parseSignedOffset(value string) int {
sign := value[0]
if sign != '-' && sign != '+' {
return 0
}
x, rem, err := leadingInt(value[1:])
if err != nil {
return 0
}
if sign == '-' {
x = -x
}
if x == 0 || x < -14 || 12 < x {
return 0
}
return len(value) - len(rem)
}
func parseNanoseconds(value string, nbytes int) (ns int, rangeErrString string, err error) {
if value[0] != '.' {
err = errBad
return
}
if ns, err = atoi(value[1:nbytes]); err != nil {
return
}
if ns < 0 || 1e9 <= ns {
rangeErrString = "fractional second"
return
}
// We need nanoseconds, which means scaling by the number
// of missing digits in the format, maximum length 10. If it's
// longer than 10, we won't scale.
scaleDigits := 10 - nbytes
for i := 0; i < scaleDigits; i++ {
ns *= 10
}
return
}
// std0x records the std values for "01", "02", ..., "06".
var std0x = [...]int{stdZeroMonth, stdZeroDay, stdZeroHour12, stdZeroMinute, stdZeroSecond, stdYear}
// startsWithLowerCase reports whether the string has a lower-case letter at the beginning.
// Its purpose is to prevent matching strings like "Month" when looking for "Mon".
func startsWithLowerCase(str string) bool {
if len(str) == 0 {
return false
}
c := str[0]
return 'a' <= c && c <= 'z'
}

312
server/vendor/github.com/dop251/goja/destruct.go generated vendored Normal file
View File

@@ -0,0 +1,312 @@
package goja
import (
"github.com/dop251/goja/unistring"
"reflect"
)
type destructKeyedSource struct {
r *Runtime
wrapped Value
usedKeys map[Value]struct{}
}
func newDestructKeyedSource(r *Runtime, wrapped Value) *destructKeyedSource {
return &destructKeyedSource{
r: r,
wrapped: wrapped,
}
}
func (r *Runtime) newDestructKeyedSource(wrapped Value) *Object {
return &Object{
runtime: r,
self: newDestructKeyedSource(r, wrapped),
}
}
func (d *destructKeyedSource) w() objectImpl {
return d.wrapped.ToObject(d.r).self
}
func (d *destructKeyedSource) recordKey(key Value) {
if d.usedKeys == nil {
d.usedKeys = make(map[Value]struct{})
}
d.usedKeys[key] = struct{}{}
}
func (d *destructKeyedSource) sortLen() int {
return d.w().sortLen()
}
func (d *destructKeyedSource) sortGet(i int) Value {
return d.w().sortGet(i)
}
func (d *destructKeyedSource) swap(i int, i2 int) {
d.w().swap(i, i2)
}
func (d *destructKeyedSource) className() string {
return d.w().className()
}
func (d *destructKeyedSource) typeOf() valueString {
return d.w().typeOf()
}
func (d *destructKeyedSource) getStr(p unistring.String, receiver Value) Value {
d.recordKey(stringValueFromRaw(p))
return d.w().getStr(p, receiver)
}
func (d *destructKeyedSource) getIdx(p valueInt, receiver Value) Value {
d.recordKey(p.toString())
return d.w().getIdx(p, receiver)
}
func (d *destructKeyedSource) getSym(p *Symbol, receiver Value) Value {
d.recordKey(p)
return d.w().getSym(p, receiver)
}
func (d *destructKeyedSource) getOwnPropStr(u unistring.String) Value {
d.recordKey(stringValueFromRaw(u))
return d.w().getOwnPropStr(u)
}
func (d *destructKeyedSource) getOwnPropIdx(v valueInt) Value {
d.recordKey(v.toString())
return d.w().getOwnPropIdx(v)
}
func (d *destructKeyedSource) getOwnPropSym(symbol *Symbol) Value {
d.recordKey(symbol)
return d.w().getOwnPropSym(symbol)
}
func (d *destructKeyedSource) setOwnStr(p unistring.String, v Value, throw bool) bool {
return d.w().setOwnStr(p, v, throw)
}
func (d *destructKeyedSource) setOwnIdx(p valueInt, v Value, throw bool) bool {
return d.w().setOwnIdx(p, v, throw)
}
func (d *destructKeyedSource) setOwnSym(p *Symbol, v Value, throw bool) bool {
return d.w().setOwnSym(p, v, throw)
}
func (d *destructKeyedSource) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
return d.w().setForeignStr(p, v, receiver, throw)
}
func (d *destructKeyedSource) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
return d.w().setForeignIdx(p, v, receiver, throw)
}
func (d *destructKeyedSource) setForeignSym(p *Symbol, v, receiver Value, throw bool) (res bool, handled bool) {
return d.w().setForeignSym(p, v, receiver, throw)
}
func (d *destructKeyedSource) hasPropertyStr(u unistring.String) bool {
return d.w().hasPropertyStr(u)
}
func (d *destructKeyedSource) hasPropertyIdx(idx valueInt) bool {
return d.w().hasPropertyIdx(idx)
}
func (d *destructKeyedSource) hasPropertySym(s *Symbol) bool {
return d.w().hasPropertySym(s)
}
func (d *destructKeyedSource) hasOwnPropertyStr(u unistring.String) bool {
return d.w().hasOwnPropertyStr(u)
}
func (d *destructKeyedSource) hasOwnPropertyIdx(v valueInt) bool {
return d.w().hasOwnPropertyIdx(v)
}
func (d *destructKeyedSource) hasOwnPropertySym(s *Symbol) bool {
return d.w().hasOwnPropertySym(s)
}
func (d *destructKeyedSource) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
return d.w().defineOwnPropertyStr(name, desc, throw)
}
func (d *destructKeyedSource) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
return d.w().defineOwnPropertyIdx(name, desc, throw)
}
func (d *destructKeyedSource) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
return d.w().defineOwnPropertySym(name, desc, throw)
}
func (d *destructKeyedSource) deleteStr(name unistring.String, throw bool) bool {
return d.w().deleteStr(name, throw)
}
func (d *destructKeyedSource) deleteIdx(idx valueInt, throw bool) bool {
return d.w().deleteIdx(idx, throw)
}
func (d *destructKeyedSource) deleteSym(s *Symbol, throw bool) bool {
return d.w().deleteSym(s, throw)
}
func (d *destructKeyedSource) toPrimitiveNumber() Value {
return d.w().toPrimitiveNumber()
}
func (d *destructKeyedSource) toPrimitiveString() Value {
return d.w().toPrimitiveString()
}
func (d *destructKeyedSource) toPrimitive() Value {
return d.w().toPrimitive()
}
func (d *destructKeyedSource) assertCallable() (call func(FunctionCall) Value, ok bool) {
return d.w().assertCallable()
}
func (d *destructKeyedSource) vmCall(vm *vm, n int) {
d.w().vmCall(vm, n)
}
func (d *destructKeyedSource) assertConstructor() func(args []Value, newTarget *Object) *Object {
return d.w().assertConstructor()
}
func (d *destructKeyedSource) proto() *Object {
return d.w().proto()
}
func (d *destructKeyedSource) setProto(proto *Object, throw bool) bool {
return d.w().setProto(proto, throw)
}
func (d *destructKeyedSource) hasInstance(v Value) bool {
return d.w().hasInstance(v)
}
func (d *destructKeyedSource) isExtensible() bool {
return d.w().isExtensible()
}
func (d *destructKeyedSource) preventExtensions(throw bool) bool {
return d.w().preventExtensions(throw)
}
type destructKeyedSourceIter struct {
d *destructKeyedSource
wrapped iterNextFunc
}
func (i *destructKeyedSourceIter) next() (propIterItem, iterNextFunc) {
for {
item, next := i.wrapped()
if next == nil {
return item, nil
}
i.wrapped = next
if _, exists := i.d.usedKeys[item.name]; !exists {
return item, i.next
}
}
}
func (d *destructKeyedSource) iterateStringKeys() iterNextFunc {
return (&destructKeyedSourceIter{
d: d,
wrapped: d.w().iterateStringKeys(),
}).next
}
func (d *destructKeyedSource) iterateSymbols() iterNextFunc {
return (&destructKeyedSourceIter{
d: d,
wrapped: d.w().iterateSymbols(),
}).next
}
func (d *destructKeyedSource) iterateKeys() iterNextFunc {
return (&destructKeyedSourceIter{
d: d,
wrapped: d.w().iterateKeys(),
}).next
}
func (d *destructKeyedSource) export(ctx *objectExportCtx) interface{} {
return d.w().export(ctx)
}
func (d *destructKeyedSource) exportType() reflect.Type {
return d.w().exportType()
}
func (d *destructKeyedSource) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
return d.w().exportToMap(dst, typ, ctx)
}
func (d *destructKeyedSource) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
return d.w().exportToArrayOrSlice(dst, typ, ctx)
}
func (d *destructKeyedSource) equal(impl objectImpl) bool {
return d.w().equal(impl)
}
func (d *destructKeyedSource) stringKeys(all bool, accum []Value) []Value {
var next iterNextFunc
if all {
next = d.iterateStringKeys()
} else {
next = (&enumerableIter{
o: d.wrapped.ToObject(d.r),
wrapped: d.iterateStringKeys(),
}).next
}
for item, next := next(); next != nil; item, next = next() {
accum = append(accum, item.name)
}
return accum
}
func (d *destructKeyedSource) filterUsedKeys(keys []Value) []Value {
k := 0
for i, key := range keys {
if _, exists := d.usedKeys[key]; exists {
continue
}
if k != i {
keys[k] = key
}
k++
}
return keys[:k]
}
func (d *destructKeyedSource) symbols(all bool, accum []Value) []Value {
return d.filterUsedKeys(d.w().symbols(all, accum))
}
func (d *destructKeyedSource) keys(all bool, accum []Value) []Value {
return d.filterUsedKeys(d.w().keys(all, accum))
}
func (d *destructKeyedSource) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
return d.w()._putProp(name, value, writable, enumerable, configurable)
}
func (d *destructKeyedSource) _putSym(s *Symbol, prop Value) {
d.w()._putSym(s, prop)
}
func (d *destructKeyedSource) getPrivateEnv(typ *privateEnvType, create bool) *privateElements {
return d.w().getPrivateEnv(typ, create)
}

View File

@@ -0,0 +1,3 @@
#!/bin/sh
sed -En 's/^.*FAIL: TestTC39\/tc39\/(test\/.*.js).*$/"\1": true,/p'

View File

@@ -0,0 +1,110 @@
# file
--
import "github.com/dop251/goja/file"
Package file encapsulates the file abstractions used by the ast & parser.
## Usage
#### type File
```go
type File struct {
}
```
#### func NewFile
```go
func NewFile(filename, src string, base int) *File
```
#### func (*File) Base
```go
func (fl *File) Base() int
```
#### func (*File) Name
```go
func (fl *File) Name() string
```
#### func (*File) Source
```go
func (fl *File) Source() string
```
#### type FileSet
```go
type FileSet struct {
}
```
A FileSet represents a set of source files.
#### func (*FileSet) AddFile
```go
func (self *FileSet) AddFile(filename, src string) int
```
AddFile adds a new file with the given filename and src.
This an internal method, but exported for cross-package use.
#### func (*FileSet) File
```go
func (self *FileSet) File(idx Idx) *File
```
#### func (*FileSet) Position
```go
func (self *FileSet) Position(idx Idx) *Position
```
Position converts an Idx in the FileSet into a Position.
#### type Idx
```go
type Idx int
```
Idx is a compact encoding of a source position within a file set. It can be
converted into a Position for a more convenient, but much larger,
representation.
#### type Position
```go
type Position struct {
Filename string // The filename where the error occurred, if any
Offset int // The src offset
Line int // The line number, starting at 1
Column int // The column number, starting at 1 (The character count)
}
```
Position describes an arbitrary source position including the filename, line,
and column location.
#### func (*Position) String
```go
func (self *Position) String() string
```
String returns a string in one of several forms:
file:line:column A valid position with filename
line:column A valid position without filename
file An invalid position with filename
- An invalid position without filename
--
**godocdown** http://github.com/robertkrimen/godocdown

234
server/vendor/github.com/dop251/goja/file/file.go generated vendored Normal file
View File

@@ -0,0 +1,234 @@
// Package file encapsulates the file abstractions used by the ast & parser.
package file
import (
"fmt"
"net/url"
"path"
"sort"
"strings"
"sync"
"github.com/go-sourcemap/sourcemap"
)
// Idx is a compact encoding of a source position within a file set.
// It can be converted into a Position for a more convenient, but much
// larger, representation.
type Idx int
// Position describes an arbitrary source position
// including the filename, line, and column location.
type Position struct {
Filename string // The filename where the error occurred, if any
Line int // The line number, starting at 1
Column int // The column number, starting at 1 (The character count)
}
// A Position is valid if the line number is > 0.
func (self *Position) isValid() bool {
return self.Line > 0
}
// String returns a string in one of several forms:
//
// file:line:column A valid position with filename
// line:column A valid position without filename
// file An invalid position with filename
// - An invalid position without filename
func (self Position) String() string {
str := self.Filename
if self.isValid() {
if str != "" {
str += ":"
}
str += fmt.Sprintf("%d:%d", self.Line, self.Column)
}
if str == "" {
str = "-"
}
return str
}
// FileSet
// A FileSet represents a set of source files.
type FileSet struct {
files []*File
last *File
}
// AddFile adds a new file with the given filename and src.
//
// This an internal method, but exported for cross-package use.
func (self *FileSet) AddFile(filename, src string) int {
base := self.nextBase()
file := &File{
name: filename,
src: src,
base: base,
}
self.files = append(self.files, file)
self.last = file
return base
}
func (self *FileSet) nextBase() int {
if self.last == nil {
return 1
}
return self.last.base + len(self.last.src) + 1
}
func (self *FileSet) File(idx Idx) *File {
for _, file := range self.files {
if idx <= Idx(file.base+len(file.src)) {
return file
}
}
return nil
}
// Position converts an Idx in the FileSet into a Position.
func (self *FileSet) Position(idx Idx) Position {
for _, file := range self.files {
if idx <= Idx(file.base+len(file.src)) {
return file.Position(int(idx) - file.base)
}
}
return Position{}
}
type File struct {
mu sync.Mutex
name string
src string
base int // This will always be 1 or greater
sourceMap *sourcemap.Consumer
lineOffsets []int
lastScannedOffset int
}
func NewFile(filename, src string, base int) *File {
return &File{
name: filename,
src: src,
base: base,
}
}
func (fl *File) Name() string {
return fl.name
}
func (fl *File) Source() string {
return fl.src
}
func (fl *File) Base() int {
return fl.base
}
func (fl *File) SetSourceMap(m *sourcemap.Consumer) {
fl.sourceMap = m
}
func (fl *File) Position(offset int) Position {
var line int
var lineOffsets []int
fl.mu.Lock()
if offset > fl.lastScannedOffset {
line = fl.scanTo(offset)
lineOffsets = fl.lineOffsets
fl.mu.Unlock()
} else {
lineOffsets = fl.lineOffsets
fl.mu.Unlock()
line = sort.Search(len(lineOffsets), func(x int) bool { return lineOffsets[x] > offset }) - 1
}
var lineStart int
if line >= 0 {
lineStart = lineOffsets[line]
}
row := line + 2
col := offset - lineStart + 1
if fl.sourceMap != nil {
if source, _, row, col, ok := fl.sourceMap.Source(row, col); ok {
sourceUrlStr := source
sourceURL := ResolveSourcemapURL(fl.Name(), source)
if sourceURL != nil {
sourceUrlStr = sourceURL.String()
}
return Position{
Filename: sourceUrlStr,
Line: row,
Column: col,
}
}
}
return Position{
Filename: fl.name,
Line: row,
Column: col,
}
}
func ResolveSourcemapURL(basename, source string) *url.URL {
// if the url is absolute(has scheme) there is nothing to do
smURL, err := url.Parse(strings.TrimSpace(source))
if err == nil && !smURL.IsAbs() {
baseURL, err1 := url.Parse(strings.TrimSpace(basename))
if err1 == nil && path.IsAbs(baseURL.Path) {
smURL = baseURL.ResolveReference(smURL)
} else {
// pathological case where both are not absolute paths and using Resolve
// as above will produce an absolute one
smURL, _ = url.Parse(path.Join(path.Dir(basename), smURL.Path))
}
}
return smURL
}
func findNextLineStart(s string) int {
for pos, ch := range s {
switch ch {
case '\r':
if pos < len(s)-1 && s[pos+1] == '\n' {
return pos + 2
}
return pos + 1
case '\n':
return pos + 1
case '\u2028', '\u2029':
return pos + 3
}
}
return -1
}
func (fl *File) scanTo(offset int) int {
o := fl.lastScannedOffset
for o < offset {
p := findNextLineStart(fl.src[o:])
if p == -1 {
fl.lastScannedOffset = len(fl.src)
return len(fl.lineOffsets) - 1
}
o = o + p
fl.lineOffsets = append(fl.lineOffsets, o)
}
fl.lastScannedOffset = o
if o == offset {
return len(fl.lineOffsets) - 1
}
return len(fl.lineOffsets) - 2
}

View File

@@ -0,0 +1,21 @@
Copyright (C) 1998, 1999 by Lucent Technologies
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

150
server/vendor/github.com/dop251/goja/ftoa/common.go generated vendored Normal file
View File

@@ -0,0 +1,150 @@
/*
Package ftoa provides ECMAScript-compliant floating point number conversion to string.
It contains code ported from Rhino (https://github.com/mozilla/rhino/blob/master/src/org/mozilla/javascript/DToA.java)
as well as from the original code by David M. Gay.
See LICENSE_LUCENE for the original copyright message and disclaimer.
*/
package ftoa
import (
"math"
)
const (
frac_mask = 0xfffff
exp_shift = 20
exp_msk1 = 0x100000
exp_shiftL = 52
exp_mask_shifted = 0x7ff
frac_maskL = 0xfffffffffffff
exp_msk1L = 0x10000000000000
exp_shift1 = 20
exp_mask = 0x7ff00000
bias = 1023
p = 53
bndry_mask = 0xfffff
log2P = 1
)
func lo0bits(x uint32) (k int) {
if (x & 7) != 0 {
if (x & 1) != 0 {
return 0
}
if (x & 2) != 0 {
return 1
}
return 2
}
if (x & 0xffff) == 0 {
k = 16
x >>= 16
}
if (x & 0xff) == 0 {
k += 8
x >>= 8
}
if (x & 0xf) == 0 {
k += 4
x >>= 4
}
if (x & 0x3) == 0 {
k += 2
x >>= 2
}
if (x & 1) == 0 {
k++
x >>= 1
if (x & 1) == 0 {
return 32
}
}
return
}
func hi0bits(x uint32) (k int) {
if (x & 0xffff0000) == 0 {
k = 16
x <<= 16
}
if (x & 0xff000000) == 0 {
k += 8
x <<= 8
}
if (x & 0xf0000000) == 0 {
k += 4
x <<= 4
}
if (x & 0xc0000000) == 0 {
k += 2
x <<= 2
}
if (x & 0x80000000) == 0 {
k++
if (x & 0x40000000) == 0 {
return 32
}
}
return
}
func stuffBits(bits []byte, offset int, val uint32) {
bits[offset] = byte(val >> 24)
bits[offset+1] = byte(val >> 16)
bits[offset+2] = byte(val >> 8)
bits[offset+3] = byte(val)
}
func d2b(d float64, b []byte) (e, bits int, dblBits []byte) {
dBits := math.Float64bits(d)
d0 := uint32(dBits >> 32)
d1 := uint32(dBits)
z := d0 & frac_mask
d0 &= 0x7fffffff /* clear sign bit, which we ignore */
var de, k, i int
if de = int(d0 >> exp_shift); de != 0 {
z |= exp_msk1
}
y := d1
if y != 0 {
dblBits = b[:8]
k = lo0bits(y)
y >>= k
if k != 0 {
stuffBits(dblBits, 4, y|z<<(32-k))
z >>= k
} else {
stuffBits(dblBits, 4, y)
}
stuffBits(dblBits, 0, z)
if z != 0 {
i = 2
} else {
i = 1
}
} else {
dblBits = b[:4]
k = lo0bits(z)
z >>= k
stuffBits(dblBits, 0, z)
k += 32
i = 1
}
if de != 0 {
e = de - bias - (p - 1) + k
bits = p - k
} else {
e = de - bias - (p - 1) + 1 + k
bits = 32*i - hi0bits(z)
}
return
}

699
server/vendor/github.com/dop251/goja/ftoa/ftoa.go generated vendored Normal file
View File

@@ -0,0 +1,699 @@
package ftoa
import (
"math"
"math/big"
)
const (
exp_11 = 0x3ff00000
frac_mask1 = 0xfffff
bletch = 0x10
quick_max = 14
int_max = 14
)
var (
tens = [...]float64{
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
1e20, 1e21, 1e22,
}
bigtens = [...]float64{1e16, 1e32, 1e64, 1e128, 1e256}
big5 = big.NewInt(5)
big10 = big.NewInt(10)
p05 = []*big.Int{big5, big.NewInt(25), big.NewInt(125)}
pow5Cache [7]*big.Int
dtoaModes = []int{
ModeStandard: 0,
ModeStandardExponential: 0,
ModeFixed: 3,
ModeExponential: 2,
ModePrecision: 2,
}
)
/*
d must be > 0 and must not be Inf
mode:
0 ==> shortest string that yields d when read in
and rounded to nearest.
1 ==> like 0, but with Steele & White stopping rule;
e.g. with IEEE P754 arithmetic , mode 0 gives
1e23 whereas mode 1 gives 9.999999999999999e22.
2 ==> max(1,ndigits) significant digits. This gives a
return value similar to that of ecvt, except
that trailing zeros are suppressed.
3 ==> through ndigits past the decimal point. This
gives a return value similar to that from fcvt,
except that trailing zeros are suppressed, and
ndigits can be negative.
4,5 ==> similar to 2 and 3, respectively, but (in
round-nearest mode) with the tests of mode 0 to
possibly return a shorter string that rounds to d.
With IEEE arithmetic and compilation with
-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
as modes 2 and 3 when FLT_ROUNDS != 1.
6-9 ==> Debugging modes similar to mode - 4: don't try
fast floating-point estimate (if applicable).
Values of mode other than 0-9 are treated as mode 0.
*/
func ftoa(d float64, mode int, biasUp bool, ndigits int, buf []byte) ([]byte, int) {
startPos := len(buf)
dblBits := make([]byte, 0, 8)
be, bbits, dblBits := d2b(d, dblBits)
dBits := math.Float64bits(d)
word0 := uint32(dBits >> 32)
word1 := uint32(dBits)
i := int((word0 >> exp_shift1) & (exp_mask >> exp_shift1))
var d2 float64
var denorm bool
if i != 0 {
d2 = setWord0(d, (word0&frac_mask1)|exp_11)
i -= bias
denorm = false
} else {
/* d is denormalized */
i = bbits + be + (bias + (p - 1) - 1)
var x uint64
if i > 32 {
x = uint64(word0)<<(64-i) | uint64(word1)>>(i-32)
} else {
x = uint64(word1) << (32 - i)
}
d2 = setWord0(float64(x), uint32((x>>32)-31*exp_mask))
i -= (bias + (p - 1) - 1) + 1
denorm = true
}
/* At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. */
ds := (d2-1.5)*0.289529654602168 + 0.1760912590558 + float64(i)*0.301029995663981
k := int(ds)
if ds < 0.0 && ds != float64(k) {
k-- /* want k = floor(ds) */
}
k_check := true
if k >= 0 && k < len(tens) {
if d < tens[k] {
k--
}
k_check = false
}
/* At this point floor(log10(d)) <= k <= floor(log10(d))+1.
If k_check is zero, we're guaranteed that k = floor(log10(d)). */
j := bbits - i - 1
var b2, s2, b5, s5 int
/* At this point d = b/2^j, where b is an odd integer. */
if j >= 0 {
b2 = 0
s2 = j
} else {
b2 = -j
s2 = 0
}
if k >= 0 {
b5 = 0
s5 = k
s2 += k
} else {
b2 -= k
b5 = -k
s5 = 0
}
/* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer,
b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */
if mode < 0 || mode > 9 {
mode = 0
}
try_quick := true
if mode > 5 {
mode -= 4
try_quick = false
}
leftright := true
var ilim, ilim1 int
switch mode {
case 0, 1:
ilim, ilim1 = -1, -1
ndigits = 0
case 2:
leftright = false
fallthrough
case 4:
if ndigits <= 0 {
ndigits = 1
}
ilim, ilim1 = ndigits, ndigits
case 3:
leftright = false
fallthrough
case 5:
i = ndigits + k + 1
ilim = i
ilim1 = i - 1
}
/* ilim is the maximum number of significant digits we want, based on k and ndigits. */
/* ilim1 is the maximum number of significant digits we want, based on k and ndigits,
when it turns out that k was computed too high by one. */
fast_failed := false
if ilim >= 0 && ilim <= quick_max && try_quick {
/* Try to get by with floating-point arithmetic. */
i = 0
d2 = d
k0 := k
ilim0 := ilim
ieps := 2 /* conservative */
/* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */
if k > 0 {
ds = tens[k&0xf]
j = k >> 4
if (j & bletch) != 0 {
/* prevent overflows */
j &= bletch - 1
d /= bigtens[len(bigtens)-1]
ieps++
}
for ; j != 0; i++ {
if (j & 1) != 0 {
ieps++
ds *= bigtens[i]
}
j >>= 1
}
d /= ds
} else if j1 := -k; j1 != 0 {
d *= tens[j1&0xf]
for j = j1 >> 4; j != 0; i++ {
if (j & 1) != 0 {
ieps++
d *= bigtens[i]
}
j >>= 1
}
}
/* Check that k was computed correctly. */
if k_check && d < 1.0 && ilim > 0 {
if ilim1 <= 0 {
fast_failed = true
} else {
ilim = ilim1
k--
d *= 10.
ieps++
}
}
/* eps bounds the cumulative error. */
eps := float64(ieps)*d + 7.0
eps = setWord0(eps, _word0(eps)-(p-1)*exp_msk1)
if ilim == 0 {
d -= 5.0
if d > eps {
buf = append(buf, '1')
k++
return buf, k + 1
}
if d < -eps {
buf = append(buf, '0')
return buf, 1
}
fast_failed = true
}
if !fast_failed {
fast_failed = true
if leftright {
/* Use Steele & White method of only
* generating digits needed.
*/
eps = 0.5/tens[ilim-1] - eps
for i = 0; ; {
l := int64(d)
d -= float64(l)
buf = append(buf, byte('0'+l))
if d < eps {
return buf, k + 1
}
if 1.0-d < eps {
buf, k = bumpUp(buf, k)
return buf, k + 1
}
i++
if i >= ilim {
break
}
eps *= 10.0
d *= 10.0
}
} else {
/* Generate ilim digits, then fix them up. */
eps *= tens[ilim-1]
for i = 1; ; i++ {
l := int64(d)
d -= float64(l)
buf = append(buf, byte('0'+l))
if i == ilim {
if d > 0.5+eps {
buf, k = bumpUp(buf, k)
return buf, k + 1
} else if d < 0.5-eps {
buf = stripTrailingZeroes(buf, startPos)
return buf, k + 1
}
break
}
d *= 10.0
}
}
}
if fast_failed {
buf = buf[:startPos]
d = d2
k = k0
ilim = ilim0
}
}
/* Do we have a "small" integer? */
if be >= 0 && k <= int_max {
/* Yes. */
ds = tens[k]
if ndigits < 0 && ilim <= 0 {
if ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds) {
buf = buf[:startPos]
buf = append(buf, '0')
return buf, 1
}
buf = append(buf, '1')
k++
return buf, k + 1
}
for i = 1; ; i++ {
l := int64(d / ds)
d -= float64(l) * ds
buf = append(buf, byte('0'+l))
if i == ilim {
d += d
if (d > ds) || (d == ds && (((l & 1) != 0) || biasUp)) {
buf, k = bumpUp(buf, k)
}
break
}
d *= 10.0
if d == 0 {
break
}
}
return buf, k + 1
}
m2 := b2
m5 := b5
var mhi, mlo *big.Int
if leftright {
if mode < 2 {
if denorm {
i = be + (bias + (p - 1) - 1 + 1)
} else {
i = 1 + p - bbits
}
/* i is 1 plus the number of trailing zero bits in d's significand. Thus,
(2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */
} else {
j = ilim - 1
if m5 >= j {
m5 -= j
} else {
j -= m5
s5 += j
b5 += j
m5 = 0
}
i = ilim
if i < 0 {
m2 -= i
i = 0
}
/* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */
}
b2 += i
s2 += i
mhi = big.NewInt(1)
/* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or
input (when mode < 2) significant digit, divided by 10^k. */
}
/* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in
b2, m2, and s2 without changing the equalities. */
if m2 > 0 && s2 > 0 {
if m2 < s2 {
i = m2
} else {
i = s2
}
b2 -= i
m2 -= i
s2 -= i
}
b := new(big.Int).SetBytes(dblBits)
/* Fold b5 into b and m5 into mhi. */
if b5 > 0 {
if leftright {
if m5 > 0 {
pow5mult(mhi, m5)
b.Mul(mhi, b)
}
j = b5 - m5
if j != 0 {
pow5mult(b, j)
}
} else {
pow5mult(b, b5)
}
}
/* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and
(mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */
S := big.NewInt(1)
if s5 > 0 {
pow5mult(S, s5)
}
/* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and
(mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */
/* Check for special case that d is a normalized power of 2. */
spec_case := false
if mode < 2 {
if (_word1(d) == 0) && ((_word0(d) & bndry_mask) == 0) &&
((_word0(d) & (exp_mask & (exp_mask << 1))) != 0) {
/* The special case. Here we want to be within a quarter of the last input
significant digit instead of one half of it when the decimal output string's value is less than d. */
b2 += log2P
s2 += log2P
spec_case = true
}
}
/* Arrange for convenient computation of quotients:
* shift left if necessary so divisor has 4 leading 0 bits.
*
* Perhaps we should just compute leading 28 bits of S once
* and for all and pass them and a shift to quorem, so it
* can do shifts and ors to compute the numerator for q.
*/
var zz int
if s5 != 0 {
S_bytes := S.Bytes()
var S_hiWord uint32
for idx := 0; idx < 4; idx++ {
S_hiWord = S_hiWord << 8
if idx < len(S_bytes) {
S_hiWord |= uint32(S_bytes[idx])
}
}
zz = 32 - hi0bits(S_hiWord)
} else {
zz = 1
}
i = (zz + s2) & 0x1f
if i != 0 {
i = 32 - i
}
/* i is the number of leading zero bits in the most significant word of S*2^s2. */
if i > 4 {
i -= 4
b2 += i
m2 += i
s2 += i
} else if i < 4 {
i += 28
b2 += i
m2 += i
s2 += i
}
/* Now S*2^s2 has exactly four leading zero bits in its most significant word. */
if b2 > 0 {
b = b.Lsh(b, uint(b2))
}
if s2 > 0 {
S.Lsh(S, uint(s2))
}
/* Now we have d/10^k = b/S and
(mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */
if k_check {
if b.Cmp(S) < 0 {
k--
b.Mul(b, big10) /* we botched the k estimate */
if leftright {
mhi.Mul(mhi, big10)
}
ilim = ilim1
}
}
/* At this point 1 <= d/10^k = b/S < 10. */
if ilim <= 0 && mode > 2 {
/* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode.
Output either zero or the minimum nonzero output depending on which is closer to d. */
if ilim >= 0 {
i = b.Cmp(S.Mul(S, big5))
}
if ilim < 0 || i < 0 || i == 0 && !biasUp {
/* Always emit at least one digit. If the number appears to be zero
using the current mode, then emit one '0' digit and set decpt to 1. */
buf = buf[:startPos]
buf = append(buf, '0')
return buf, 1
}
buf = append(buf, '1')
k++
return buf, k + 1
}
var dig byte
if leftright {
if m2 > 0 {
mhi.Lsh(mhi, uint(m2))
}
/* Compute mlo -- check for special case
* that d is a normalized power of 2.
*/
mlo = mhi
if spec_case {
mhi = mlo
mhi = new(big.Int).Lsh(mhi, log2P)
}
/* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */
/* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */
var z, delta big.Int
for i = 1; ; i++ {
z.DivMod(b, S, b)
dig = byte(z.Int64() + '0')
/* Do we yet have the shortest decimal string
* that will round to d?
*/
j = b.Cmp(mlo)
/* j is b/S compared with mlo/S. */
delta.Sub(S, mhi)
var j1 int
if delta.Sign() <= 0 {
j1 = 1
} else {
j1 = b.Cmp(&delta)
}
/* j1 is b/S compared with 1 - mhi/S. */
if (j1 == 0) && (mode == 0) && ((_word1(d) & 1) == 0) {
if dig == '9' {
var flag bool
buf = append(buf, '9')
if buf, flag = roundOff(buf, startPos); flag {
k++
buf = append(buf, '1')
}
return buf, k + 1
}
if j > 0 {
dig++
}
buf = append(buf, dig)
return buf, k + 1
}
if (j < 0) || ((j == 0) && (mode == 0) && ((_word1(d) & 1) == 0)) {
if j1 > 0 {
/* Either dig or dig+1 would work here as the least significant decimal digit.
Use whichever would produce a decimal value closer to d. */
b.Lsh(b, 1)
j1 = b.Cmp(S)
if (j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp)) {
dig++
if dig == '9' {
buf = append(buf, '9')
buf, flag := roundOff(buf, startPos)
if flag {
k++
buf = append(buf, '1')
}
return buf, k + 1
}
}
}
buf = append(buf, dig)
return buf, k + 1
}
if j1 > 0 {
if dig == '9' { /* possible if i == 1 */
buf = append(buf, '9')
buf, flag := roundOff(buf, startPos)
if flag {
k++
buf = append(buf, '1')
}
return buf, k + 1
}
buf = append(buf, dig+1)
return buf, k + 1
}
buf = append(buf, dig)
if i == ilim {
break
}
b.Mul(b, big10)
if mlo == mhi {
mhi.Mul(mhi, big10)
} else {
mlo.Mul(mlo, big10)
mhi.Mul(mhi, big10)
}
}
} else {
var z big.Int
for i = 1; ; i++ {
z.DivMod(b, S, b)
dig = byte(z.Int64() + '0')
buf = append(buf, dig)
if i >= ilim {
break
}
b.Mul(b, big10)
}
}
/* Round off last digit */
b.Lsh(b, 1)
j = b.Cmp(S)
if (j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp)) {
var flag bool
buf, flag = roundOff(buf, startPos)
if flag {
k++
buf = append(buf, '1')
return buf, k + 1
}
} else {
buf = stripTrailingZeroes(buf, startPos)
}
return buf, k + 1
}
func bumpUp(buf []byte, k int) ([]byte, int) {
var lastCh byte
stop := 0
if len(buf) > 0 && buf[0] == '-' {
stop = 1
}
for {
lastCh = buf[len(buf)-1]
buf = buf[:len(buf)-1]
if lastCh != '9' {
break
}
if len(buf) == stop {
k++
lastCh = '0'
break
}
}
buf = append(buf, lastCh+1)
return buf, k
}
func setWord0(d float64, w uint32) float64 {
dBits := math.Float64bits(d)
return math.Float64frombits(uint64(w)<<32 | dBits&0xffffffff)
}
func _word0(d float64) uint32 {
dBits := math.Float64bits(d)
return uint32(dBits >> 32)
}
func _word1(d float64) uint32 {
dBits := math.Float64bits(d)
return uint32(dBits)
}
func stripTrailingZeroes(buf []byte, startPos int) []byte {
bl := len(buf) - 1
for bl >= startPos && buf[bl] == '0' {
bl--
}
return buf[:bl+1]
}
/* Set b = b * 5^k. k must be nonnegative. */
func pow5mult(b *big.Int, k int) *big.Int {
if k < (1 << (len(pow5Cache) + 2)) {
i := k & 3
if i != 0 {
b.Mul(b, p05[i-1])
}
k >>= 2
i = 0
for {
if k&1 != 0 {
b.Mul(b, pow5Cache[i])
}
k >>= 1
if k == 0 {
break
}
i++
}
return b
}
return b.Mul(b, new(big.Int).Exp(big5, big.NewInt(int64(k)), nil))
}
func roundOff(buf []byte, startPos int) ([]byte, bool) {
i := len(buf)
for i != startPos {
i--
if buf[i] != '9' {
buf[i]++
return buf[:i+1], false
}
}
return buf[:startPos], true
}
func init() {
p := big.NewInt(625)
pow5Cache[0] = p
for i := 1; i < len(pow5Cache); i++ {
p = new(big.Int).Mul(p, p)
pow5Cache[i] = p
}
}

153
server/vendor/github.com/dop251/goja/ftoa/ftobasestr.go generated vendored Normal file
View File

@@ -0,0 +1,153 @@
package ftoa
import (
"fmt"
"math"
"math/big"
"strconv"
"strings"
)
const (
digits = "0123456789abcdefghijklmnopqrstuvwxyz"
)
func FToBaseStr(num float64, radix int) string {
var negative bool
if num < 0 {
num = -num
negative = true
}
dfloor := math.Floor(num)
ldfloor := int64(dfloor)
var intDigits string
if dfloor == float64(ldfloor) {
if negative {
ldfloor = -ldfloor
}
intDigits = strconv.FormatInt(ldfloor, radix)
} else {
floorBits := math.Float64bits(num)
exp := int(floorBits>>exp_shiftL) & exp_mask_shifted
var mantissa int64
if exp == 0 {
mantissa = int64((floorBits & frac_maskL) << 1)
} else {
mantissa = int64((floorBits & frac_maskL) | exp_msk1L)
}
if negative {
mantissa = -mantissa
}
exp -= 1075
x := big.NewInt(mantissa)
if exp > 0 {
x.Lsh(x, uint(exp))
} else if exp < 0 {
x.Rsh(x, uint(-exp))
}
intDigits = x.Text(radix)
}
if num == dfloor {
// No fraction part
return intDigits
} else {
/* We have a fraction. */
var buffer strings.Builder
buffer.WriteString(intDigits)
buffer.WriteByte('.')
df := num - dfloor
dBits := math.Float64bits(num)
word0 := uint32(dBits >> 32)
word1 := uint32(dBits)
dblBits := make([]byte, 0, 8)
e, _, dblBits := d2b(df, dblBits)
// JS_ASSERT(e < 0);
/* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */
s2 := -int((word0 >> exp_shift1) & (exp_mask >> exp_shift1))
if s2 == 0 {
s2 = -1
}
s2 += bias + p
/* 1/2^s2 = (nextDouble(d) - d)/2 */
// JS_ASSERT(-s2 < e);
if -s2 >= e {
panic(fmt.Errorf("-s2 >= e: %d, %d", -s2, e))
}
mlo := big.NewInt(1)
mhi := mlo
if (word1 == 0) && ((word0 & bndry_mask) == 0) && ((word0 & (exp_mask & (exp_mask << 1))) != 0) {
/* The special case. Here we want to be within a quarter of the last input
significant digit instead of one half of it when the output string's value is less than d. */
s2 += log2P
mhi = big.NewInt(1 << log2P)
}
b := new(big.Int).SetBytes(dblBits)
b.Lsh(b, uint(e+s2))
s := big.NewInt(1)
s.Lsh(s, uint(s2))
/* At this point we have the following:
* s = 2^s2;
* 1 > df = b/2^s2 > 0;
* (d - prevDouble(d))/2 = mlo/2^s2;
* (nextDouble(d) - d)/2 = mhi/2^s2. */
bigBase := big.NewInt(int64(radix))
done := false
m := &big.Int{}
delta := &big.Int{}
for !done {
b.Mul(b, bigBase)
b.DivMod(b, s, m)
digit := byte(b.Int64())
b, m = m, b
mlo.Mul(mlo, bigBase)
if mlo != mhi {
mhi.Mul(mhi, bigBase)
}
/* Do we yet have the shortest string that will round to d? */
j := b.Cmp(mlo)
/* j is b/2^s2 compared with mlo/2^s2. */
delta.Sub(s, mhi)
var j1 int
if delta.Sign() <= 0 {
j1 = 1
} else {
j1 = b.Cmp(delta)
}
/* j1 is b/2^s2 compared with 1 - mhi/2^s2. */
if j1 == 0 && (word1&1) == 0 {
if j > 0 {
digit++
}
done = true
} else if j < 0 || (j == 0 && ((word1 & 1) == 0)) {
if j1 > 0 {
/* Either dig or dig+1 would work here as the least significant digit.
Use whichever would produce an output value closer to d. */
b.Lsh(b, 1)
j1 = b.Cmp(s)
if j1 > 0 { /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output such as 3.5 in base 3. */
digit++
}
}
done = true
} else if j1 > 0 {
digit++
done = true
}
// JS_ASSERT(digit < (uint32)base);
buffer.WriteByte(digits[digit])
}
return buffer.String()
}
}

147
server/vendor/github.com/dop251/goja/ftoa/ftostr.go generated vendored Normal file
View File

@@ -0,0 +1,147 @@
package ftoa
import (
"math"
"strconv"
"github.com/dop251/goja/ftoa/internal/fast"
)
type FToStrMode int
const (
// Either fixed or exponential format; round-trip
ModeStandard FToStrMode = iota
// Always exponential format; round-trip
ModeStandardExponential
// Round to <precision> digits after the decimal point; exponential if number is large
ModeFixed
// Always exponential format; <precision> significant digits
ModeExponential
// Either fixed or exponential format; <precision> significant digits
ModePrecision
)
func insert(b []byte, p int, c byte) []byte {
b = append(b, 0)
copy(b[p+1:], b[p:])
b[p] = c
return b
}
func expand(b []byte, delta int) []byte {
newLen := len(b) + delta
if newLen <= cap(b) {
return b[:newLen]
}
b1 := make([]byte, newLen)
copy(b1, b)
return b1
}
func FToStr(d float64, mode FToStrMode, precision int, buffer []byte) []byte {
if math.IsNaN(d) {
buffer = append(buffer, "NaN"...)
return buffer
}
if math.IsInf(d, 0) {
if math.Signbit(d) {
buffer = append(buffer, '-')
}
buffer = append(buffer, "Infinity"...)
return buffer
}
if mode == ModeFixed && (d >= 1e21 || d <= -1e21) {
mode = ModeStandard
}
var decPt int
var ok bool
startPos := len(buffer)
if d != 0 { // also matches -0
if d < 0 {
buffer = append(buffer, '-')
d = -d
startPos++
}
switch mode {
case ModeStandard, ModeStandardExponential:
buffer, decPt, ok = fast.Dtoa(d, fast.ModeShortest, 0, buffer)
case ModeExponential, ModePrecision:
buffer, decPt, ok = fast.Dtoa(d, fast.ModePrecision, precision, buffer)
}
} else {
buffer = append(buffer, '0')
decPt, ok = 1, true
}
if !ok {
buffer, decPt = ftoa(d, dtoaModes[mode], mode >= ModeFixed, precision, buffer)
}
exponentialNotation := false
minNDigits := 0 /* Minimum number of significand digits required by mode and precision */
nDigits := len(buffer) - startPos
switch mode {
case ModeStandard:
if decPt < -5 || decPt > 21 {
exponentialNotation = true
} else {
minNDigits = decPt
}
case ModeFixed:
if precision >= 0 {
minNDigits = decPt + precision
} else {
minNDigits = decPt
}
case ModeExponential:
// JS_ASSERT(precision > 0);
minNDigits = precision
fallthrough
case ModeStandardExponential:
exponentialNotation = true
case ModePrecision:
// JS_ASSERT(precision > 0);
minNDigits = precision
if decPt < -5 || decPt > precision {
exponentialNotation = true
}
}
for nDigits < minNDigits {
buffer = append(buffer, '0')
nDigits++
}
if exponentialNotation {
/* Insert a decimal point if more than one significand digit */
if nDigits != 1 {
buffer = insert(buffer, startPos+1, '.')
}
buffer = append(buffer, 'e')
if decPt-1 >= 0 {
buffer = append(buffer, '+')
}
buffer = strconv.AppendInt(buffer, int64(decPt-1), 10)
} else if decPt != nDigits {
/* Some kind of a fraction in fixed notation */
// JS_ASSERT(decPt <= nDigits);
if decPt > 0 {
/* dd...dd . dd...dd */
buffer = insert(buffer, startPos+decPt, '.')
} else {
/* 0 . 00...00dd...dd */
buffer = expand(buffer, 2-decPt)
copy(buffer[startPos+2-decPt:], buffer[startPos:])
buffer[startPos] = '0'
buffer[startPos+1] = '.'
for i := startPos + 2; i < startPos+2-decPt; i++ {
buffer[i] = '0'
}
}
}
return buffer
}

View File

@@ -0,0 +1,26 @@
Copyright 2014, the V8 project authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,120 @@
package fast
import "math"
const (
kCachedPowersOffset = 348 // -1 * the first decimal_exponent.
kD_1_LOG2_10 = 0.30102999566398114 // 1 / lg(10)
kDecimalExponentDistance = 8
)
type cachedPower struct {
significand uint64
binary_exponent int16
decimal_exponent int16
}
var (
cachedPowers = [...]cachedPower{
{0xFA8FD5A0081C0288, -1220, -348},
{0xBAAEE17FA23EBF76, -1193, -340},
{0x8B16FB203055AC76, -1166, -332},
{0xCF42894A5DCE35EA, -1140, -324},
{0x9A6BB0AA55653B2D, -1113, -316},
{0xE61ACF033D1A45DF, -1087, -308},
{0xAB70FE17C79AC6CA, -1060, -300},
{0xFF77B1FCBEBCDC4F, -1034, -292},
{0xBE5691EF416BD60C, -1007, -284},
{0x8DD01FAD907FFC3C, -980, -276},
{0xD3515C2831559A83, -954, -268},
{0x9D71AC8FADA6C9B5, -927, -260},
{0xEA9C227723EE8BCB, -901, -252},
{0xAECC49914078536D, -874, -244},
{0x823C12795DB6CE57, -847, -236},
{0xC21094364DFB5637, -821, -228},
{0x9096EA6F3848984F, -794, -220},
{0xD77485CB25823AC7, -768, -212},
{0xA086CFCD97BF97F4, -741, -204},
{0xEF340A98172AACE5, -715, -196},
{0xB23867FB2A35B28E, -688, -188},
{0x84C8D4DFD2C63F3B, -661, -180},
{0xC5DD44271AD3CDBA, -635, -172},
{0x936B9FCEBB25C996, -608, -164},
{0xDBAC6C247D62A584, -582, -156},
{0xA3AB66580D5FDAF6, -555, -148},
{0xF3E2F893DEC3F126, -529, -140},
{0xB5B5ADA8AAFF80B8, -502, -132},
{0x87625F056C7C4A8B, -475, -124},
{0xC9BCFF6034C13053, -449, -116},
{0x964E858C91BA2655, -422, -108},
{0xDFF9772470297EBD, -396, -100},
{0xA6DFBD9FB8E5B88F, -369, -92},
{0xF8A95FCF88747D94, -343, -84},
{0xB94470938FA89BCF, -316, -76},
{0x8A08F0F8BF0F156B, -289, -68},
{0xCDB02555653131B6, -263, -60},
{0x993FE2C6D07B7FAC, -236, -52},
{0xE45C10C42A2B3B06, -210, -44},
{0xAA242499697392D3, -183, -36},
{0xFD87B5F28300CA0E, -157, -28},
{0xBCE5086492111AEB, -130, -20},
{0x8CBCCC096F5088CC, -103, -12},
{0xD1B71758E219652C, -77, -4},
{0x9C40000000000000, -50, 4},
{0xE8D4A51000000000, -24, 12},
{0xAD78EBC5AC620000, 3, 20},
{0x813F3978F8940984, 30, 28},
{0xC097CE7BC90715B3, 56, 36},
{0x8F7E32CE7BEA5C70, 83, 44},
{0xD5D238A4ABE98068, 109, 52},
{0x9F4F2726179A2245, 136, 60},
{0xED63A231D4C4FB27, 162, 68},
{0xB0DE65388CC8ADA8, 189, 76},
{0x83C7088E1AAB65DB, 216, 84},
{0xC45D1DF942711D9A, 242, 92},
{0x924D692CA61BE758, 269, 100},
{0xDA01EE641A708DEA, 295, 108},
{0xA26DA3999AEF774A, 322, 116},
{0xF209787BB47D6B85, 348, 124},
{0xB454E4A179DD1877, 375, 132},
{0x865B86925B9BC5C2, 402, 140},
{0xC83553C5C8965D3D, 428, 148},
{0x952AB45CFA97A0B3, 455, 156},
{0xDE469FBD99A05FE3, 481, 164},
{0xA59BC234DB398C25, 508, 172},
{0xF6C69A72A3989F5C, 534, 180},
{0xB7DCBF5354E9BECE, 561, 188},
{0x88FCF317F22241E2, 588, 196},
{0xCC20CE9BD35C78A5, 614, 204},
{0x98165AF37B2153DF, 641, 212},
{0xE2A0B5DC971F303A, 667, 220},
{0xA8D9D1535CE3B396, 694, 228},
{0xFB9B7CD9A4A7443C, 720, 236},
{0xBB764C4CA7A44410, 747, 244},
{0x8BAB8EEFB6409C1A, 774, 252},
{0xD01FEF10A657842C, 800, 260},
{0x9B10A4E5E9913129, 827, 268},
{0xE7109BFBA19C0C9D, 853, 276},
{0xAC2820D9623BF429, 880, 284},
{0x80444B5E7AA7CF85, 907, 292},
{0xBF21E44003ACDD2D, 933, 300},
{0x8E679C2F5E44FF8F, 960, 308},
{0xD433179D9C8CB841, 986, 316},
{0x9E19DB92B4E31BA9, 1013, 324},
{0xEB96BF6EBADF77D9, 1039, 332},
{0xAF87023B9BF0EE6B, 1066, 340},
}
)
func getCachedPowerForBinaryExponentRange(min_exponent, max_exponent int) (power diyfp, decimal_exponent int) {
kQ := diyFpKSignificandSize
k := int(math.Ceil(float64(min_exponent+kQ-1) * kD_1_LOG2_10))
index := (kCachedPowersOffset+k-1)/kDecimalExponentDistance + 1
cached_power := cachedPowers[index]
_DCHECK(min_exponent <= int(cached_power.binary_exponent))
_DCHECK(int(cached_power.binary_exponent) <= max_exponent)
decimal_exponent = int(cached_power.decimal_exponent)
power = diyfp{f: cached_power.significand, e: int(cached_power.binary_exponent)}
return
}

View File

@@ -0,0 +1,18 @@
/*
Package fast contains code ported from V8 (https://github.com/v8/v8/blob/master/src/numbers/fast-dtoa.cc)
See LICENSE_V8 for the original copyright message and disclaimer.
*/
package fast
import "errors"
var (
dcheckFailure = errors.New("DCHECK assertion failed")
)
func _DCHECK(f bool) {
if !f {
panic(dcheckFailure)
}
}

View File

@@ -0,0 +1,152 @@
package fast
import "math"
const (
diyFpKSignificandSize = 64
kSignificandSize = 53
kUint64MSB uint64 = 1 << 63
kSignificandMask = 0x000FFFFFFFFFFFFF
kHiddenBit = 0x0010000000000000
kExponentMask = 0x7FF0000000000000
kPhysicalSignificandSize = 52 // Excludes the hidden bit.
kExponentBias = 0x3FF + kPhysicalSignificandSize
kDenormalExponent = -kExponentBias + 1
)
type double float64
type diyfp struct {
f uint64
e int
}
// f =- o.
// The exponents of both numbers must be the same and the significand of this
// must be bigger than the significand of other.
// The result will not be normalized.
func (f *diyfp) subtract(o diyfp) {
_DCHECK(f.e == o.e)
_DCHECK(f.f >= o.f)
f.f -= o.f
}
// Returns f - o
// The exponents of both numbers must be the same and this must be bigger
// than other. The result will not be normalized.
func (f diyfp) minus(o diyfp) diyfp {
res := f
res.subtract(o)
return res
}
// f *= o
func (f *diyfp) mul(o diyfp) {
// Simply "emulates" a 128 bit multiplication.
// However: the resulting number only contains 64 bits. The least
// significant 64 bits are only used for rounding the most significant 64
// bits.
const kM32 uint64 = 0xFFFFFFFF
a := f.f >> 32
b := f.f & kM32
c := o.f >> 32
d := o.f & kM32
ac := a * c
bc := b * c
ad := a * d
bd := b * d
tmp := (bd >> 32) + (ad & kM32) + (bc & kM32)
// By adding 1U << 31 to tmp we round the final result.
// Halfway cases will be round up.
tmp += 1 << 31
result_f := ac + (ad >> 32) + (bc >> 32) + (tmp >> 32)
f.e += o.e + 64
f.f = result_f
}
// Returns f * o
func (f diyfp) times(o diyfp) diyfp {
res := f
res.mul(o)
return res
}
func (f *diyfp) _normalize() {
f_, e := f.f, f.e
// This method is mainly called for normalizing boundaries. In general
// boundaries need to be shifted by 10 bits. We thus optimize for this case.
const k10MSBits uint64 = 0x3FF << 54
for f_&k10MSBits == 0 {
f_ <<= 10
e -= 10
}
for f_&kUint64MSB == 0 {
f_ <<= 1
e--
}
f.f, f.e = f_, e
}
func normalizeDiyfp(f diyfp) diyfp {
res := f
res._normalize()
return res
}
// f must be strictly greater than 0.
func (d double) toNormalizedDiyfp() diyfp {
f, e := d.sigExp()
// The current float could be a denormal.
for (f & kHiddenBit) == 0 {
f <<= 1
e--
}
// Do the final shifts in one go.
f <<= diyFpKSignificandSize - kSignificandSize
e -= diyFpKSignificandSize - kSignificandSize
return diyfp{f, e}
}
// Returns the two boundaries of this.
// The bigger boundary (m_plus) is normalized. The lower boundary has the same
// exponent as m_plus.
// Precondition: the value encoded by this Double must be greater than 0.
func (d double) normalizedBoundaries() (m_minus, m_plus diyfp) {
v := d.toDiyFp()
significand_is_zero := v.f == kHiddenBit
m_plus = normalizeDiyfp(diyfp{f: (v.f << 1) + 1, e: v.e - 1})
if significand_is_zero && v.e != kDenormalExponent {
// The boundary is closer. Think of v = 1000e10 and v- = 9999e9.
// Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
// at a distance of 1e8.
// The only exception is for the smallest normal: the largest denormal is
// at the same distance as its successor.
// Note: denormals have the same exponent as the smallest normals.
m_minus = diyfp{f: (v.f << 2) - 1, e: v.e - 2}
} else {
m_minus = diyfp{f: (v.f << 1) - 1, e: v.e - 1}
}
m_minus.f <<= m_minus.e - m_plus.e
m_minus.e = m_plus.e
return
}
func (d double) toDiyFp() diyfp {
f, e := d.sigExp()
return diyfp{f: f, e: e}
}
func (d double) sigExp() (significand uint64, exponent int) {
d64 := math.Float64bits(float64(d))
significand = d64 & kSignificandMask
if d64&kExponentMask != 0 { // not denormal
significand += kHiddenBit
exponent = int((d64&kExponentMask)>>kPhysicalSignificandSize) - kExponentBias
} else {
exponent = kDenormalExponent
}
return
}

View File

@@ -0,0 +1,642 @@
package fast
import (
"fmt"
"strconv"
)
const (
kMinimalTargetExponent = -60
kMaximalTargetExponent = -32
kTen4 = 10000
kTen5 = 100000
kTen6 = 1000000
kTen7 = 10000000
kTen8 = 100000000
kTen9 = 1000000000
)
type Mode int
const (
ModeShortest Mode = iota
ModePrecision
)
// Adjusts the last digit of the generated number, and screens out generated
// solutions that may be inaccurate. A solution may be inaccurate if it is
// outside the safe interval, or if we cannot prove that it is closer to the
// input than a neighboring representation of the same length.
//
// Input: * buffer containing the digits of too_high / 10^kappa
// - distance_too_high_w == (too_high - w).f() * unit
// - unsafe_interval == (too_high - too_low).f() * unit
// - rest = (too_high - buffer * 10^kappa).f() * unit
// - ten_kappa = 10^kappa * unit
// - unit = the common multiplier
//
// Output: returns true if the buffer is guaranteed to contain the closest
//
// representable number to the input.
// Modifies the generated digits in the buffer to approach (round towards) w.
func roundWeed(buffer []byte, distance_too_high_w, unsafe_interval, rest, ten_kappa, unit uint64) bool {
small_distance := distance_too_high_w - unit
big_distance := distance_too_high_w + unit
// Let w_low = too_high - big_distance, and
// w_high = too_high - small_distance.
// Note: w_low < w < w_high
//
// The real w (* unit) must lie somewhere inside the interval
// ]w_low; w_high[ (often written as "(w_low; w_high)")
// Basically the buffer currently contains a number in the unsafe interval
// ]too_low; too_high[ with too_low < w < too_high
//
// too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// ^v 1 unit ^ ^ ^ ^
// boundary_high --------------------- . . . .
// ^v 1 unit . . . .
// - - - - - - - - - - - - - - - - - - - + - - + - - - - - - . .
// . . ^ . .
// . big_distance . . .
// . . . . rest
// small_distance . . . .
// v . . . .
// w_high - - - - - - - - - - - - - - - - - - . . . .
// ^v 1 unit . . . .
// w ---------------------------------------- . . . .
// ^v 1 unit v . . .
// w_low - - - - - - - - - - - - - - - - - - - - - . . .
// . . v
// buffer --------------------------------------------------+-------+--------
// . .
// safe_interval .
// v .
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - .
// ^v 1 unit .
// boundary_low ------------------------- unsafe_interval
// ^v 1 unit v
// too_low - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
//
// Note that the value of buffer could lie anywhere inside the range too_low
// to too_high.
//
// boundary_low, boundary_high and w are approximations of the real boundaries
// and v (the input number). They are guaranteed to be precise up to one unit.
// In fact the error is guaranteed to be strictly less than one unit.
//
// Anything that lies outside the unsafe interval is guaranteed not to round
// to v when read again.
// Anything that lies inside the safe interval is guaranteed to round to v
// when read again.
// If the number inside the buffer lies inside the unsafe interval but not
// inside the safe interval then we simply do not know and bail out (returning
// false).
//
// Similarly we have to take into account the imprecision of 'w' when finding
// the closest representation of 'w'. If we have two potential
// representations, and one is closer to both w_low and w_high, then we know
// it is closer to the actual value v.
//
// By generating the digits of too_high we got the largest (closest to
// too_high) buffer that is still in the unsafe interval. In the case where
// w_high < buffer < too_high we try to decrement the buffer.
// This way the buffer approaches (rounds towards) w.
// There are 3 conditions that stop the decrementation process:
// 1) the buffer is already below w_high
// 2) decrementing the buffer would make it leave the unsafe interval
// 3) decrementing the buffer would yield a number below w_high and farther
// away than the current number. In other words:
// (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
// Instead of using the buffer directly we use its distance to too_high.
// Conceptually rest ~= too_high - buffer
// We need to do the following tests in this order to avoid over- and
// underflows.
_DCHECK(rest <= unsafe_interval)
for rest < small_distance && // Negated condition 1
unsafe_interval-rest >= ten_kappa && // Negated condition 2
(rest+ten_kappa < small_distance || // buffer{-1} > w_high
small_distance-rest >= rest+ten_kappa-small_distance) {
buffer[len(buffer)-1]--
rest += ten_kappa
}
// We have approached w+ as much as possible. We now test if approaching w-
// would require changing the buffer. If yes, then we have two possible
// representations close to w, but we cannot decide which one is closer.
if rest < big_distance && unsafe_interval-rest >= ten_kappa &&
(rest+ten_kappa < big_distance ||
big_distance-rest > rest+ten_kappa-big_distance) {
return false
}
// Weeding test.
// The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
// Since too_low = too_high - unsafe_interval this is equivalent to
// [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
// Conceptually we have: rest ~= too_high - buffer
return (2*unit <= rest) && (rest <= unsafe_interval-4*unit)
}
// Rounds the buffer upwards if the result is closer to v by possibly adding
// 1 to the buffer. If the precision of the calculation is not sufficient to
// round correctly, return false.
// The rounding might shift the whole buffer in which case the kappa is
// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
//
// If 2*rest > ten_kappa then the buffer needs to be round up.
// rest can have an error of +/- 1 unit. This function accounts for the
// imprecision and returns false, if the rounding direction cannot be
// unambiguously determined.
//
// Precondition: rest < ten_kappa.
func roundWeedCounted(buffer []byte, rest, ten_kappa, unit uint64, kappa *int) bool {
_DCHECK(rest < ten_kappa)
// The following tests are done in a specific order to avoid overflows. They
// will work correctly with any uint64 values of rest < ten_kappa and unit.
//
// If the unit is too big, then we don't know which way to round. For example
// a unit of 50 means that the real number lies within rest +/- 50. If
// 10^kappa == 40 then there is no way to tell which way to round.
if unit >= ten_kappa {
return false
}
// Even if unit is just half the size of 10^kappa we are already completely
// lost. (And after the previous test we know that the expression will not
// over/underflow.)
if ten_kappa-unit <= unit {
return false
}
// If 2 * (rest + unit) <= 10^kappa we can safely round down.
if (ten_kappa-rest > rest) && (ten_kappa-2*rest >= 2*unit) {
return true
}
// If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
if (rest > unit) && (ten_kappa-(rest-unit) <= (rest - unit)) {
// Increment the last digit recursively until we find a non '9' digit.
buffer[len(buffer)-1]++
for i := len(buffer) - 1; i > 0; i-- {
if buffer[i] != '0'+10 {
break
}
buffer[i] = '0'
buffer[i-1]++
}
// If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
// exception of the first digit all digits are now '0'. Simply switch the
// first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
// the power (the kappa) is increased.
if buffer[0] == '0'+10 {
buffer[0] = '1'
*kappa += 1
}
return true
}
return false
}
// Returns the biggest power of ten that is less than or equal than the given
// number. We furthermore receive the maximum number of bits 'number' has.
// If number_bits == 0 then 0^-1 is returned
// The number of bits must be <= 32.
// Precondition: number < (1 << (number_bits + 1)).
func biggestPowerTen(number uint32, number_bits int) (power uint32, exponent int) {
switch number_bits {
case 32, 31, 30:
if kTen9 <= number {
power = kTen9
exponent = 9
break
}
fallthrough
case 29, 28, 27:
if kTen8 <= number {
power = kTen8
exponent = 8
break
}
fallthrough
case 26, 25, 24:
if kTen7 <= number {
power = kTen7
exponent = 7
break
}
fallthrough
case 23, 22, 21, 20:
if kTen6 <= number {
power = kTen6
exponent = 6
break
}
fallthrough
case 19, 18, 17:
if kTen5 <= number {
power = kTen5
exponent = 5
break
}
fallthrough
case 16, 15, 14:
if kTen4 <= number {
power = kTen4
exponent = 4
break
}
fallthrough
case 13, 12, 11, 10:
if 1000 <= number {
power = 1000
exponent = 3
break
}
fallthrough
case 9, 8, 7:
if 100 <= number {
power = 100
exponent = 2
break
}
fallthrough
case 6, 5, 4:
if 10 <= number {
power = 10
exponent = 1
break
}
fallthrough
case 3, 2, 1:
if 1 <= number {
power = 1
exponent = 0
break
}
fallthrough
case 0:
power = 0
exponent = -1
}
return
}
// Generates the digits of input number w.
// w is a floating-point number (DiyFp), consisting of a significand and an
// exponent. Its exponent is bounded by kMinimalTargetExponent and
// kMaximalTargetExponent.
//
// Hence -60 <= w.e() <= -32.
//
// Returns false if it fails, in which case the generated digits in the buffer
// should not be used.
// Preconditions:
// - low, w and high are correct up to 1 ulp (unit in the last place). That
// is, their error must be less than a unit of their last digits.
// - low.e() == w.e() == high.e()
// - low < w < high, and taking into account their error: low~ <= high~
// - kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
//
// Postconditions: returns false if procedure fails.
//
// otherwise:
// * buffer is not null-terminated, but len contains the number of digits.
// * buffer contains the shortest possible decimal digit-sequence
// such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
// correct values of low and high (without their error).
// * if more than one decimal representation gives the minimal number of
// decimal digits then the one closest to W (where W is the correct value
// of w) is chosen.
//
// Remark: this procedure takes into account the imprecision of its input
//
// numbers. If the precision is not enough to guarantee all the postconditions
// then false is returned. This usually happens rarely (~0.5%).
//
// Say, for the sake of example, that
//
// w.e() == -48, and w.f() == 0x1234567890ABCDEF
//
// w's value can be computed by w.f() * 2^w.e()
// We can obtain w's integral digits by simply shifting w.f() by -w.e().
//
// -> w's integral part is 0x1234
// w's fractional part is therefore 0x567890ABCDEF.
//
// Printing w's integral part is easy (simply print 0x1234 in decimal).
// In order to print its fraction we repeatedly multiply the fraction by 10 and
// get each digit. Example the first digit after the point would be computed by
//
// (0x567890ABCDEF * 10) >> 48. -> 3
//
// The whole thing becomes slightly more complicated because we want to stop
// once we have enough digits. That is, once the digits inside the buffer
// represent 'w' we can stop. Everything inside the interval low - high
// represents w. However we have to pay attention to low, high and w's
// imprecision.
func digitGen(low, w, high diyfp, buffer []byte) (kappa int, buf []byte, res bool) {
_DCHECK(low.e == w.e && w.e == high.e)
_DCHECK(low.f+1 <= high.f-1)
_DCHECK(kMinimalTargetExponent <= w.e && w.e <= kMaximalTargetExponent)
// low, w and high are imprecise, but by less than one ulp (unit in the last
// place).
// If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
// the new numbers are outside of the interval we want the final
// representation to lie in.
// Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
// numbers that are certain to lie in the interval. We will use this fact
// later on.
// We will now start by generating the digits within the uncertain
// interval. Later we will weed out representations that lie outside the safe
// interval and thus _might_ lie outside the correct interval.
unit := uint64(1)
too_low := diyfp{f: low.f - unit, e: low.e}
too_high := diyfp{f: high.f + unit, e: high.e}
// too_low and too_high are guaranteed to lie outside the interval we want the
// generated number in.
unsafe_interval := too_high.minus(too_low)
// We now cut the input number into two parts: the integral digits and the
// fractionals. We will not write any decimal separator though, but adapt
// kappa instead.
// Reminder: we are currently computing the digits (stored inside the buffer)
// such that: too_low < buffer * 10^kappa < too_high
// We use too_high for the digit_generation and stop as soon as possible.
// If we stop early we effectively round down.
one := diyfp{f: 1 << -w.e, e: w.e}
// Division by one is a shift.
integrals := uint32(too_high.f >> -one.e)
// Modulo by one is an and.
fractionals := too_high.f & (one.f - 1)
divisor, divisor_exponent := biggestPowerTen(integrals, diyFpKSignificandSize-(-one.e))
kappa = divisor_exponent + 1
buf = buffer
for kappa > 0 {
digit := int(integrals / divisor)
buf = append(buf, byte('0'+digit))
integrals %= divisor
kappa--
// Note that kappa now equals the exponent of the divisor and that the
// invariant thus holds again.
rest := uint64(integrals)<<-one.e + fractionals
// Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e)
// Reminder: unsafe_interval.e == one.e
if rest < unsafe_interval.f {
// Rounding down (by not emitting the remaining digits) yields a number
// that lies within the unsafe interval.
res = roundWeed(buf, too_high.minus(w).f,
unsafe_interval.f, rest,
uint64(divisor)<<-one.e, unit)
return
}
divisor /= 10
}
// The integrals have been generated. We are at the point of the decimal
// separator. In the following loop we simply multiply the remaining digits by
// 10 and divide by one. We just need to pay attention to multiply associated
// data (like the interval or 'unit'), too.
// Note that the multiplication by 10 does not overflow, because w.e >= -60
// and thus one.e >= -60.
_DCHECK(one.e >= -60)
_DCHECK(fractionals < one.f)
_DCHECK(0xFFFFFFFFFFFFFFFF/10 >= one.f)
for {
fractionals *= 10
unit *= 10
unsafe_interval.f *= 10
// Integer division by one.
digit := byte(fractionals >> -one.e)
buf = append(buf, '0'+digit)
fractionals &= one.f - 1 // Modulo by one.
kappa--
if fractionals < unsafe_interval.f {
res = roundWeed(buf, too_high.minus(w).f*unit, unsafe_interval.f, fractionals, one.f, unit)
return
}
}
}
// Generates (at most) requested_digits of input number w.
// w is a floating-point number (DiyFp), consisting of a significand and an
// exponent. Its exponent is bounded by kMinimalTargetExponent and
// kMaximalTargetExponent.
//
// Hence -60 <= w.e() <= -32.
//
// Returns false if it fails, in which case the generated digits in the buffer
// should not be used.
// Preconditions:
// - w is correct up to 1 ulp (unit in the last place). That
// is, its error must be strictly less than a unit of its last digit.
// - kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
//
// Postconditions: returns false if procedure fails.
//
// otherwise:
// * buffer is not null-terminated, but length contains the number of
// digits.
// * the representation in buffer is the most precise representation of
// requested_digits digits.
// * buffer contains at most requested_digits digits of w. If there are less
// than requested_digits digits then some trailing '0's have been removed.
// * kappa is such that
// w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
//
// Remark: This procedure takes into account the imprecision of its input
//
// numbers. If the precision is not enough to guarantee all the postconditions
// then false is returned. This usually happens rarely, but the failure-rate
// increases with higher requested_digits.
func digitGenCounted(w diyfp, requested_digits int, buffer []byte) (kappa int, buf []byte, res bool) {
_DCHECK(kMinimalTargetExponent <= w.e && w.e <= kMaximalTargetExponent)
// w is assumed to have an error less than 1 unit. Whenever w is scaled we
// also scale its error.
w_error := uint64(1)
// We cut the input number into two parts: the integral digits and the
// fractional digits. We don't emit any decimal separator, but adapt kappa
// instead. Example: instead of writing "1.2" we put "12" into the buffer and
// increase kappa by 1.
one := diyfp{f: 1 << -w.e, e: w.e}
// Division by one is a shift.
integrals := uint32(w.f >> -one.e)
// Modulo by one is an and.
fractionals := w.f & (one.f - 1)
divisor, divisor_exponent := biggestPowerTen(integrals, diyFpKSignificandSize-(-one.e))
kappa = divisor_exponent + 1
buf = buffer
// Loop invariant: buffer = w / 10^kappa (integer division)
// The invariant holds for the first iteration: kappa has been initialized
// with the divisor exponent + 1. And the divisor is the biggest power of ten
// that is smaller than 'integrals'.
for kappa > 0 {
digit := byte(integrals / divisor)
buf = append(buf, '0'+digit)
requested_digits--
integrals %= divisor
kappa--
// Note that kappa now equals the exponent of the divisor and that the
// invariant thus holds again.
if requested_digits == 0 {
break
}
divisor /= 10
}
if requested_digits == 0 {
rest := uint64(integrals)<<-one.e + fractionals
res = roundWeedCounted(buf, rest, uint64(divisor)<<-one.e, w_error, &kappa)
return
}
// The integrals have been generated. We are at the point of the decimal
// separator. In the following loop we simply multiply the remaining digits by
// 10 and divide by one. We just need to pay attention to multiply associated
// data (the 'unit'), too.
// Note that the multiplication by 10 does not overflow, because w.e >= -60
// and thus one.e >= -60.
_DCHECK(one.e >= -60)
_DCHECK(fractionals < one.f)
_DCHECK(0xFFFFFFFFFFFFFFFF/10 >= one.f)
for requested_digits > 0 && fractionals > w_error {
fractionals *= 10
w_error *= 10
// Integer division by one.
digit := byte(fractionals >> -one.e)
buf = append(buf, '0'+digit)
requested_digits--
fractionals &= one.f - 1 // Modulo by one.
kappa--
}
if requested_digits != 0 {
res = false
} else {
res = roundWeedCounted(buf, fractionals, one.f, w_error, &kappa)
}
return
}
// Provides a decimal representation of v.
// Returns true if it succeeds, otherwise the result cannot be trusted.
// There will be *length digits inside the buffer (not null-terminated).
// If the function returns true then
//
// v == (double) (buffer * 10^decimal_exponent).
//
// The digits in the buffer are the shortest representation possible: no
// 0.09999999999999999 instead of 0.1. The shorter representation will even be
// chosen even if the longer one would be closer to v.
// The last digit will be closest to the actual v. That is, even if several
// digits might correctly yield 'v' when read again, the closest will be
// computed.
func grisu3(f float64, buffer []byte) (digits []byte, decimal_exponent int, result bool) {
v := double(f)
w := v.toNormalizedDiyfp()
// boundary_minus and boundary_plus are the boundaries between v and its
// closest floating-point neighbors. Any number strictly between
// boundary_minus and boundary_plus will round to v when convert to a double.
// Grisu3 will never output representations that lie exactly on a boundary.
boundary_minus, boundary_plus := v.normalizedBoundaries()
ten_mk_minimal_binary_exponent := kMinimalTargetExponent - (w.e + diyFpKSignificandSize)
ten_mk_maximal_binary_exponent := kMaximalTargetExponent - (w.e + diyFpKSignificandSize)
ten_mk, mk := getCachedPowerForBinaryExponentRange(ten_mk_minimal_binary_exponent, ten_mk_maximal_binary_exponent)
_DCHECK(
(kMinimalTargetExponent <=
w.e+ten_mk.e+diyFpKSignificandSize) &&
(kMaximalTargetExponent >= w.e+ten_mk.e+diyFpKSignificandSize))
// Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
// 64 bit significand and ten_mk is thus only precise up to 64 bits.
// The DiyFp::Times procedure rounds its result, and ten_mk is approximated
// too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
// off by a small amount.
// In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
// In other words: let f = scaled_w.f() and e = scaled_w.e(), then
// (f-1) * 2^e < w*10^k < (f+1) * 2^e
scaled_w := w.times(ten_mk)
_DCHECK(scaled_w.e ==
boundary_plus.e+ten_mk.e+diyFpKSignificandSize)
// In theory it would be possible to avoid some recomputations by computing
// the difference between w and boundary_minus/plus (a power of 2) and to
// compute scaled_boundary_minus/plus by subtracting/adding from
// scaled_w. However the code becomes much less readable and the speed
// enhancements are not terrific.
scaled_boundary_minus := boundary_minus.times(ten_mk)
scaled_boundary_plus := boundary_plus.times(ten_mk)
// DigitGen will generate the digits of scaled_w. Therefore we have
// v == (double) (scaled_w * 10^-mk).
// Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
// integer than it will be updated. For instance if scaled_w == 1.23 then
// the buffer will be filled with "123" und the decimal_exponent will be
// decreased by 2.
var kappa int
kappa, digits, result = digitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus, buffer)
decimal_exponent = -mk + kappa
return
}
// The "counted" version of grisu3 (see above) only generates requested_digits
// number of digits. This version does not generate the shortest representation,
// and with enough requested digits 0.1 will at some point print as 0.9999999...
// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
// therefore the rounding strategy for halfway cases is irrelevant.
func grisu3Counted(v float64, requested_digits int, buffer []byte) (digits []byte, decimal_exponent int, result bool) {
w := double(v).toNormalizedDiyfp()
ten_mk_minimal_binary_exponent := kMinimalTargetExponent - (w.e + diyFpKSignificandSize)
ten_mk_maximal_binary_exponent := kMaximalTargetExponent - (w.e + diyFpKSignificandSize)
ten_mk, mk := getCachedPowerForBinaryExponentRange(ten_mk_minimal_binary_exponent, ten_mk_maximal_binary_exponent)
_DCHECK(
(kMinimalTargetExponent <=
w.e+ten_mk.e+diyFpKSignificandSize) &&
(kMaximalTargetExponent >= w.e+ten_mk.e+diyFpKSignificandSize))
// Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
// 64 bit significand and ten_mk is thus only precise up to 64 bits.
// The DiyFp::Times procedure rounds its result, and ten_mk is approximated
// too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
// off by a small amount.
// In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
// In other words: let f = scaled_w.f() and e = scaled_w.e(), then
// (f-1) * 2^e < w*10^k < (f+1) * 2^e
scaled_w := w.times(ten_mk)
// We now have (double) (scaled_w * 10^-mk).
// DigitGen will generate the first requested_digits digits of scaled_w and
// return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
// will not always be exactly the same since DigitGenCounted only produces a
// limited number of digits.)
var kappa int
kappa, digits, result = digitGenCounted(scaled_w, requested_digits, buffer)
decimal_exponent = -mk + kappa
return
}
// v must be > 0 and must not be Inf or NaN
func Dtoa(v float64, mode Mode, requested_digits int, buffer []byte) (digits []byte, decimal_point int, result bool) {
defer func() {
if x := recover(); x != nil {
if x == dcheckFailure {
panic(fmt.Errorf("DCHECK assertion failed while formatting %s in mode %d", strconv.FormatFloat(v, 'e', 50, 64), mode))
}
panic(x)
}
}()
var decimal_exponent int
startPos := len(buffer)
switch mode {
case ModeShortest:
digits, decimal_exponent, result = grisu3(v, buffer)
case ModePrecision:
digits, decimal_exponent, result = grisu3Counted(v, requested_digits, buffer)
}
if result {
decimal_point = len(digits) - startPos + decimal_exponent
} else {
digits = digits[:startPos]
}
return
}

1101
server/vendor/github.com/dop251/goja/func.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

97
server/vendor/github.com/dop251/goja/ipow.go generated vendored Normal file
View File

@@ -0,0 +1,97 @@
package goja
// ported from https://gist.github.com/orlp/3551590
var highest_bit_set = [256]byte{
0, 1, 2, 2, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 255, // anything past 63 is a guaranteed overflow with base > 1
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255,
}
func ipow(base, exp int64) (result int64) {
result = 1
switch highest_bit_set[byte(exp)] {
case 255: // we use 255 as an overflow marker and return 0 on overflow/underflow
if base == 1 {
return 1
}
if base == -1 {
return 1 - 2*(exp&1)
}
return 0
case 6:
if exp&1 != 0 {
result *= base
}
exp >>= 1
base *= base
fallthrough
case 5:
if exp&1 != 0 {
result *= base
}
exp >>= 1
base *= base
fallthrough
case 4:
if exp&1 != 0 {
result *= base
}
exp >>= 1
base *= base
fallthrough
case 3:
if exp&1 != 0 {
result *= base
}
exp >>= 1
base *= base
fallthrough
case 2:
if exp&1 != 0 {
result *= base
}
exp >>= 1
base *= base
fallthrough
case 1:
if exp&1 != 0 {
result *= base
}
fallthrough
default:
return result
}
}

169
server/vendor/github.com/dop251/goja/map.go generated vendored Normal file
View File

@@ -0,0 +1,169 @@
package goja
import (
"hash/maphash"
)
type mapEntry struct {
key, value Value
iterPrev, iterNext *mapEntry
hNext *mapEntry
}
type orderedMap struct {
hash *maphash.Hash
hashTable map[uint64]*mapEntry
iterFirst, iterLast *mapEntry
size int
}
type orderedMapIter struct {
m *orderedMap
cur *mapEntry
}
func (m *orderedMap) lookup(key Value) (h uint64, entry, hPrev *mapEntry) {
if key == _negativeZero {
key = intToValue(0)
}
h = key.hash(m.hash)
for entry = m.hashTable[h]; entry != nil && !entry.key.SameAs(key); hPrev, entry = entry, entry.hNext {
}
return
}
func (m *orderedMap) set(key, value Value) {
h, entry, hPrev := m.lookup(key)
if entry != nil {
entry.value = value
} else {
if key == _negativeZero {
key = intToValue(0)
}
entry = &mapEntry{key: key, value: value}
if hPrev == nil {
m.hashTable[h] = entry
} else {
hPrev.hNext = entry
}
if m.iterLast != nil {
entry.iterPrev = m.iterLast
m.iterLast.iterNext = entry
} else {
m.iterFirst = entry
}
m.iterLast = entry
m.size++
}
}
func (m *orderedMap) get(key Value) Value {
_, entry, _ := m.lookup(key)
if entry != nil {
return entry.value
}
return nil
}
func (m *orderedMap) remove(key Value) bool {
h, entry, hPrev := m.lookup(key)
if entry != nil {
entry.key = nil
entry.value = nil
// remove from the doubly-linked list
if entry.iterPrev != nil {
entry.iterPrev.iterNext = entry.iterNext
} else {
m.iterFirst = entry.iterNext
}
if entry.iterNext != nil {
entry.iterNext.iterPrev = entry.iterPrev
} else {
m.iterLast = entry.iterPrev
}
// remove from the hashTable
if hPrev == nil {
if entry.hNext == nil {
delete(m.hashTable, h)
} else {
m.hashTable[h] = entry.hNext
}
} else {
hPrev.hNext = entry.hNext
}
m.size--
return true
}
return false
}
func (m *orderedMap) has(key Value) bool {
_, entry, _ := m.lookup(key)
return entry != nil
}
func (iter *orderedMapIter) next() *mapEntry {
if iter.m == nil {
// closed iterator
return nil
}
cur := iter.cur
// if the current item was deleted, track back to find the latest that wasn't
for cur != nil && cur.key == nil {
cur = cur.iterPrev
}
if cur != nil {
cur = cur.iterNext
} else {
cur = iter.m.iterFirst
}
if cur == nil {
iter.close()
} else {
iter.cur = cur
}
return cur
}
func (iter *orderedMapIter) close() {
iter.m = nil
iter.cur = nil
}
func newOrderedMap(h *maphash.Hash) *orderedMap {
return &orderedMap{
hash: h,
hashTable: make(map[uint64]*mapEntry),
}
}
func (m *orderedMap) newIter() *orderedMapIter {
iter := &orderedMapIter{
m: m,
}
return iter
}
func (m *orderedMap) clear() {
for item := m.iterFirst; item != nil; item = item.iterNext {
item.key = nil
item.value = nil
if item.iterPrev != nil {
item.iterPrev.iterNext = nil
}
}
m.iterFirst = nil
m.iterLast = nil
m.hashTable = make(map[uint64]*mapEntry)
m.size = 0
}

1843
server/vendor/github.com/dop251/goja/object.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

139
server/vendor/github.com/dop251/goja/object_args.go generated vendored Normal file
View File

@@ -0,0 +1,139 @@
package goja
import "github.com/dop251/goja/unistring"
type argumentsObject struct {
baseObject
length int
}
type mappedProperty struct {
valueProperty
v *Value
}
func (a *argumentsObject) getStr(name unistring.String, receiver Value) Value {
return a.getStrWithOwnProp(a.getOwnPropStr(name), name, receiver)
}
func (a *argumentsObject) getOwnPropStr(name unistring.String) Value {
if mapped, ok := a.values[name].(*mappedProperty); ok {
if mapped.writable && mapped.enumerable && mapped.configurable {
return *mapped.v
}
return &valueProperty{
value: *mapped.v,
writable: mapped.writable,
configurable: mapped.configurable,
enumerable: mapped.enumerable,
}
}
return a.baseObject.getOwnPropStr(name)
}
func (a *argumentsObject) init() {
a.baseObject.init()
a._putProp("length", intToValue(int64(a.length)), true, false, true)
}
func (a *argumentsObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
if prop, ok := a.values[name].(*mappedProperty); ok {
if !prop.writable {
a.val.runtime.typeErrorResult(throw, "Property is not writable: %s", name)
return false
}
*prop.v = val
return true
}
return a.baseObject.setOwnStr(name, val, throw)
}
func (a *argumentsObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return a._setForeignStr(name, a.getOwnPropStr(name), val, receiver, throw)
}
func (a *argumentsObject) deleteStr(name unistring.String, throw bool) bool {
if prop, ok := a.values[name].(*mappedProperty); ok {
if !a.checkDeleteProp(name, &prop.valueProperty, throw) {
return false
}
a._delete(name)
return true
}
return a.baseObject.deleteStr(name, throw)
}
type argumentsPropIter struct {
wrapped iterNextFunc
}
func (i *argumentsPropIter) next() (propIterItem, iterNextFunc) {
var item propIterItem
item, i.wrapped = i.wrapped()
if i.wrapped == nil {
return propIterItem{}, nil
}
if prop, ok := item.value.(*mappedProperty); ok {
item.value = *prop.v
}
return item, i.next
}
func (a *argumentsObject) iterateStringKeys() iterNextFunc {
return (&argumentsPropIter{
wrapped: a.baseObject.iterateStringKeys(),
}).next
}
func (a *argumentsObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if mapped, ok := a.values[name].(*mappedProperty); ok {
existing := &valueProperty{
configurable: mapped.configurable,
writable: true,
enumerable: mapped.enumerable,
value: *mapped.v,
}
val, ok := a.baseObject._defineOwnProperty(name, existing, descr, throw)
if !ok {
return false
}
if prop, ok := val.(*valueProperty); ok {
if !prop.accessor {
*mapped.v = prop.value
}
if prop.accessor || !prop.writable {
a._put(name, prop)
return true
}
mapped.configurable = prop.configurable
mapped.enumerable = prop.enumerable
} else {
*mapped.v = val
mapped.configurable = true
mapped.enumerable = true
}
return true
}
return a.baseObject.defineOwnPropertyStr(name, descr, throw)
}
func (a *argumentsObject) export(ctx *objectExportCtx) interface{} {
if v, exists := ctx.get(a.val); exists {
return v
}
arr := make([]interface{}, a.length)
ctx.put(a.val, arr)
for i := range arr {
v := a.getIdx(valueInt(int64(i)), nil)
if v != nil {
arr[i] = exportValue(v, ctx)
}
}
return arr
}

806
server/vendor/github.com/dop251/goja/object_dynamic.go generated vendored Normal file
View File

@@ -0,0 +1,806 @@
package goja
import (
"fmt"
"reflect"
"strconv"
"github.com/dop251/goja/unistring"
)
/*
DynamicObject is an interface representing a handler for a dynamic Object. Such an object can be created
using the Runtime.NewDynamicObject() method.
Note that Runtime.ToValue() does not have any special treatment for DynamicObject. The only way to create
a dynamic object is by using the Runtime.NewDynamicObject() method. This is done deliberately to avoid
silent code breaks when this interface changes.
*/
type DynamicObject interface {
// Get a property value for the key. May return nil if the property does not exist.
Get(key string) Value
// Set a property value for the key. Return true if success, false otherwise.
Set(key string, val Value) bool
// Has should return true if and only if the property exists.
Has(key string) bool
// Delete the property for the key. Returns true on success (note, that includes missing property).
Delete(key string) bool
// Keys returns a list of all existing property keys. There are no checks for duplicates or to make sure
// that the order conforms to https://262.ecma-international.org/#sec-ordinaryownpropertykeys
Keys() []string
}
/*
DynamicArray is an interface representing a handler for a dynamic array Object. Such an object can be created
using the Runtime.NewDynamicArray() method.
Any integer property key or a string property key that can be parsed into an int value (including negative
ones) is treated as an index and passed to the trap methods of the DynamicArray. Note this is different from
the regular ECMAScript arrays which only support positive indexes up to 2^32-1.
DynamicArray cannot be sparse, i.e. hasOwnProperty(num) will return true for num >= 0 && num < Len(). Deleting
such a property is equivalent to setting it to undefined. Note that this creates a slight peculiarity because
hasOwnProperty() will still return true, even after deletion.
Note that Runtime.ToValue() does not have any special treatment for DynamicArray. The only way to create
a dynamic array is by using the Runtime.NewDynamicArray() method. This is done deliberately to avoid
silent code breaks when this interface changes.
*/
type DynamicArray interface {
// Len returns the current array length.
Len() int
// Get an item at index idx. Note that idx may be any integer, negative or beyond the current length.
Get(idx int) Value
// Set an item at index idx. Note that idx may be any integer, negative or beyond the current length.
// The expected behaviour when it's beyond length is that the array's length is increased to accommodate
// the item. All elements in the 'new' section of the array should be zeroed.
Set(idx int, val Value) bool
// SetLen is called when the array's 'length' property is changed. If the length is increased all elements in the
// 'new' section of the array should be zeroed.
SetLen(int) bool
}
type baseDynamicObject struct {
val *Object
prototype *Object
}
type dynamicObject struct {
baseDynamicObject
d DynamicObject
}
type dynamicArray struct {
baseDynamicObject
a DynamicArray
}
/*
NewDynamicObject creates an Object backed by the provided DynamicObject handler.
All properties of this Object are Writable, Enumerable and Configurable data properties. Any attempt to define
a property that does not conform to this will fail.
The Object is always extensible and cannot be made non-extensible. Object.preventExtensions() will fail.
The Object's prototype is initially set to Object.prototype, but can be changed using regular mechanisms
(Object.SetPrototype() in Go or Object.setPrototypeOf() in JS).
The Object cannot have own Symbol properties, however its prototype can. If you need an iterator support for
example, you could create a regular object, set Symbol.iterator on that object and then use it as a
prototype. See TestDynamicObjectCustomProto for more details.
Export() returns the original DynamicObject.
This mechanism is similar to ECMAScript Proxy, however because all properties are enumerable and the object
is always extensible there is no need for invariant checks which removes the need to have a target object and
makes it a lot more efficient.
*/
func (r *Runtime) NewDynamicObject(d DynamicObject) *Object {
v := &Object{runtime: r}
o := &dynamicObject{
d: d,
baseDynamicObject: baseDynamicObject{
val: v,
prototype: r.global.ObjectPrototype,
},
}
v.self = o
return v
}
/*
NewSharedDynamicObject is similar to Runtime.NewDynamicObject but the resulting Object can be shared across multiple
Runtimes. The Object's prototype will be null. The provided DynamicObject must be goroutine-safe.
*/
func NewSharedDynamicObject(d DynamicObject) *Object {
v := &Object{}
o := &dynamicObject{
d: d,
baseDynamicObject: baseDynamicObject{
val: v,
},
}
v.self = o
return v
}
/*
NewDynamicArray creates an array Object backed by the provided DynamicArray handler.
It is similar to NewDynamicObject, the differences are:
- the Object is an array (i.e. Array.isArray() will return true and it will have the length property).
- the prototype will be initially set to Array.prototype.
- the Object cannot have any own string properties except for the 'length'.
*/
func (r *Runtime) NewDynamicArray(a DynamicArray) *Object {
v := &Object{runtime: r}
o := &dynamicArray{
a: a,
baseDynamicObject: baseDynamicObject{
val: v,
prototype: r.global.ArrayPrototype,
},
}
v.self = o
return v
}
/*
NewSharedDynamicArray is similar to Runtime.NewDynamicArray but the resulting Object can be shared across multiple
Runtimes. The Object's prototype will be null. If you need to run Array's methods on it, use Array.prototype.[...].call(a, ...).
The provided DynamicArray must be goroutine-safe.
*/
func NewSharedDynamicArray(a DynamicArray) *Object {
v := &Object{}
o := &dynamicArray{
a: a,
baseDynamicObject: baseDynamicObject{
val: v,
},
}
v.self = o
return v
}
func (*dynamicObject) sortLen() int {
return 0
}
func (*dynamicObject) sortGet(i int) Value {
return nil
}
func (*dynamicObject) swap(i int, i2 int) {
}
func (*dynamicObject) className() string {
return classObject
}
func (o *baseDynamicObject) getParentStr(p unistring.String, receiver Value) Value {
if proto := o.prototype; proto != nil {
if receiver == nil {
return proto.self.getStr(p, o.val)
}
return proto.self.getStr(p, receiver)
}
return nil
}
func (o *dynamicObject) getStr(p unistring.String, receiver Value) Value {
prop := o.d.Get(p.String())
if prop == nil {
return o.getParentStr(p, receiver)
}
return prop
}
func (o *baseDynamicObject) getParentIdx(p valueInt, receiver Value) Value {
if proto := o.prototype; proto != nil {
if receiver == nil {
return proto.self.getIdx(p, o.val)
}
return proto.self.getIdx(p, receiver)
}
return nil
}
func (o *dynamicObject) getIdx(p valueInt, receiver Value) Value {
prop := o.d.Get(p.String())
if prop == nil {
return o.getParentIdx(p, receiver)
}
return prop
}
func (o *baseDynamicObject) getSym(p *Symbol, receiver Value) Value {
if proto := o.prototype; proto != nil {
if receiver == nil {
return proto.self.getSym(p, o.val)
}
return proto.self.getSym(p, receiver)
}
return nil
}
func (o *dynamicObject) getOwnPropStr(u unistring.String) Value {
return o.d.Get(u.String())
}
func (o *dynamicObject) getOwnPropIdx(v valueInt) Value {
return o.d.Get(v.String())
}
func (*baseDynamicObject) getOwnPropSym(*Symbol) Value {
return nil
}
func (o *dynamicObject) _set(prop string, v Value, throw bool) bool {
if o.d.Set(prop, v) {
return true
}
typeErrorResult(throw, "'Set' on a dynamic object returned false")
return false
}
func (o *baseDynamicObject) _setSym(throw bool) {
typeErrorResult(throw, "Dynamic objects do not support Symbol properties")
}
func (o *dynamicObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
prop := p.String()
if !o.d.Has(prop) {
if proto := o.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, handled := proto.self.setForeignStr(p, v, o.val, throw); handled {
return res
}
}
}
return o._set(prop, v, throw)
}
func (o *dynamicObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
prop := p.String()
if !o.d.Has(prop) {
if proto := o.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, handled := proto.self.setForeignIdx(p, v, o.val, throw); handled {
return res
}
}
}
return o._set(prop, v, throw)
}
func (o *baseDynamicObject) setOwnSym(s *Symbol, v Value, throw bool) bool {
if proto := o.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, handled := proto.self.setForeignSym(s, v, o.val, throw); handled {
return res
}
}
o._setSym(throw)
return false
}
func (o *baseDynamicObject) setParentForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
if proto := o.prototype; proto != nil {
if receiver != proto {
return proto.self.setForeignStr(p, v, receiver, throw)
}
return proto.self.setOwnStr(p, v, throw), true
}
return false, false
}
func (o *dynamicObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
prop := p.String()
if !o.d.Has(prop) {
return o.setParentForeignStr(p, v, receiver, throw)
}
return false, false
}
func (o *baseDynamicObject) setParentForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
if proto := o.prototype; proto != nil {
if receiver != proto {
return proto.self.setForeignIdx(p, v, receiver, throw)
}
return proto.self.setOwnIdx(p, v, throw), true
}
return false, false
}
func (o *dynamicObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
prop := p.String()
if !o.d.Has(prop) {
return o.setParentForeignIdx(p, v, receiver, throw)
}
return false, false
}
func (o *baseDynamicObject) setForeignSym(p *Symbol, v, receiver Value, throw bool) (res bool, handled bool) {
if proto := o.prototype; proto != nil {
if receiver != proto {
return proto.self.setForeignSym(p, v, receiver, throw)
}
return proto.self.setOwnSym(p, v, throw), true
}
return false, false
}
func (o *dynamicObject) hasPropertyStr(u unistring.String) bool {
if o.hasOwnPropertyStr(u) {
return true
}
if proto := o.prototype; proto != nil {
return proto.self.hasPropertyStr(u)
}
return false
}
func (o *dynamicObject) hasPropertyIdx(idx valueInt) bool {
if o.hasOwnPropertyIdx(idx) {
return true
}
if proto := o.prototype; proto != nil {
return proto.self.hasPropertyIdx(idx)
}
return false
}
func (o *baseDynamicObject) hasPropertySym(s *Symbol) bool {
if proto := o.prototype; proto != nil {
return proto.self.hasPropertySym(s)
}
return false
}
func (o *dynamicObject) hasOwnPropertyStr(u unistring.String) bool {
return o.d.Has(u.String())
}
func (o *dynamicObject) hasOwnPropertyIdx(v valueInt) bool {
return o.d.Has(v.String())
}
func (*baseDynamicObject) hasOwnPropertySym(_ *Symbol) bool {
return false
}
func (o *baseDynamicObject) checkDynamicObjectPropertyDescr(name fmt.Stringer, descr PropertyDescriptor, throw bool) bool {
if descr.Getter != nil || descr.Setter != nil {
typeErrorResult(throw, "Dynamic objects do not support accessor properties")
return false
}
if descr.Writable == FLAG_FALSE {
typeErrorResult(throw, "Dynamic object field %q cannot be made read-only", name.String())
return false
}
if descr.Enumerable == FLAG_FALSE {
typeErrorResult(throw, "Dynamic object field %q cannot be made non-enumerable", name.String())
return false
}
if descr.Configurable == FLAG_FALSE {
typeErrorResult(throw, "Dynamic object field %q cannot be made non-configurable", name.String())
return false
}
return true
}
func (o *dynamicObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
return o._set(name.String(), desc.Value, throw)
}
return false
}
func (o *dynamicObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
if o.checkDynamicObjectPropertyDescr(name, desc, throw) {
return o._set(name.String(), desc.Value, throw)
}
return false
}
func (o *baseDynamicObject) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
o._setSym(throw)
return false
}
func (o *dynamicObject) _delete(prop string, throw bool) bool {
if o.d.Delete(prop) {
return true
}
typeErrorResult(throw, "Could not delete property %q of a dynamic object", prop)
return false
}
func (o *dynamicObject) deleteStr(name unistring.String, throw bool) bool {
return o._delete(name.String(), throw)
}
func (o *dynamicObject) deleteIdx(idx valueInt, throw bool) bool {
return o._delete(idx.String(), throw)
}
func (*baseDynamicObject) deleteSym(_ *Symbol, _ bool) bool {
return true
}
func (o *baseDynamicObject) toPrimitiveNumber() Value {
return o.val.genericToPrimitiveNumber()
}
func (o *baseDynamicObject) toPrimitiveString() Value {
return o.val.genericToPrimitiveString()
}
func (o *baseDynamicObject) toPrimitive() Value {
return o.val.genericToPrimitive()
}
func (o *baseDynamicObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
return nil, false
}
func (o *baseDynamicObject) vmCall(vm *vm, n int) {
panic(vm.r.NewTypeError("Dynamic object is not callable"))
}
func (*baseDynamicObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
return nil
}
func (o *baseDynamicObject) proto() *Object {
return o.prototype
}
func (o *baseDynamicObject) setProto(proto *Object, throw bool) bool {
o.prototype = proto
return true
}
func (o *baseDynamicObject) hasInstance(v Value) bool {
panic(newTypeError("Expecting a function in instanceof check, but got a dynamic object"))
}
func (*baseDynamicObject) isExtensible() bool {
return true
}
func (o *baseDynamicObject) preventExtensions(throw bool) bool {
typeErrorResult(throw, "Cannot make a dynamic object non-extensible")
return false
}
type dynamicObjectPropIter struct {
o *dynamicObject
propNames []string
idx int
}
func (i *dynamicObjectPropIter) next() (propIterItem, iterNextFunc) {
for i.idx < len(i.propNames) {
name := i.propNames[i.idx]
i.idx++
if i.o.d.Has(name) {
return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
}
}
return propIterItem{}, nil
}
func (o *dynamicObject) iterateStringKeys() iterNextFunc {
keys := o.d.Keys()
return (&dynamicObjectPropIter{
o: o,
propNames: keys,
}).next
}
func (o *baseDynamicObject) iterateSymbols() iterNextFunc {
return func() (propIterItem, iterNextFunc) {
return propIterItem{}, nil
}
}
func (o *dynamicObject) iterateKeys() iterNextFunc {
return o.iterateStringKeys()
}
func (o *dynamicObject) export(ctx *objectExportCtx) interface{} {
return o.d
}
func (o *dynamicObject) exportType() reflect.Type {
return reflect.TypeOf(o.d)
}
func (o *baseDynamicObject) exportToMap(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
return genericExportToMap(o.val, dst, typ, ctx)
}
func (o *baseDynamicObject) exportToArrayOrSlice(dst reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
return genericExportToArrayOrSlice(o.val, dst, typ, ctx)
}
func (o *dynamicObject) equal(impl objectImpl) bool {
if other, ok := impl.(*dynamicObject); ok {
return o.d == other.d
}
return false
}
func (o *dynamicObject) stringKeys(all bool, accum []Value) []Value {
keys := o.d.Keys()
if l := len(accum) + len(keys); l > cap(accum) {
oldAccum := accum
accum = make([]Value, len(accum), l)
copy(accum, oldAccum)
}
for _, key := range keys {
accum = append(accum, newStringValue(key))
}
return accum
}
func (*baseDynamicObject) symbols(all bool, accum []Value) []Value {
return accum
}
func (o *dynamicObject) keys(all bool, accum []Value) []Value {
return o.stringKeys(all, accum)
}
func (*baseDynamicObject) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
return nil
}
func (*baseDynamicObject) _putSym(s *Symbol, prop Value) {
}
func (o *baseDynamicObject) getPrivateEnv(*privateEnvType, bool) *privateElements {
panic(newTypeError("Dynamic objects cannot have private elements"))
}
func (o *baseDynamicObject) typeOf() valueString {
return stringObjectC
}
func (a *dynamicArray) sortLen() int {
return a.a.Len()
}
func (a *dynamicArray) sortGet(i int) Value {
return a.a.Get(i)
}
func (a *dynamicArray) swap(i int, j int) {
x := a.sortGet(i)
y := a.sortGet(j)
a.a.Set(int(i), y)
a.a.Set(int(j), x)
}
func (a *dynamicArray) className() string {
return classArray
}
func (a *dynamicArray) getStr(p unistring.String, receiver Value) Value {
if p == "length" {
return intToValue(int64(a.a.Len()))
}
if idx, ok := strToInt(p); ok {
return a.a.Get(idx)
}
return a.getParentStr(p, receiver)
}
func (a *dynamicArray) getIdx(p valueInt, receiver Value) Value {
if val := a.getOwnPropIdx(p); val != nil {
return val
}
return a.getParentIdx(p, receiver)
}
func (a *dynamicArray) getOwnPropStr(u unistring.String) Value {
if u == "length" {
return &valueProperty{
value: intToValue(int64(a.a.Len())),
writable: true,
}
}
if idx, ok := strToInt(u); ok {
return a.a.Get(idx)
}
return nil
}
func (a *dynamicArray) getOwnPropIdx(v valueInt) Value {
return a.a.Get(toIntStrict(int64(v)))
}
func (a *dynamicArray) _setLen(v Value, throw bool) bool {
if a.a.SetLen(toIntStrict(v.ToInteger())) {
return true
}
typeErrorResult(throw, "'SetLen' on a dynamic array returned false")
return false
}
func (a *dynamicArray) setOwnStr(p unistring.String, v Value, throw bool) bool {
if p == "length" {
return a._setLen(v, throw)
}
if idx, ok := strToInt(p); ok {
return a._setIdx(idx, v, throw)
}
typeErrorResult(throw, "Cannot set property %q on a dynamic array", p.String())
return false
}
func (a *dynamicArray) _setIdx(idx int, v Value, throw bool) bool {
if a.a.Set(idx, v) {
return true
}
typeErrorResult(throw, "'Set' on a dynamic array returned false")
return false
}
func (a *dynamicArray) setOwnIdx(p valueInt, v Value, throw bool) bool {
return a._setIdx(toIntStrict(int64(p)), v, throw)
}
func (a *dynamicArray) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
return a.setParentForeignStr(p, v, receiver, throw)
}
func (a *dynamicArray) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
return a.setParentForeignIdx(p, v, receiver, throw)
}
func (a *dynamicArray) hasPropertyStr(u unistring.String) bool {
if a.hasOwnPropertyStr(u) {
return true
}
if proto := a.prototype; proto != nil {
return proto.self.hasPropertyStr(u)
}
return false
}
func (a *dynamicArray) hasPropertyIdx(idx valueInt) bool {
if a.hasOwnPropertyIdx(idx) {
return true
}
if proto := a.prototype; proto != nil {
return proto.self.hasPropertyIdx(idx)
}
return false
}
func (a *dynamicArray) _has(idx int) bool {
return idx >= 0 && idx < a.a.Len()
}
func (a *dynamicArray) hasOwnPropertyStr(u unistring.String) bool {
if u == "length" {
return true
}
if idx, ok := strToInt(u); ok {
return a._has(idx)
}
return false
}
func (a *dynamicArray) hasOwnPropertyIdx(v valueInt) bool {
return a._has(toIntStrict(int64(v)))
}
func (a *dynamicArray) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
if idx, ok := strToInt(name); ok {
return a._setIdx(idx, desc.Value, throw)
}
typeErrorResult(throw, "Cannot define property %q on a dynamic array", name.String())
}
return false
}
func (a *dynamicArray) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
if a.checkDynamicObjectPropertyDescr(name, desc, throw) {
return a._setIdx(toIntStrict(int64(name)), desc.Value, throw)
}
return false
}
func (a *dynamicArray) _delete(idx int, throw bool) bool {
if a._has(idx) {
a._setIdx(idx, _undefined, throw)
}
return true
}
func (a *dynamicArray) deleteStr(name unistring.String, throw bool) bool {
if idx, ok := strToInt(name); ok {
return a._delete(idx, throw)
}
if a.hasOwnPropertyStr(name) {
typeErrorResult(throw, "Cannot delete property %q on a dynamic array", name.String())
return false
}
return true
}
func (a *dynamicArray) deleteIdx(idx valueInt, throw bool) bool {
return a._delete(toIntStrict(int64(idx)), throw)
}
type dynArrayPropIter struct {
a DynamicArray
idx, limit int
}
func (i *dynArrayPropIter) next() (propIterItem, iterNextFunc) {
if i.idx < i.limit && i.idx < i.a.Len() {
name := strconv.Itoa(i.idx)
i.idx++
return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
}
return propIterItem{}, nil
}
func (a *dynamicArray) iterateStringKeys() iterNextFunc {
return (&dynArrayPropIter{
a: a.a,
limit: a.a.Len(),
}).next
}
func (a *dynamicArray) iterateKeys() iterNextFunc {
return a.iterateStringKeys()
}
func (a *dynamicArray) export(ctx *objectExportCtx) interface{} {
return a.a
}
func (a *dynamicArray) exportType() reflect.Type {
return reflect.TypeOf(a.a)
}
func (a *dynamicArray) equal(impl objectImpl) bool {
if other, ok := impl.(*dynamicArray); ok {
return a == other
}
return false
}
func (a *dynamicArray) stringKeys(all bool, accum []Value) []Value {
al := a.a.Len()
l := len(accum) + al
if all {
l++
}
if l > cap(accum) {
oldAccum := accum
accum = make([]Value, len(oldAccum), l)
copy(accum, oldAccum)
}
for i := 0; i < al; i++ {
accum = append(accum, asciiString(strconv.Itoa(i)))
}
if all {
accum = append(accum, asciiString("length"))
}
return accum
}
func (a *dynamicArray) keys(all bool, accum []Value) []Value {
return a.stringKeys(all, accum)
}

View File

@@ -0,0 +1,356 @@
package goja
import (
"reflect"
"strconv"
"github.com/dop251/goja/unistring"
)
type objectGoArrayReflect struct {
objectGoReflect
lengthProp valueProperty
valueCache valueArrayCache
putIdx func(idx int, v Value, throw bool) bool
}
type valueArrayCache []reflectValueWrapper
func (c *valueArrayCache) get(idx int) reflectValueWrapper {
if idx < len(*c) {
return (*c)[idx]
}
return nil
}
func (c *valueArrayCache) grow(newlen int) {
oldcap := cap(*c)
if oldcap < newlen {
a := make([]reflectValueWrapper, newlen, growCap(newlen, len(*c), oldcap))
copy(a, *c)
*c = a
} else {
*c = (*c)[:newlen]
}
}
func (c *valueArrayCache) put(idx int, w reflectValueWrapper) {
if len(*c) <= idx {
c.grow(idx + 1)
}
(*c)[idx] = w
}
func (c *valueArrayCache) shrink(newlen int) {
if len(*c) > newlen {
tail := (*c)[newlen:]
for i, item := range tail {
if item != nil {
copyReflectValueWrapper(item)
tail[i] = nil
}
}
*c = (*c)[:newlen]
}
}
func (o *objectGoArrayReflect) _init() {
o.objectGoReflect.init()
o.class = classArray
o.prototype = o.val.runtime.global.ArrayPrototype
o.updateLen()
o.baseObject._put("length", &o.lengthProp)
}
func (o *objectGoArrayReflect) init() {
o._init()
o.putIdx = o._putIdx
}
func (o *objectGoArrayReflect) updateLen() {
o.lengthProp.value = intToValue(int64(o.fieldsValue.Len()))
}
func (o *objectGoArrayReflect) _hasIdx(idx valueInt) bool {
if idx := int64(idx); idx >= 0 && idx < int64(o.fieldsValue.Len()) {
return true
}
return false
}
func (o *objectGoArrayReflect) _hasStr(name unistring.String) bool {
if idx := strToIdx64(name); idx >= 0 && idx < int64(o.fieldsValue.Len()) {
return true
}
return false
}
func (o *objectGoArrayReflect) _getIdx(idx int) Value {
if v := o.valueCache.get(idx); v != nil {
return v.esValue()
}
v := o.fieldsValue.Index(idx)
res, w := o.elemToValue(v)
if w != nil {
o.valueCache.put(idx, w)
}
return res
}
func (o *objectGoArrayReflect) getIdx(idx valueInt, receiver Value) Value {
if idx := toIntStrict(int64(idx)); idx >= 0 && idx < o.fieldsValue.Len() {
return o._getIdx(idx)
}
return o.objectGoReflect.getStr(idx.string(), receiver)
}
func (o *objectGoArrayReflect) getStr(name unistring.String, receiver Value) Value {
var ownProp Value
if idx := strToGoIdx(name); idx >= 0 && idx < o.fieldsValue.Len() {
ownProp = o._getIdx(idx)
} else if name == "length" {
ownProp = &o.lengthProp
} else {
ownProp = o.objectGoReflect.getOwnPropStr(name)
}
return o.getStrWithOwnProp(ownProp, name, receiver)
}
func (o *objectGoArrayReflect) getOwnPropStr(name unistring.String) Value {
if idx := strToGoIdx(name); idx >= 0 {
if idx < o.fieldsValue.Len() {
return &valueProperty{
value: o._getIdx(idx),
writable: true,
enumerable: true,
}
}
return nil
}
if name == "length" {
return &o.lengthProp
}
return o.objectGoReflect.getOwnPropStr(name)
}
func (o *objectGoArrayReflect) getOwnPropIdx(idx valueInt) Value {
if idx := toIntStrict(int64(idx)); idx >= 0 && idx < o.fieldsValue.Len() {
return &valueProperty{
value: o._getIdx(idx),
writable: true,
enumerable: true,
}
}
return nil
}
func (o *objectGoArrayReflect) _putIdx(idx int, v Value, throw bool) bool {
cached := o.valueCache.get(idx)
if cached != nil {
copyReflectValueWrapper(cached)
}
rv := o.fieldsValue.Index(idx)
err := o.val.runtime.toReflectValue(v, rv, &objectExportCtx{})
if err != nil {
if cached != nil {
cached.setReflectValue(rv)
}
o.val.runtime.typeErrorResult(throw, "Go type conversion error: %v", err)
return false
}
if cached != nil {
o.valueCache[idx] = nil
}
return true
}
func (o *objectGoArrayReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool {
if i := toIntStrict(int64(idx)); i >= 0 {
if i >= o.fieldsValue.Len() {
if res, ok := o._setForeignIdx(idx, nil, val, o.val, throw); ok {
return res
}
}
return o.putIdx(i, val, throw)
} else {
name := idx.string()
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
return false
} else {
return res
}
}
}
func (o *objectGoArrayReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
if idx := strToGoIdx(name); idx >= 0 {
if idx >= o.fieldsValue.Len() {
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); ok {
return res
}
}
return o.putIdx(idx, val, throw)
} else {
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
return false
} else {
return res
}
}
}
func (o *objectGoArrayReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignIdx(idx, trueValIfPresent(o._hasIdx(idx)), val, receiver, throw)
}
func (o *objectGoArrayReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
}
func (o *objectGoArrayReflect) hasOwnPropertyIdx(idx valueInt) bool {
return o._hasIdx(idx)
}
func (o *objectGoArrayReflect) hasOwnPropertyStr(name unistring.String) bool {
if o._hasStr(name) || name == "length" {
return true
}
return o.objectGoReflect._has(name.String())
}
func (o *objectGoArrayReflect) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
if i := toIntStrict(int64(idx)); i >= 0 {
if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
return false
}
val := descr.Value
if val == nil {
val = _undefined
}
return o.putIdx(i, val, throw)
}
o.val.runtime.typeErrorResult(throw, "Cannot define property '%d' on a Go slice", idx)
return false
}
func (o *objectGoArrayReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if idx := strToGoIdx(name); idx >= 0 {
if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
return false
}
val := descr.Value
if val == nil {
val = _undefined
}
return o.putIdx(idx, val, throw)
}
o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a Go slice", name)
return false
}
func (o *objectGoArrayReflect) toPrimitive() Value {
return o.toPrimitiveString()
}
func (o *objectGoArrayReflect) _deleteIdx(idx int) {
if idx < o.fieldsValue.Len() {
if cv := o.valueCache.get(idx); cv != nil {
copyReflectValueWrapper(cv)
o.valueCache[idx] = nil
}
o.fieldsValue.Index(idx).Set(reflect.Zero(o.fieldsValue.Type().Elem()))
}
}
func (o *objectGoArrayReflect) deleteStr(name unistring.String, throw bool) bool {
if idx := strToGoIdx(name); idx >= 0 {
o._deleteIdx(idx)
return true
}
return o.objectGoReflect.deleteStr(name, throw)
}
func (o *objectGoArrayReflect) deleteIdx(i valueInt, throw bool) bool {
idx := toIntStrict(int64(i))
if idx >= 0 {
o._deleteIdx(idx)
}
return true
}
type goArrayReflectPropIter struct {
o *objectGoArrayReflect
idx, limit int
}
func (i *goArrayReflectPropIter) next() (propIterItem, iterNextFunc) {
if i.idx < i.limit && i.idx < i.o.fieldsValue.Len() {
name := strconv.Itoa(i.idx)
i.idx++
return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
}
return i.o.objectGoReflect.iterateStringKeys()()
}
func (o *objectGoArrayReflect) stringKeys(all bool, accum []Value) []Value {
for i := 0; i < o.fieldsValue.Len(); i++ {
accum = append(accum, asciiString(strconv.Itoa(i)))
}
return o.objectGoReflect.stringKeys(all, accum)
}
func (o *objectGoArrayReflect) iterateStringKeys() iterNextFunc {
return (&goArrayReflectPropIter{
o: o,
limit: o.fieldsValue.Len(),
}).next
}
func (o *objectGoArrayReflect) sortLen() int {
return o.fieldsValue.Len()
}
func (o *objectGoArrayReflect) sortGet(i int) Value {
return o.getIdx(valueInt(i), nil)
}
func (o *objectGoArrayReflect) swap(i int, j int) {
vi := o.fieldsValue.Index(i)
vj := o.fieldsValue.Index(j)
tmp := reflect.New(o.fieldsValue.Type().Elem()).Elem()
tmp.Set(vi)
vi.Set(vj)
vj.Set(tmp)
cachedI := o.valueCache.get(i)
cachedJ := o.valueCache.get(j)
if cachedI != nil {
cachedI.setReflectValue(vj)
o.valueCache.put(j, cachedI)
} else {
if j < len(o.valueCache) {
o.valueCache[j] = nil
}
}
if cachedJ != nil {
cachedJ.setReflectValue(vi)
o.valueCache.put(i, cachedJ)
} else {
if i < len(o.valueCache) {
o.valueCache[i] = nil
}
}
}

176
server/vendor/github.com/dop251/goja/object_gomap.go generated vendored Normal file
View File

@@ -0,0 +1,176 @@
package goja
import (
"reflect"
"github.com/dop251/goja/unistring"
)
type objectGoMapSimple struct {
baseObject
data map[string]interface{}
}
func (o *objectGoMapSimple) init() {
o.baseObject.init()
o.prototype = o.val.runtime.global.ObjectPrototype
o.class = classObject
o.extensible = true
}
func (o *objectGoMapSimple) _getStr(name string) Value {
v, exists := o.data[name]
if !exists {
return nil
}
return o.val.runtime.ToValue(v)
}
func (o *objectGoMapSimple) getStr(name unistring.String, receiver Value) Value {
if v := o._getStr(name.String()); v != nil {
return v
}
return o.baseObject.getStr(name, receiver)
}
func (o *objectGoMapSimple) getOwnPropStr(name unistring.String) Value {
if v := o._getStr(name.String()); v != nil {
return v
}
return nil
}
func (o *objectGoMapSimple) setOwnStr(name unistring.String, val Value, throw bool) bool {
n := name.String()
if _, exists := o.data[n]; exists {
o.data[n] = val.Export()
return true
}
if proto := o.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok {
return res
}
}
// new property
if !o.extensible {
o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", name)
return false
} else {
o.data[n] = val.Export()
}
return true
}
func trueValIfPresent(present bool) Value {
if present {
return valueTrue
}
return nil
}
func (o *objectGoMapSimple) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignStr(name, trueValIfPresent(o._hasStr(name.String())), val, receiver, throw)
}
func (o *objectGoMapSimple) _hasStr(name string) bool {
_, exists := o.data[name]
return exists
}
func (o *objectGoMapSimple) hasOwnPropertyStr(name unistring.String) bool {
return o._hasStr(name.String())
}
func (o *objectGoMapSimple) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
return false
}
n := name.String()
if o.extensible || o._hasStr(n) {
o.data[n] = descr.Value.Export()
return true
}
o.val.runtime.typeErrorResult(throw, "Cannot define property %s, object is not extensible", n)
return false
}
/*
func (o *objectGoMapSimple) toPrimitiveNumber() Value {
return o.toPrimitiveString()
}
func (o *objectGoMapSimple) toPrimitiveString() Value {
return stringObjectObject
}
func (o *objectGoMapSimple) toPrimitive() Value {
return o.toPrimitiveString()
}
func (o *objectGoMapSimple) assertCallable() (call func(FunctionCall) Value, ok bool) {
return nil, false
}
*/
func (o *objectGoMapSimple) deleteStr(name unistring.String, _ bool) bool {
delete(o.data, name.String())
return true
}
type gomapPropIter struct {
o *objectGoMapSimple
propNames []string
idx int
}
func (i *gomapPropIter) next() (propIterItem, iterNextFunc) {
for i.idx < len(i.propNames) {
name := i.propNames[i.idx]
i.idx++
if _, exists := i.o.data[name]; exists {
return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
}
}
return propIterItem{}, nil
}
func (o *objectGoMapSimple) iterateStringKeys() iterNextFunc {
propNames := make([]string, len(o.data))
i := 0
for key := range o.data {
propNames[i] = key
i++
}
return (&gomapPropIter{
o: o,
propNames: propNames,
}).next
}
func (o *objectGoMapSimple) stringKeys(_ bool, accum []Value) []Value {
// all own keys are enumerable
for key := range o.data {
accum = append(accum, newStringValue(key))
}
return accum
}
func (o *objectGoMapSimple) export(*objectExportCtx) interface{} {
return o.data
}
func (o *objectGoMapSimple) exportType() reflect.Type {
return reflectTypeMap
}
func (o *objectGoMapSimple) equal(other objectImpl) bool {
if other, ok := other.(*objectGoMapSimple); ok {
return o == other
}
return false
}

View File

@@ -0,0 +1,265 @@
package goja
import (
"reflect"
"github.com/dop251/goja/unistring"
)
type objectGoMapReflect struct {
objectGoReflect
keyType, valueType reflect.Type
}
func (o *objectGoMapReflect) init() {
o.objectGoReflect.init()
o.keyType = o.fieldsValue.Type().Key()
o.valueType = o.fieldsValue.Type().Elem()
}
func (o *objectGoMapReflect) toKey(n Value, throw bool) reflect.Value {
key := reflect.New(o.keyType).Elem()
err := o.val.runtime.toReflectValue(n, key, &objectExportCtx{})
if err != nil {
o.val.runtime.typeErrorResult(throw, "map key conversion error: %v", err)
return reflect.Value{}
}
return key
}
func (o *objectGoMapReflect) strToKey(name string, throw bool) reflect.Value {
if o.keyType.Kind() == reflect.String {
return reflect.ValueOf(name).Convert(o.keyType)
}
return o.toKey(newStringValue(name), throw)
}
func (o *objectGoMapReflect) _getKey(key reflect.Value) Value {
if !key.IsValid() {
return nil
}
if v := o.fieldsValue.MapIndex(key); v.IsValid() {
rv := v
if rv.Kind() == reflect.Interface {
rv = rv.Elem()
}
return o.val.runtime.toValue(v.Interface(), rv)
}
return nil
}
func (o *objectGoMapReflect) _get(n Value) Value {
return o._getKey(o.toKey(n, false))
}
func (o *objectGoMapReflect) _getStr(name string) Value {
return o._getKey(o.strToKey(name, false))
}
func (o *objectGoMapReflect) getStr(name unistring.String, receiver Value) Value {
if v := o._getStr(name.String()); v != nil {
return v
}
return o.objectGoReflect.getStr(name, receiver)
}
func (o *objectGoMapReflect) getIdx(idx valueInt, receiver Value) Value {
if v := o._get(idx); v != nil {
return v
}
return o.objectGoReflect.getIdx(idx, receiver)
}
func (o *objectGoMapReflect) getOwnPropStr(name unistring.String) Value {
if v := o._getStr(name.String()); v != nil {
return &valueProperty{
value: v,
writable: true,
enumerable: true,
}
}
return o.objectGoReflect.getOwnPropStr(name)
}
func (o *objectGoMapReflect) getOwnPropIdx(idx valueInt) Value {
if v := o._get(idx); v != nil {
return &valueProperty{
value: v,
writable: true,
enumerable: true,
}
}
return o.objectGoReflect.getOwnPropStr(idx.string())
}
func (o *objectGoMapReflect) toValue(val Value, throw bool) (reflect.Value, bool) {
v := reflect.New(o.valueType).Elem()
err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
if err != nil {
o.val.runtime.typeErrorResult(throw, "map value conversion error: %v", err)
return reflect.Value{}, false
}
return v, true
}
func (o *objectGoMapReflect) _put(key reflect.Value, val Value, throw bool) bool {
if key.IsValid() {
if o.extensible || o.fieldsValue.MapIndex(key).IsValid() {
v, ok := o.toValue(val, throw)
if !ok {
return false
}
o.fieldsValue.SetMapIndex(key, v)
} else {
o.val.runtime.typeErrorResult(throw, "Cannot set property %s, object is not extensible", key.String())
return false
}
return true
}
return false
}
func (o *objectGoMapReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
n := name.String()
key := o.strToKey(n, false)
if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() {
if proto := o.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok {
return res
}
}
// new property
if !o.extensible {
o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", n)
return false
} else {
if throw && !key.IsValid() {
o.strToKey(n, true)
return false
}
}
}
o._put(key, val, throw)
return true
}
func (o *objectGoMapReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool {
key := o.toKey(idx, false)
if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() {
if proto := o.prototype; proto != nil {
// we know it's foreign because prototype loops are not allowed
if res, ok := proto.self.setForeignIdx(idx, val, o.val, throw); ok {
return res
}
}
// new property
if !o.extensible {
o.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx)
return false
} else {
if throw && !key.IsValid() {
o.toKey(idx, true)
return false
}
}
}
o._put(key, val, throw)
return true
}
func (o *objectGoMapReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
}
func (o *objectGoMapReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw)
}
func (o *objectGoMapReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
return false
}
return o._put(o.strToKey(name.String(), throw), descr.Value, throw)
}
func (o *objectGoMapReflect) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
return false
}
return o._put(o.toKey(idx, throw), descr.Value, throw)
}
func (o *objectGoMapReflect) hasOwnPropertyStr(name unistring.String) bool {
key := o.strToKey(name.String(), false)
if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() {
return true
}
return false
}
func (o *objectGoMapReflect) hasOwnPropertyIdx(idx valueInt) bool {
key := o.toKey(idx, false)
if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() {
return true
}
return false
}
func (o *objectGoMapReflect) deleteStr(name unistring.String, throw bool) bool {
key := o.strToKey(name.String(), throw)
if !key.IsValid() {
return false
}
o.fieldsValue.SetMapIndex(key, reflect.Value{})
return true
}
func (o *objectGoMapReflect) deleteIdx(idx valueInt, throw bool) bool {
key := o.toKey(idx, throw)
if !key.IsValid() {
return false
}
o.fieldsValue.SetMapIndex(key, reflect.Value{})
return true
}
type gomapReflectPropIter struct {
o *objectGoMapReflect
keys []reflect.Value
idx int
}
func (i *gomapReflectPropIter) next() (propIterItem, iterNextFunc) {
for i.idx < len(i.keys) {
key := i.keys[i.idx]
v := i.o.fieldsValue.MapIndex(key)
i.idx++
if v.IsValid() {
return propIterItem{name: newStringValue(key.String()), enumerable: _ENUM_TRUE}, i.next
}
}
return propIterItem{}, nil
}
func (o *objectGoMapReflect) iterateStringKeys() iterNextFunc {
return (&gomapReflectPropIter{
o: o,
keys: o.fieldsValue.MapKeys(),
}).next
}
func (o *objectGoMapReflect) stringKeys(_ bool, accum []Value) []Value {
// all own keys are enumerable
for _, key := range o.fieldsValue.MapKeys() {
accum = append(accum, newStringValue(key.String()))
}
return accum
}

View File

@@ -0,0 +1,715 @@
package goja
import (
"fmt"
"go/ast"
"reflect"
"strings"
"github.com/dop251/goja/parser"
"github.com/dop251/goja/unistring"
)
// JsonEncodable allows custom JSON encoding by JSON.stringify()
// Note that if the returned value itself also implements JsonEncodable, it won't have any effect.
type JsonEncodable interface {
JsonEncodable() interface{}
}
// FieldNameMapper provides custom mapping between Go and JavaScript property names.
type FieldNameMapper interface {
// FieldName returns a JavaScript name for the given struct field in the given type.
// If this method returns "" the field becomes hidden.
FieldName(t reflect.Type, f reflect.StructField) string
// MethodName returns a JavaScript name for the given method in the given type.
// If this method returns "" the method becomes hidden.
MethodName(t reflect.Type, m reflect.Method) string
}
type tagFieldNameMapper struct {
tagName string
uncapMethods bool
}
func (tfm tagFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
tag := f.Tag.Get(tfm.tagName)
if idx := strings.IndexByte(tag, ','); idx != -1 {
tag = tag[:idx]
}
if parser.IsIdentifier(tag) {
return tag
}
return ""
}
func uncapitalize(s string) string {
return strings.ToLower(s[0:1]) + s[1:]
}
func (tfm tagFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
if tfm.uncapMethods {
return uncapitalize(m.Name)
}
return m.Name
}
type uncapFieldNameMapper struct {
}
func (u uncapFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
return uncapitalize(f.Name)
}
func (u uncapFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
return uncapitalize(m.Name)
}
type reflectFieldInfo struct {
Index []int
Anonymous bool
}
type reflectFieldsInfo struct {
Fields map[string]reflectFieldInfo
Names []string
}
type reflectMethodsInfo struct {
Methods map[string]int
Names []string
}
type reflectValueWrapper interface {
esValue() Value
reflectValue() reflect.Value
setReflectValue(reflect.Value)
}
func isContainer(k reflect.Kind) bool {
switch k {
case reflect.Struct, reflect.Slice, reflect.Array:
return true
}
return false
}
func copyReflectValueWrapper(w reflectValueWrapper) {
v := w.reflectValue()
c := reflect.New(v.Type()).Elem()
c.Set(v)
w.setReflectValue(c)
}
type objectGoReflect struct {
baseObject
origValue, fieldsValue reflect.Value
fieldsInfo *reflectFieldsInfo
methodsInfo *reflectMethodsInfo
methodsValue reflect.Value
valueCache map[string]reflectValueWrapper
toString, valueOf func() Value
toJson func() interface{}
}
func (o *objectGoReflect) init() {
o.baseObject.init()
switch o.fieldsValue.Kind() {
case reflect.Bool:
o.class = classBoolean
o.prototype = o.val.runtime.global.BooleanPrototype
o.toString = o._toStringBool
o.valueOf = o._valueOfBool
case reflect.String:
o.class = classString
o.prototype = o.val.runtime.global.StringPrototype
o.toString = o._toStringString
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
o.class = classNumber
o.prototype = o.val.runtime.global.NumberPrototype
o.valueOf = o._valueOfInt
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
o.class = classNumber
o.prototype = o.val.runtime.global.NumberPrototype
o.valueOf = o._valueOfUint
case reflect.Float32, reflect.Float64:
o.class = classNumber
o.prototype = o.val.runtime.global.NumberPrototype
o.valueOf = o._valueOfFloat
default:
o.class = classObject
o.prototype = o.val.runtime.global.ObjectPrototype
}
if o.fieldsValue.Kind() == reflect.Struct {
o.fieldsInfo = o.val.runtime.fieldsInfo(o.fieldsValue.Type())
}
var methodsType reflect.Type
// Always use pointer type for non-interface values to be able to access both methods defined on
// the literal type and on the pointer.
if o.fieldsValue.Kind() != reflect.Interface {
methodsType = reflect.PtrTo(o.fieldsValue.Type())
} else {
methodsType = o.fieldsValue.Type()
}
o.methodsInfo = o.val.runtime.methodsInfo(methodsType)
// Container values and values that have at least one method defined on the pointer type
// need to be addressable.
if !o.origValue.CanAddr() && (isContainer(o.origValue.Kind()) || len(o.methodsInfo.Names) > 0) {
value := reflect.New(o.origValue.Type()).Elem()
value.Set(o.origValue)
o.origValue = value
if value.Kind() != reflect.Ptr {
o.fieldsValue = value
}
}
o.extensible = true
switch o.origValue.Interface().(type) {
case fmt.Stringer:
o.toString = o._toStringStringer
case error:
o.toString = o._toStringError
}
if o.toString != nil || o.valueOf != nil {
o.baseObject._putProp("toString", o.val.runtime.newNativeFunc(o.toStringFunc, nil, "toString", nil, 0), true, false, true)
o.baseObject._putProp("valueOf", o.val.runtime.newNativeFunc(o.valueOfFunc, nil, "valueOf", nil, 0), true, false, true)
}
if len(o.methodsInfo.Names) > 0 && o.fieldsValue.Kind() != reflect.Interface {
o.methodsValue = o.fieldsValue.Addr()
} else {
o.methodsValue = o.fieldsValue
}
if j, ok := o.origValue.Interface().(JsonEncodable); ok {
o.toJson = j.JsonEncodable
}
}
func (o *objectGoReflect) toStringFunc(FunctionCall) Value {
return o.toPrimitiveString()
}
func (o *objectGoReflect) valueOfFunc(FunctionCall) Value {
return o.toPrimitiveNumber()
}
func (o *objectGoReflect) getStr(name unistring.String, receiver Value) Value {
if v := o._get(name.String()); v != nil {
return v
}
return o.baseObject.getStr(name, receiver)
}
func (o *objectGoReflect) _getField(jsName string) reflect.Value {
if o.fieldsInfo != nil {
if info, exists := o.fieldsInfo.Fields[jsName]; exists {
return o.fieldsValue.FieldByIndex(info.Index)
}
}
return reflect.Value{}
}
func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
if o.methodsInfo != nil {
if idx, exists := o.methodsInfo.Methods[jsName]; exists {
return o.methodsValue.Method(idx)
}
}
return reflect.Value{}
}
func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) {
if isContainer(ev.Kind()) {
ret := o.val.runtime.toValue(ev.Interface(), ev)
if obj, ok := ret.(*Object); ok {
if w, ok := obj.self.(reflectValueWrapper); ok {
return ret, w
}
}
return ret, nil
}
if ev.Kind() == reflect.Interface {
ev = ev.Elem()
}
if ev.Kind() == reflect.Invalid {
return _null, nil
}
return o.val.runtime.toValue(ev.Interface(), ev), nil
}
func (o *objectGoReflect) _getFieldValue(name string) Value {
if v := o.valueCache[name]; v != nil {
return v.esValue()
}
if v := o._getField(name); v.IsValid() {
res, w := o.elemToValue(v)
if w != nil {
if o.valueCache == nil {
o.valueCache = make(map[string]reflectValueWrapper)
}
o.valueCache[name] = w
}
return res
}
return nil
}
func (o *objectGoReflect) _get(name string) Value {
if o.fieldsValue.Kind() == reflect.Struct {
if ret := o._getFieldValue(name); ret != nil {
return ret
}
}
if v := o._getMethod(name); v.IsValid() {
return o.val.runtime.toValue(v.Interface(), v)
}
return nil
}
func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
n := name.String()
if o.fieldsValue.Kind() == reflect.Struct {
if v := o._getFieldValue(n); v != nil {
return &valueProperty{
value: v,
writable: true,
enumerable: true,
}
}
}
if v := o._getMethod(n); v.IsValid() {
return &valueProperty{
value: o.val.runtime.toValue(v.Interface(), v),
enumerable: true,
}
}
return nil
}
func (o *objectGoReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
has, ok := o._put(name.String(), val, throw)
if !has {
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
o.val.runtime.typeErrorResult(throw, "Cannot assign to property %s of a host object", name)
return false
} else {
return res
}
}
return ok
}
func (o *objectGoReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignStr(name, trueValIfPresent(o._has(name.String())), val, receiver, throw)
}
func (o *objectGoReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignIdx(idx, nil, val, receiver, throw)
}
func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
if o.fieldsValue.Kind() == reflect.Struct {
if v := o._getField(name); v.IsValid() {
cached := o.valueCache[name]
if cached != nil {
copyReflectValueWrapper(cached)
}
err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
if err != nil {
if cached != nil {
cached.setReflectValue(v)
}
o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
return true, false
}
if cached != nil {
delete(o.valueCache, name)
}
return true, true
}
}
return false, false
}
func (o *objectGoReflect) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
if _, ok := o._put(name.String(), value, false); ok {
return value
}
return o.baseObject._putProp(name, value, writable, enumerable, configurable)
}
func (r *Runtime) checkHostObjectPropertyDescr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if descr.Getter != nil || descr.Setter != nil {
r.typeErrorResult(throw, "Host objects do not support accessor properties")
return false
}
if descr.Writable == FLAG_FALSE {
r.typeErrorResult(throw, "Host object field %s cannot be made read-only", name)
return false
}
if descr.Configurable == FLAG_TRUE {
r.typeErrorResult(throw, "Host object field %s cannot be made configurable", name)
return false
}
return true
}
func (o *objectGoReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
n := name.String()
if has, ok := o._put(n, descr.Value, throw); !has {
o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a host object", n)
return false
} else {
return ok
}
}
return false
}
func (o *objectGoReflect) _has(name string) bool {
if o.fieldsValue.Kind() == reflect.Struct {
if v := o._getField(name); v.IsValid() {
return true
}
}
if v := o._getMethod(name); v.IsValid() {
return true
}
return false
}
func (o *objectGoReflect) hasOwnPropertyStr(name unistring.String) bool {
return o._has(name.String())
}
func (o *objectGoReflect) _valueOfInt() Value {
return intToValue(o.fieldsValue.Int())
}
func (o *objectGoReflect) _valueOfUint() Value {
return intToValue(int64(o.fieldsValue.Uint()))
}
func (o *objectGoReflect) _valueOfBool() Value {
if o.fieldsValue.Bool() {
return valueTrue
} else {
return valueFalse
}
}
func (o *objectGoReflect) _valueOfFloat() Value {
return floatToValue(o.fieldsValue.Float())
}
func (o *objectGoReflect) _toStringStringer() Value {
return newStringValue(o.origValue.Interface().(fmt.Stringer).String())
}
func (o *objectGoReflect) _toStringString() Value {
return newStringValue(o.fieldsValue.String())
}
func (o *objectGoReflect) _toStringBool() Value {
if o.fieldsValue.Bool() {
return stringTrue
} else {
return stringFalse
}
}
func (o *objectGoReflect) _toStringError() Value {
return newStringValue(o.origValue.Interface().(error).Error())
}
func (o *objectGoReflect) toPrimitiveNumber() Value {
if o.valueOf != nil {
return o.valueOf()
}
if o.toString != nil {
return o.toString()
}
return o.baseObject.toPrimitiveNumber()
}
func (o *objectGoReflect) toPrimitiveString() Value {
if o.toString != nil {
return o.toString()
}
if o.valueOf != nil {
return o.valueOf().toString()
}
return o.baseObject.toPrimitiveString()
}
func (o *objectGoReflect) toPrimitive() Value {
if o.valueOf != nil {
return o.valueOf()
}
if o.toString != nil {
return o.toString()
}
return o.baseObject.toPrimitive()
}
func (o *objectGoReflect) deleteStr(name unistring.String, throw bool) bool {
n := name.String()
if o._has(n) {
o.val.runtime.typeErrorResult(throw, "Cannot delete property %s from a Go type", n)
return false
}
return o.baseObject.deleteStr(name, throw)
}
type goreflectPropIter struct {
o *objectGoReflect
idx int
}
func (i *goreflectPropIter) nextField() (propIterItem, iterNextFunc) {
names := i.o.fieldsInfo.Names
if i.idx < len(names) {
name := names[i.idx]
i.idx++
return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextField
}
i.idx = 0
return i.nextMethod()
}
func (i *goreflectPropIter) nextMethod() (propIterItem, iterNextFunc) {
names := i.o.methodsInfo.Names
if i.idx < len(names) {
name := names[i.idx]
i.idx++
return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextMethod
}
return propIterItem{}, nil
}
func (o *objectGoReflect) iterateStringKeys() iterNextFunc {
r := &goreflectPropIter{
o: o,
}
if o.fieldsInfo != nil {
return r.nextField
}
return r.nextMethod
}
func (o *objectGoReflect) stringKeys(_ bool, accum []Value) []Value {
// all own keys are enumerable
if o.fieldsInfo != nil {
for _, name := range o.fieldsInfo.Names {
accum = append(accum, newStringValue(name))
}
}
for _, name := range o.methodsInfo.Names {
accum = append(accum, newStringValue(name))
}
return accum
}
func (o *objectGoReflect) export(*objectExportCtx) interface{} {
return o.origValue.Interface()
}
func (o *objectGoReflect) exportType() reflect.Type {
return o.origValue.Type()
}
func (o *objectGoReflect) equal(other objectImpl) bool {
if other, ok := other.(*objectGoReflect); ok {
k1, k2 := o.fieldsValue.Kind(), other.fieldsValue.Kind()
if k1 == k2 {
if isContainer(k1) {
return o.fieldsValue == other.fieldsValue
}
return o.fieldsValue.Interface() == other.fieldsValue.Interface()
}
}
return false
}
func (o *objectGoReflect) reflectValue() reflect.Value {
return o.fieldsValue
}
func (o *objectGoReflect) setReflectValue(v reflect.Value) {
o.fieldsValue = v
o.origValue = v
o.methodsValue = v.Addr()
}
func (o *objectGoReflect) esValue() Value {
return o.val
}
func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectFieldsInfo) {
n := t.NumField()
for i := 0; i < n; i++ {
field := t.Field(i)
name := field.Name
if !ast.IsExported(name) {
continue
}
if r.fieldNameMapper != nil {
name = r.fieldNameMapper.FieldName(t, field)
}
if name != "" {
if inf, exists := info.Fields[name]; !exists {
info.Names = append(info.Names, name)
} else {
if len(inf.Index) <= len(index) {
continue
}
}
}
if name != "" || field.Anonymous {
idx := make([]int, len(index)+1)
copy(idx, index)
idx[len(idx)-1] = i
if name != "" {
info.Fields[name] = reflectFieldInfo{
Index: idx,
Anonymous: field.Anonymous,
}
}
if field.Anonymous {
typ := field.Type
for typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
if typ.Kind() == reflect.Struct {
r.buildFieldInfo(typ, idx, info)
}
}
}
}
}
var emptyMethodsInfo = reflectMethodsInfo{}
func (r *Runtime) buildMethodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
n := t.NumMethod()
if n == 0 {
return &emptyMethodsInfo
}
info = new(reflectMethodsInfo)
info.Methods = make(map[string]int, n)
info.Names = make([]string, 0, n)
for i := 0; i < n; i++ {
method := t.Method(i)
name := method.Name
if !ast.IsExported(name) {
continue
}
if r.fieldNameMapper != nil {
name = r.fieldNameMapper.MethodName(t, method)
if name == "" {
continue
}
}
if _, exists := info.Methods[name]; !exists {
info.Names = append(info.Names, name)
}
info.Methods[name] = i
}
return
}
func (r *Runtime) buildFieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
info = new(reflectFieldsInfo)
n := t.NumField()
info.Fields = make(map[string]reflectFieldInfo, n)
info.Names = make([]string, 0, n)
r.buildFieldInfo(t, nil, info)
return
}
func (r *Runtime) fieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
var exists bool
if info, exists = r.fieldsInfoCache[t]; !exists {
info = r.buildFieldsInfo(t)
if r.fieldsInfoCache == nil {
r.fieldsInfoCache = make(map[reflect.Type]*reflectFieldsInfo)
}
r.fieldsInfoCache[t] = info
}
return
}
func (r *Runtime) methodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
var exists bool
if info, exists = r.methodsInfoCache[t]; !exists {
info = r.buildMethodsInfo(t)
if r.methodsInfoCache == nil {
r.methodsInfoCache = make(map[reflect.Type]*reflectMethodsInfo)
}
r.methodsInfoCache[t] = info
}
return
}
// SetFieldNameMapper sets a custom field name mapper for Go types. It can be called at any time, however
// the mapping for any given value is fixed at the point of creation.
// Setting this to nil restores the default behaviour which is all exported fields and methods are mapped to their
// original unchanged names.
func (r *Runtime) SetFieldNameMapper(mapper FieldNameMapper) {
r.fieldNameMapper = mapper
r.fieldsInfoCache = nil
r.methodsInfoCache = nil
}
// TagFieldNameMapper returns a FieldNameMapper that uses the given tagName for struct fields and optionally
// uncapitalises (making the first letter lower case) method names.
// The common tag value syntax is supported (name[,options]), however options are ignored.
// Setting name to anything other than a valid ECMAScript identifier makes the field hidden.
func TagFieldNameMapper(tagName string, uncapMethods bool) FieldNameMapper {
return tagFieldNameMapper{
tagName: tagName,
uncapMethods: uncapMethods,
}
}
// UncapFieldNameMapper returns a FieldNameMapper that uncapitalises struct field and method names
// making the first letter lower case.
func UncapFieldNameMapper() FieldNameMapper {
return uncapFieldNameMapper{}
}

336
server/vendor/github.com/dop251/goja/object_goslice.go generated vendored Normal file
View File

@@ -0,0 +1,336 @@
package goja
import (
"math"
"math/bits"
"reflect"
"strconv"
"github.com/dop251/goja/unistring"
)
type objectGoSlice struct {
baseObject
data *[]interface{}
lengthProp valueProperty
}
func (r *Runtime) newObjectGoSlice(data *[]interface{}) *objectGoSlice {
obj := &Object{runtime: r}
a := &objectGoSlice{
baseObject: baseObject{
val: obj,
},
data: data,
}
obj.self = a
a.init()
return a
}
func (o *objectGoSlice) init() {
o.baseObject.init()
o.class = classArray
o.prototype = o.val.runtime.global.ArrayPrototype
o.lengthProp.writable = true
o.extensible = true
o.updateLen()
o.baseObject._put("length", &o.lengthProp)
}
func (o *objectGoSlice) updateLen() {
o.lengthProp.value = intToValue(int64(len(*o.data)))
}
func (o *objectGoSlice) _getIdx(idx int) Value {
return o.val.runtime.ToValue((*o.data)[idx])
}
func (o *objectGoSlice) getStr(name unistring.String, receiver Value) Value {
var ownProp Value
if idx := strToGoIdx(name); idx >= 0 && idx < len(*o.data) {
ownProp = o._getIdx(idx)
} else if name == "length" {
ownProp = &o.lengthProp
}
return o.getStrWithOwnProp(ownProp, name, receiver)
}
func (o *objectGoSlice) getIdx(idx valueInt, receiver Value) Value {
if idx := int64(idx); idx >= 0 && idx < int64(len(*o.data)) {
return o._getIdx(int(idx))
}
if o.prototype != nil {
if receiver == nil {
return o.prototype.self.getIdx(idx, o.val)
}
return o.prototype.self.getIdx(idx, receiver)
}
return nil
}
func (o *objectGoSlice) getOwnPropStr(name unistring.String) Value {
if idx := strToGoIdx(name); idx >= 0 {
if idx < len(*o.data) {
return &valueProperty{
value: o._getIdx(idx),
writable: true,
enumerable: true,
}
}
return nil
}
if name == "length" {
return &o.lengthProp
}
return nil
}
func (o *objectGoSlice) getOwnPropIdx(idx valueInt) Value {
if idx := int64(idx); idx >= 0 && idx < int64(len(*o.data)) {
return &valueProperty{
value: o._getIdx(int(idx)),
writable: true,
enumerable: true,
}
}
return nil
}
func (o *objectGoSlice) grow(size int) {
oldcap := cap(*o.data)
if oldcap < size {
n := make([]interface{}, size, growCap(size, len(*o.data), oldcap))
copy(n, *o.data)
*o.data = n
} else {
tail := (*o.data)[len(*o.data):size]
for k := range tail {
tail[k] = nil
}
*o.data = (*o.data)[:size]
}
o.updateLen()
}
func (o *objectGoSlice) shrink(size int) {
tail := (*o.data)[size:]
for k := range tail {
tail[k] = nil
}
*o.data = (*o.data)[:size]
o.updateLen()
}
func (o *objectGoSlice) putIdx(idx int, v Value, throw bool) {
if idx >= len(*o.data) {
o.grow(idx + 1)
}
(*o.data)[idx] = v.Export()
}
func (o *objectGoSlice) putLength(v uint32, throw bool) bool {
if bits.UintSize == 32 && v > math.MaxInt32 {
panic(rangeError("Integer value overflows 32-bit int"))
}
newLen := int(v)
curLen := len(*o.data)
if newLen > curLen {
o.grow(newLen)
} else if newLen < curLen {
o.shrink(newLen)
}
return true
}
func (o *objectGoSlice) setOwnIdx(idx valueInt, val Value, throw bool) bool {
if i := toIntStrict(int64(idx)); i >= 0 {
if i >= len(*o.data) {
if res, ok := o._setForeignIdx(idx, nil, val, o.val, throw); ok {
return res
}
}
o.putIdx(i, val, throw)
} else {
name := idx.string()
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
return false
} else {
return res
}
}
return true
}
func (o *objectGoSlice) setOwnStr(name unistring.String, val Value, throw bool) bool {
if idx := strToGoIdx(name); idx >= 0 {
if idx >= len(*o.data) {
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); ok {
return res
}
}
o.putIdx(idx, val, throw)
} else {
if name == "length" {
return o.putLength(o.val.runtime.toLengthUint32(val), throw)
}
if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name)
return false
} else {
return res
}
}
return true
}
func (o *objectGoSlice) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw)
}
func (o *objectGoSlice) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw)
}
func (o *objectGoSlice) hasOwnPropertyIdx(idx valueInt) bool {
if idx := int64(idx); idx >= 0 {
return idx < int64(len(*o.data))
}
return false
}
func (o *objectGoSlice) hasOwnPropertyStr(name unistring.String) bool {
if idx := strToIdx64(name); idx >= 0 {
return idx < int64(len(*o.data))
}
return name == "length"
}
func (o *objectGoSlice) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
if i := toIntStrict(int64(idx)); i >= 0 {
if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) {
return false
}
val := descr.Value
if val == nil {
val = _undefined
}
o.putIdx(i, val, throw)
return true
}
o.val.runtime.typeErrorResult(throw, "Cannot define property '%d' on a Go slice", idx)
return false
}
func (o *objectGoSlice) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if idx := strToGoIdx(name); idx >= 0 {
if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
return false
}
val := descr.Value
if val == nil {
val = _undefined
}
o.putIdx(idx, val, throw)
return true
}
if name == "length" {
return o.val.runtime.defineArrayLength(&o.lengthProp, descr, o.putLength, throw)
}
o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a Go slice", name)
return false
}
func (o *objectGoSlice) _deleteIdx(idx int64) {
if idx < int64(len(*o.data)) {
(*o.data)[idx] = nil
}
}
func (o *objectGoSlice) deleteStr(name unistring.String, throw bool) bool {
if idx := strToIdx64(name); idx >= 0 {
o._deleteIdx(idx)
return true
}
return o.baseObject.deleteStr(name, throw)
}
func (o *objectGoSlice) deleteIdx(i valueInt, throw bool) bool {
idx := int64(i)
if idx >= 0 {
o._deleteIdx(idx)
}
return true
}
type goslicePropIter struct {
o *objectGoSlice
idx, limit int
}
func (i *goslicePropIter) next() (propIterItem, iterNextFunc) {
if i.idx < i.limit && i.idx < len(*i.o.data) {
name := strconv.Itoa(i.idx)
i.idx++
return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next
}
return propIterItem{}, nil
}
func (o *objectGoSlice) iterateStringKeys() iterNextFunc {
return (&goslicePropIter{
o: o,
limit: len(*o.data),
}).next
}
func (o *objectGoSlice) stringKeys(_ bool, accum []Value) []Value {
for i := range *o.data {
accum = append(accum, asciiString(strconv.Itoa(i)))
}
return accum
}
func (o *objectGoSlice) export(*objectExportCtx) interface{} {
return *o.data
}
func (o *objectGoSlice) exportType() reflect.Type {
return reflectTypeArray
}
func (o *objectGoSlice) equal(other objectImpl) bool {
if other, ok := other.(*objectGoSlice); ok {
return o.data == other.data
}
return false
}
func (o *objectGoSlice) esValue() Value {
return o.val
}
func (o *objectGoSlice) reflectValue() reflect.Value {
return reflect.ValueOf(o.data).Elem()
}
func (o *objectGoSlice) setReflectValue(value reflect.Value) {
o.data = value.Addr().Interface().(*[]interface{})
}
func (o *objectGoSlice) sortLen() int {
return len(*o.data)
}
func (o *objectGoSlice) sortGet(i int) Value {
return o.getIdx(valueInt(i), nil)
}
func (o *objectGoSlice) swap(i int, j int) {
(*o.data)[i], (*o.data)[j] = (*o.data)[j], (*o.data)[i]
}

View File

@@ -0,0 +1,91 @@
package goja
import (
"math"
"math/bits"
"reflect"
"github.com/dop251/goja/unistring"
)
type objectGoSliceReflect struct {
objectGoArrayReflect
}
func (o *objectGoSliceReflect) init() {
o.objectGoArrayReflect._init()
o.lengthProp.writable = true
o.putIdx = o._putIdx
}
func (o *objectGoSliceReflect) _putIdx(idx int, v Value, throw bool) bool {
if idx >= o.fieldsValue.Len() {
o.grow(idx + 1)
}
return o.objectGoArrayReflect._putIdx(idx, v, throw)
}
func (o *objectGoSliceReflect) grow(size int) {
oldcap := o.fieldsValue.Cap()
if oldcap < size {
n := reflect.MakeSlice(o.fieldsValue.Type(), size, growCap(size, o.fieldsValue.Len(), oldcap))
reflect.Copy(n, o.fieldsValue)
o.fieldsValue.Set(n)
l := len(o.valueCache)
if l > size {
l = size
}
for i, w := range o.valueCache[:l] {
if w != nil {
w.setReflectValue(o.fieldsValue.Index(i))
}
}
} else {
tail := o.fieldsValue.Slice(o.fieldsValue.Len(), size)
zero := reflect.Zero(o.fieldsValue.Type().Elem())
for i := 0; i < tail.Len(); i++ {
tail.Index(i).Set(zero)
}
o.fieldsValue.SetLen(size)
}
o.updateLen()
}
func (o *objectGoSliceReflect) shrink(size int) {
o.valueCache.shrink(size)
tail := o.fieldsValue.Slice(size, o.fieldsValue.Len())
zero := reflect.Zero(o.fieldsValue.Type().Elem())
for i := 0; i < tail.Len(); i++ {
tail.Index(i).Set(zero)
}
o.fieldsValue.SetLen(size)
o.updateLen()
}
func (o *objectGoSliceReflect) putLength(v uint32, throw bool) bool {
if bits.UintSize == 32 && v > math.MaxInt32 {
panic(rangeError("Integer value overflows 32-bit int"))
}
newLen := int(v)
curLen := o.fieldsValue.Len()
if newLen > curLen {
o.grow(newLen)
} else if newLen < curLen {
o.shrink(newLen)
}
return true
}
func (o *objectGoSliceReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
if name == "length" {
return o.putLength(o.val.runtime.toLengthUint32(val), throw)
}
return o.objectGoArrayReflect.setOwnStr(name, val, throw)
}
func (o *objectGoSliceReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if name == "length" {
return o.val.runtime.defineArrayLength(&o.lengthProp, descr, o.putLength, throw)
}
return o.objectGoArrayReflect.defineOwnPropertyStr(name, descr, throw)
}

332
server/vendor/github.com/dop251/goja/object_lazy.go generated vendored Normal file
View File

@@ -0,0 +1,332 @@
package goja
import (
"reflect"
"github.com/dop251/goja/unistring"
)
type lazyObject struct {
val *Object
create func(*Object) objectImpl
}
func (o *lazyObject) className() string {
obj := o.create(o.val)
o.val.self = obj
return obj.className()
}
func (o *lazyObject) typeOf() valueString {
obj := o.create(o.val)
o.val.self = obj
return obj.typeOf()
}
func (o *lazyObject) getIdx(p valueInt, receiver Value) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.getIdx(p, receiver)
}
func (o *lazyObject) getSym(p *Symbol, receiver Value) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.getSym(p, receiver)
}
func (o *lazyObject) getOwnPropIdx(idx valueInt) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.getOwnPropIdx(idx)
}
func (o *lazyObject) getOwnPropSym(s *Symbol) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.getOwnPropSym(s)
}
func (o *lazyObject) hasPropertyIdx(idx valueInt) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasPropertyIdx(idx)
}
func (o *lazyObject) hasPropertySym(s *Symbol) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasPropertySym(s)
}
func (o *lazyObject) hasOwnPropertyIdx(idx valueInt) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasOwnPropertyIdx(idx)
}
func (o *lazyObject) hasOwnPropertySym(s *Symbol) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasOwnPropertySym(s)
}
func (o *lazyObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.defineOwnPropertyStr(name, desc, throw)
}
func (o *lazyObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.defineOwnPropertyIdx(name, desc, throw)
}
func (o *lazyObject) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.defineOwnPropertySym(name, desc, throw)
}
func (o *lazyObject) deleteIdx(idx valueInt, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.deleteIdx(idx, throw)
}
func (o *lazyObject) deleteSym(s *Symbol, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.deleteSym(s, throw)
}
func (o *lazyObject) getStr(name unistring.String, receiver Value) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.getStr(name, receiver)
}
func (o *lazyObject) getOwnPropStr(name unistring.String) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.getOwnPropStr(name)
}
func (o *lazyObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.setOwnStr(p, v, throw)
}
func (o *lazyObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.setOwnIdx(p, v, throw)
}
func (o *lazyObject) setOwnSym(p *Symbol, v Value, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.setOwnSym(p, v, throw)
}
func (o *lazyObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (bool, bool) {
obj := o.create(o.val)
o.val.self = obj
return obj.setForeignStr(p, v, receiver, throw)
}
func (o *lazyObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (bool, bool) {
obj := o.create(o.val)
o.val.self = obj
return obj.setForeignIdx(p, v, receiver, throw)
}
func (o *lazyObject) setForeignSym(p *Symbol, v, receiver Value, throw bool) (bool, bool) {
obj := o.create(o.val)
o.val.self = obj
return obj.setForeignSym(p, v, receiver, throw)
}
func (o *lazyObject) hasPropertyStr(name unistring.String) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasPropertyStr(name)
}
func (o *lazyObject) hasOwnPropertyStr(name unistring.String) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasOwnPropertyStr(name)
}
func (o *lazyObject) _putProp(unistring.String, Value, bool, bool, bool) Value {
panic("cannot use _putProp() in lazy object")
}
func (o *lazyObject) _putSym(*Symbol, Value) {
panic("cannot use _putSym() in lazy object")
}
func (o *lazyObject) toPrimitiveNumber() Value {
obj := o.create(o.val)
o.val.self = obj
return obj.toPrimitiveNumber()
}
func (o *lazyObject) toPrimitiveString() Value {
obj := o.create(o.val)
o.val.self = obj
return obj.toPrimitiveString()
}
func (o *lazyObject) toPrimitive() Value {
obj := o.create(o.val)
o.val.self = obj
return obj.toPrimitive()
}
func (o *lazyObject) assertCallable() (call func(FunctionCall) Value, ok bool) {
obj := o.create(o.val)
o.val.self = obj
return obj.assertCallable()
}
func (o *lazyObject) vmCall(vm *vm, n int) {
obj := o.create(o.val)
o.val.self = obj
obj.vmCall(vm, n)
}
func (o *lazyObject) assertConstructor() func(args []Value, newTarget *Object) *Object {
obj := o.create(o.val)
o.val.self = obj
return obj.assertConstructor()
}
func (o *lazyObject) deleteStr(name unistring.String, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.deleteStr(name, throw)
}
func (o *lazyObject) proto() *Object {
obj := o.create(o.val)
o.val.self = obj
return obj.proto()
}
func (o *lazyObject) hasInstance(v Value) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.hasInstance(v)
}
func (o *lazyObject) isExtensible() bool {
obj := o.create(o.val)
o.val.self = obj
return obj.isExtensible()
}
func (o *lazyObject) preventExtensions(throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.preventExtensions(throw)
}
func (o *lazyObject) iterateStringKeys() iterNextFunc {
obj := o.create(o.val)
o.val.self = obj
return obj.iterateStringKeys()
}
func (o *lazyObject) iterateSymbols() iterNextFunc {
obj := o.create(o.val)
o.val.self = obj
return obj.iterateSymbols()
}
func (o *lazyObject) iterateKeys() iterNextFunc {
obj := o.create(o.val)
o.val.self = obj
return obj.iterateKeys()
}
func (o *lazyObject) export(ctx *objectExportCtx) interface{} {
obj := o.create(o.val)
o.val.self = obj
return obj.export(ctx)
}
func (o *lazyObject) exportType() reflect.Type {
obj := o.create(o.val)
o.val.self = obj
return obj.exportType()
}
func (o *lazyObject) exportToMap(m reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
obj := o.create(o.val)
o.val.self = obj
return obj.exportToMap(m, typ, ctx)
}
func (o *lazyObject) exportToArrayOrSlice(s reflect.Value, typ reflect.Type, ctx *objectExportCtx) error {
obj := o.create(o.val)
o.val.self = obj
return obj.exportToArrayOrSlice(s, typ, ctx)
}
func (o *lazyObject) equal(other objectImpl) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.equal(other)
}
func (o *lazyObject) stringKeys(all bool, accum []Value) []Value {
obj := o.create(o.val)
o.val.self = obj
return obj.stringKeys(all, accum)
}
func (o *lazyObject) symbols(all bool, accum []Value) []Value {
obj := o.create(o.val)
o.val.self = obj
return obj.symbols(all, accum)
}
func (o *lazyObject) keys(all bool, accum []Value) []Value {
obj := o.create(o.val)
o.val.self = obj
return obj.keys(all, accum)
}
func (o *lazyObject) setProto(proto *Object, throw bool) bool {
obj := o.create(o.val)
o.val.self = obj
return obj.setProto(proto, throw)
}
func (o *lazyObject) getPrivateEnv(typ *privateEnvType, create bool) *privateElements {
obj := o.create(o.val)
o.val.self = obj
return obj.getPrivateEnv(typ, create)
}
func (o *lazyObject) sortLen() int {
obj := o.create(o.val)
o.val.self = obj
return obj.sortLen()
}
func (o *lazyObject) sortGet(i int) Value {
obj := o.create(o.val)
o.val.self = obj
return obj.sortGet(i)
}
func (o *lazyObject) swap(i int, j int) {
obj := o.create(o.val)
o.val.self = obj
obj.swap(i, j)
}

View File

@@ -0,0 +1,184 @@
# parser
--
import "github.com/dop251/goja/parser"
Package parser implements a parser for JavaScript. Borrowed from https://github.com/robertkrimen/otto/tree/master/parser
import (
"github.com/dop251/goja/parser"
)
Parse and return an AST
filename := "" // A filename is optional
src := `
// Sample xyzzy example
(function(){
if (3.14159 > 0) {
console.log("Hello, World.");
return;
}
var xyzzy = NaN;
console.log("Nothing happens.");
return xyzzy;
})();
`
// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, filename, src, 0)
### Warning
The parser and AST interfaces are still works-in-progress (particularly where
node types are concerned) and may change in the future.
## Usage
#### func ParseFile
```go
func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode) (*ast.Program, error)
```
ParseFile parses the source code of a single JavaScript/ECMAScript source file
and returns the corresponding ast.Program node.
If fileSet == nil, ParseFile parses source without a FileSet. If fileSet != nil,
ParseFile first adds filename and src to fileSet.
The filename argument is optional and is used for labelling errors, etc.
src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST
always be in UTF-8.
// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0)
#### func ParseFunction
```go
func ParseFunction(parameterList, body string) (*ast.FunctionLiteral, error)
```
ParseFunction parses a given parameter list and body as a function and returns
the corresponding ast.FunctionLiteral node.
The parameter list, if any, should be a comma-separated list of identifiers.
#### func ReadSource
```go
func ReadSource(filename string, src interface{}) ([]byte, error)
```
#### func TransformRegExp
```go
func TransformRegExp(pattern string) (string, error)
```
TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern.
re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or
backreference (\1, \2, ...) will cause an error.
re2 (Go) has a different definition for \s: [\t\n\f\r ]. The JavaScript
definition, on the other hand, also includes \v, Unicode "Separator, Space",
etc.
If the pattern is invalid (not valid even in JavaScript), then this function
returns the empty string and an error.
If the pattern is valid, but incompatible (contains a lookahead or
backreference), then this function returns the transformation (a non-empty
string) AND an error.
#### type Error
```go
type Error struct {
Position file.Position
Message string
}
```
An Error represents a parsing error. It includes the position where the error
occurred and a message/description.
#### func (Error) Error
```go
func (self Error) Error() string
```
#### type ErrorList
```go
type ErrorList []*Error
```
ErrorList is a list of *Errors.
#### func (*ErrorList) Add
```go
func (self *ErrorList) Add(position file.Position, msg string)
```
Add adds an Error with given position and message to an ErrorList.
#### func (ErrorList) Err
```go
func (self ErrorList) Err() error
```
Err returns an error equivalent to this ErrorList. If the list is empty, Err
returns nil.
#### func (ErrorList) Error
```go
func (self ErrorList) Error() string
```
Error implements the Error interface.
#### func (ErrorList) Len
```go
func (self ErrorList) Len() int
```
#### func (ErrorList) Less
```go
func (self ErrorList) Less(i, j int) bool
```
#### func (*ErrorList) Reset
```go
func (self *ErrorList) Reset()
```
Reset resets an ErrorList to no errors.
#### func (ErrorList) Sort
```go
func (self ErrorList) Sort()
```
#### func (ErrorList) Swap
```go
func (self ErrorList) Swap(i, j int)
```
#### type Mode
```go
type Mode uint
```
A Mode value is a set of flags (or 0). They control optional parser
functionality.
--
**godocdown** http://github.com/robertkrimen/godocdown

176
server/vendor/github.com/dop251/goja/parser/error.go generated vendored Normal file
View File

@@ -0,0 +1,176 @@
package parser
import (
"fmt"
"sort"
"github.com/dop251/goja/file"
"github.com/dop251/goja/token"
)
const (
err_UnexpectedToken = "Unexpected token %v"
err_UnexpectedEndOfInput = "Unexpected end of input"
err_UnexpectedEscape = "Unexpected escape"
)
// UnexpectedNumber: 'Unexpected number',
// UnexpectedString: 'Unexpected string',
// UnexpectedIdentifier: 'Unexpected identifier',
// UnexpectedReserved: 'Unexpected reserved word',
// NewlineAfterThrow: 'Illegal newline after throw',
// InvalidRegExp: 'Invalid regular expression',
// UnterminatedRegExp: 'Invalid regular expression: missing /',
// InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
// InvalidLHSInForIn: 'Invalid left-hand side in for-in',
// MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
// NoCatchOrFinally: 'Missing catch or finally after try',
// UnknownLabel: 'Undefined label \'%0\'',
// Redeclaration: '%0 \'%1\' has already been declared',
// IllegalContinue: 'Illegal continue statement',
// IllegalBreak: 'Illegal break statement',
// IllegalReturn: 'Illegal return statement',
// StrictModeWith: 'Strict mode code may not include a with statement',
// StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
// StrictVarName: 'Variable name may not be eval or arguments in strict mode',
// StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
// StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
// StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
// StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
// StrictDelete: 'Delete of an unqualified identifier in strict mode.',
// StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
// AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
// AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
// StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
// StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
// StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
// StrictReservedWord: 'Use of future reserved word in strict mode'
// A SyntaxError is a description of an ECMAScript syntax error.
// An Error represents a parsing error. It includes the position where the error occurred and a message/description.
type Error struct {
Position file.Position
Message string
}
// FIXME Should this be "SyntaxError"?
func (self Error) Error() string {
filename := self.Position.Filename
if filename == "" {
filename = "(anonymous)"
}
return fmt.Sprintf("%s: Line %d:%d %s",
filename,
self.Position.Line,
self.Position.Column,
self.Message,
)
}
func (self *_parser) error(place interface{}, msg string, msgValues ...interface{}) *Error {
idx := file.Idx(0)
switch place := place.(type) {
case int:
idx = self.idxOf(place)
case file.Idx:
if place == 0 {
idx = self.idxOf(self.chrOffset)
} else {
idx = place
}
default:
panic(fmt.Errorf("error(%T, ...)", place))
}
position := self.position(idx)
msg = fmt.Sprintf(msg, msgValues...)
self.errors.Add(position, msg)
return self.errors[len(self.errors)-1]
}
func (self *_parser) errorUnexpected(idx file.Idx, chr rune) error {
if chr == -1 {
return self.error(idx, err_UnexpectedEndOfInput)
}
return self.error(idx, err_UnexpectedToken, token.ILLEGAL)
}
func (self *_parser) errorUnexpectedToken(tkn token.Token) error {
switch tkn {
case token.EOF:
return self.error(file.Idx(0), err_UnexpectedEndOfInput)
}
value := tkn.String()
switch tkn {
case token.BOOLEAN, token.NULL:
value = self.literal
case token.IDENTIFIER:
return self.error(self.idx, "Unexpected identifier")
case token.KEYWORD:
// TODO Might be a future reserved word
return self.error(self.idx, "Unexpected reserved word")
case token.ESCAPED_RESERVED_WORD:
return self.error(self.idx, "Keyword must not contain escaped characters")
case token.NUMBER:
return self.error(self.idx, "Unexpected number")
case token.STRING:
return self.error(self.idx, "Unexpected string")
}
return self.error(self.idx, err_UnexpectedToken, value)
}
// ErrorList is a list of *Errors.
type ErrorList []*Error
// Add adds an Error with given position and message to an ErrorList.
func (self *ErrorList) Add(position file.Position, msg string) {
*self = append(*self, &Error{position, msg})
}
// Reset resets an ErrorList to no errors.
func (self *ErrorList) Reset() { *self = (*self)[0:0] }
func (self ErrorList) Len() int { return len(self) }
func (self ErrorList) Swap(i, j int) { self[i], self[j] = self[j], self[i] }
func (self ErrorList) Less(i, j int) bool {
x := &self[i].Position
y := &self[j].Position
if x.Filename < y.Filename {
return true
}
if x.Filename == y.Filename {
if x.Line < y.Line {
return true
}
if x.Line == y.Line {
return x.Column < y.Column
}
}
return false
}
func (self ErrorList) Sort() {
sort.Sort(self)
}
// Error implements the Error interface.
func (self ErrorList) Error() string {
switch len(self) {
case 0:
return "no errors"
case 1:
return self[0].Error()
}
return fmt.Sprintf("%s (and %d more errors)", self[0].Error(), len(self)-1)
}
// Err returns an error equivalent to this ErrorList.
// If the list is empty, Err returns nil.
func (self ErrorList) Err() error {
if len(self) == 0 {
return nil
}
return self
}

1655
server/vendor/github.com/dop251/goja/parser/expression.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

1179
server/vendor/github.com/dop251/goja/parser/lexer.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

268
server/vendor/github.com/dop251/goja/parser/parser.go generated vendored Normal file
View File

@@ -0,0 +1,268 @@
/*
Package parser implements a parser for JavaScript.
import (
"github.com/dop251/goja/parser"
)
Parse and return an AST
filename := "" // A filename is optional
src := `
// Sample xyzzy example
(function(){
if (3.14159 > 0) {
console.log("Hello, World.");
return;
}
var xyzzy = NaN;
console.log("Nothing happens.");
return xyzzy;
})();
`
// Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
program, err := parser.ParseFile(nil, filename, src, 0)
# Warning
The parser and AST interfaces are still works-in-progress (particularly where
node types are concerned) and may change in the future.
*/
package parser
import (
"bytes"
"errors"
"io"
"os"
"github.com/dop251/goja/ast"
"github.com/dop251/goja/file"
"github.com/dop251/goja/token"
"github.com/dop251/goja/unistring"
)
// A Mode value is a set of flags (or 0). They control optional parser functionality.
type Mode uint
const (
IgnoreRegExpErrors Mode = 1 << iota // Ignore RegExp compatibility errors (allow backtracking)
)
type options struct {
disableSourceMaps bool
sourceMapLoader func(path string) ([]byte, error)
}
// Option represents one of the options for the parser to use in the Parse methods. Currently supported are:
// WithDisableSourceMaps and WithSourceMapLoader.
type Option func(*options)
// WithDisableSourceMaps is an option to disable source maps support. May save a bit of time when source maps
// are not in use.
func WithDisableSourceMaps(opts *options) {
opts.disableSourceMaps = true
}
// WithSourceMapLoader is an option to set a custom source map loader. The loader will be given a path or a
// URL from the sourceMappingURL. If sourceMappingURL is not absolute it is resolved relatively to the name
// of the file being parsed. Any error returned by the loader will fail the parsing.
// Note that setting this to nil does not disable source map support, there is a default loader which reads
// from the filesystem. Use WithDisableSourceMaps to disable source map support.
func WithSourceMapLoader(loader func(path string) ([]byte, error)) Option {
return func(opts *options) {
opts.sourceMapLoader = loader
}
}
type _parser struct {
str string
length int
base int
chr rune // The current character
chrOffset int // The offset of current character
offset int // The offset after current character (may be greater than 1)
idx file.Idx // The index of token
token token.Token // The token
literal string // The literal of the token, if any
parsedLiteral unistring.String
scope *_scope
insertSemicolon bool // If we see a newline, then insert an implicit semicolon
implicitSemicolon bool // An implicit semicolon exists
errors ErrorList
recover struct {
// Scratch when trying to seek to the next statement, etc.
idx file.Idx
count int
}
mode Mode
opts options
file *file.File
}
func _newParser(filename, src string, base int, opts ...Option) *_parser {
p := &_parser{
chr: ' ', // This is set so we can start scanning by skipping whitespace
str: src,
length: len(src),
base: base,
file: file.NewFile(filename, src, base),
}
for _, opt := range opts {
opt(&p.opts)
}
return p
}
func newParser(filename, src string) *_parser {
return _newParser(filename, src, 1)
}
func ReadSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch src := src.(type) {
case string:
return []byte(src), nil
case []byte:
return src, nil
case *bytes.Buffer:
if src != nil {
return src.Bytes(), nil
}
case io.Reader:
var bfr bytes.Buffer
if _, err := io.Copy(&bfr, src); err != nil {
return nil, err
}
return bfr.Bytes(), nil
}
return nil, errors.New("invalid source")
}
return os.ReadFile(filename)
}
// ParseFile parses the source code of a single JavaScript/ECMAScript source file and returns
// the corresponding ast.Program node.
//
// If fileSet == nil, ParseFile parses source without a FileSet.
// If fileSet != nil, ParseFile first adds filename and src to fileSet.
//
// The filename argument is optional and is used for labelling errors, etc.
//
// src may be a string, a byte slice, a bytes.Buffer, or an io.Reader, but it MUST always be in UTF-8.
//
// // Parse some JavaScript, yielding a *ast.Program and/or an ErrorList
// program, err := parser.ParseFile(nil, "", `if (abc > 1) {}`, 0)
func ParseFile(fileSet *file.FileSet, filename string, src interface{}, mode Mode, options ...Option) (*ast.Program, error) {
str, err := ReadSource(filename, src)
if err != nil {
return nil, err
}
{
str := string(str)
base := 1
if fileSet != nil {
base = fileSet.AddFile(filename, str)
}
parser := _newParser(filename, str, base, options...)
parser.mode = mode
return parser.parse()
}
}
// ParseFunction parses a given parameter list and body as a function and returns the
// corresponding ast.FunctionLiteral node.
//
// The parameter list, if any, should be a comma-separated list of identifiers.
func ParseFunction(parameterList, body string, options ...Option) (*ast.FunctionLiteral, error) {
src := "(function(" + parameterList + ") {\n" + body + "\n})"
parser := _newParser("", src, 1, options...)
program, err := parser.parse()
if err != nil {
return nil, err
}
return program.Body[0].(*ast.ExpressionStatement).Expression.(*ast.FunctionLiteral), nil
}
func (self *_parser) slice(idx0, idx1 file.Idx) string {
from := int(idx0) - self.base
to := int(idx1) - self.base
if from >= 0 && to <= len(self.str) {
return self.str[from:to]
}
return ""
}
func (self *_parser) parse() (*ast.Program, error) {
self.openScope()
defer self.closeScope()
self.next()
program := self.parseProgram()
if false {
self.errors.Sort()
}
return program, self.errors.Err()
}
func (self *_parser) next() {
self.token, self.literal, self.parsedLiteral, self.idx = self.scan()
}
func (self *_parser) optionalSemicolon() {
if self.token == token.SEMICOLON {
self.next()
return
}
if self.implicitSemicolon {
self.implicitSemicolon = false
return
}
if self.token != token.EOF && self.token != token.RIGHT_BRACE {
self.expect(token.SEMICOLON)
}
}
func (self *_parser) semicolon() {
if self.token != token.RIGHT_PARENTHESIS && self.token != token.RIGHT_BRACE {
if self.implicitSemicolon {
self.implicitSemicolon = false
return
}
self.expect(token.SEMICOLON)
}
}
func (self *_parser) idxOf(offset int) file.Idx {
return file.Idx(self.base + offset)
}
func (self *_parser) expect(value token.Token) file.Idx {
idx := self.idx
if self.token != value {
self.errorUnexpectedToken(self.token)
}
self.next()
return idx
}
func (self *_parser) position(idx file.Idx) file.Position {
return self.file.Position(int(idx) - self.base)
}

458
server/vendor/github.com/dop251/goja/parser/regexp.go generated vendored Normal file
View File

@@ -0,0 +1,458 @@
package parser
import (
"fmt"
"strconv"
"strings"
"unicode/utf8"
)
const (
WhitespaceChars = " \f\n\r\t\v\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff"
Re2Dot = "[^\r\n\u2028\u2029]"
)
type regexpParseError struct {
offset int
err string
}
type RegexpErrorIncompatible struct {
regexpParseError
}
type RegexpSyntaxError struct {
regexpParseError
}
func (s regexpParseError) Error() string {
return s.err
}
type _RegExp_parser struct {
str string
length int
chr rune // The current character
chrOffset int // The offset of current character
offset int // The offset after current character (may be greater than 1)
err error
goRegexp strings.Builder
passOffset int
}
// TransformRegExp transforms a JavaScript pattern into a Go "regexp" pattern.
//
// re2 (Go) cannot do backtracking, so the presence of a lookahead (?=) (?!) or
// backreference (\1, \2, ...) will cause an error.
//
// re2 (Go) has a different definition for \s: [\t\n\f\r ].
// The JavaScript definition, on the other hand, also includes \v, Unicode "Separator, Space", etc.
//
// If the pattern is valid, but incompatible (contains a lookahead or backreference),
// then this function returns an empty string an error of type RegexpErrorIncompatible.
//
// If the pattern is invalid (not valid even in JavaScript), then this function
// returns an empty string and a generic error.
func TransformRegExp(pattern string) (transformed string, err error) {
if pattern == "" {
return "", nil
}
parser := _RegExp_parser{
str: pattern,
length: len(pattern),
}
err = parser.parse()
if err != nil {
return "", err
}
return parser.ResultString(), nil
}
func (self *_RegExp_parser) ResultString() string {
if self.passOffset != -1 {
return self.str[:self.passOffset]
}
return self.goRegexp.String()
}
func (self *_RegExp_parser) parse() (err error) {
self.read() // Pull in the first character
self.scan()
return self.err
}
func (self *_RegExp_parser) read() {
if self.offset < self.length {
self.chrOffset = self.offset
chr, width := rune(self.str[self.offset]), 1
if chr >= utf8.RuneSelf { // !ASCII
chr, width = utf8.DecodeRuneInString(self.str[self.offset:])
if chr == utf8.RuneError && width == 1 {
self.error(true, "Invalid UTF-8 character")
return
}
}
self.offset += width
self.chr = chr
} else {
self.chrOffset = self.length
self.chr = -1 // EOF
}
}
func (self *_RegExp_parser) stopPassing() {
self.goRegexp.Grow(3 * len(self.str) / 2)
self.goRegexp.WriteString(self.str[:self.passOffset])
self.passOffset = -1
}
func (self *_RegExp_parser) write(p []byte) {
if self.passOffset != -1 {
self.stopPassing()
}
self.goRegexp.Write(p)
}
func (self *_RegExp_parser) writeByte(b byte) {
if self.passOffset != -1 {
self.stopPassing()
}
self.goRegexp.WriteByte(b)
}
func (self *_RegExp_parser) writeString(s string) {
if self.passOffset != -1 {
self.stopPassing()
}
self.goRegexp.WriteString(s)
}
func (self *_RegExp_parser) scan() {
for self.chr != -1 {
switch self.chr {
case '\\':
self.read()
self.scanEscape(false)
case '(':
self.pass()
self.scanGroup()
case '[':
self.scanBracket()
case ')':
self.error(true, "Unmatched ')'")
return
case '.':
self.writeString(Re2Dot)
self.read()
default:
self.pass()
}
}
}
// (...)
func (self *_RegExp_parser) scanGroup() {
str := self.str[self.chrOffset:]
if len(str) > 1 { // A possibility of (?= or (?!
if str[0] == '?' {
ch := str[1]
switch {
case ch == '=' || ch == '!':
self.error(false, "re2: Invalid (%s) <lookahead>", self.str[self.chrOffset:self.chrOffset+2])
return
case ch == '<':
self.error(false, "re2: Invalid (%s) <lookbehind>", self.str[self.chrOffset:self.chrOffset+2])
return
case ch != ':':
self.error(true, "Invalid group")
return
}
}
}
for self.chr != -1 && self.chr != ')' {
switch self.chr {
case '\\':
self.read()
self.scanEscape(false)
case '(':
self.pass()
self.scanGroup()
case '[':
self.scanBracket()
case '.':
self.writeString(Re2Dot)
self.read()
default:
self.pass()
continue
}
}
if self.chr != ')' {
self.error(true, "Unterminated group")
return
}
self.pass()
}
// [...]
func (self *_RegExp_parser) scanBracket() {
str := self.str[self.chrOffset:]
if strings.HasPrefix(str, "[]") {
// [] -- Empty character class
self.writeString("[^\u0000-\U0001FFFF]")
self.offset += 1
self.read()
return
}
if strings.HasPrefix(str, "[^]") {
self.writeString("[\u0000-\U0001FFFF]")
self.offset += 2
self.read()
return
}
self.pass()
for self.chr != -1 {
if self.chr == ']' {
break
} else if self.chr == '\\' {
self.read()
self.scanEscape(true)
continue
}
self.pass()
}
if self.chr != ']' {
self.error(true, "Unterminated character class")
return
}
self.pass()
}
// \...
func (self *_RegExp_parser) scanEscape(inClass bool) {
offset := self.chrOffset
var length, base uint32
switch self.chr {
case '0', '1', '2', '3', '4', '5', '6', '7':
var value int64
size := 0
for {
digit := int64(digitValue(self.chr))
if digit >= 8 {
// Not a valid digit
break
}
value = value*8 + digit
self.read()
size += 1
}
if size == 1 { // The number of characters read
if value != 0 {
// An invalid backreference
self.error(false, "re2: Invalid \\%d <backreference>", value)
return
}
self.passString(offset-1, self.chrOffset)
return
}
tmp := []byte{'\\', 'x', '0', 0}
if value >= 16 {
tmp = tmp[0:2]
} else {
tmp = tmp[0:3]
}
tmp = strconv.AppendInt(tmp, value, 16)
self.write(tmp)
return
case '8', '9':
self.read()
self.error(false, "re2: Invalid \\%s <backreference>", self.str[offset:self.chrOffset])
return
case 'x':
self.read()
length, base = 2, 16
case 'u':
self.read()
if self.chr == '{' {
self.read()
length, base = 0, 16
} else {
length, base = 4, 16
}
case 'b':
if inClass {
self.write([]byte{'\\', 'x', '0', '8'})
self.read()
return
}
fallthrough
case 'B':
fallthrough
case 'd', 'D', 'w', 'W':
// This is slightly broken, because ECMAScript
// includes \v in \s, \S, while re2 does not
fallthrough
case '\\':
fallthrough
case 'f', 'n', 'r', 't', 'v':
self.passString(offset-1, self.offset)
self.read()
return
case 'c':
self.read()
var value int64
if 'a' <= self.chr && self.chr <= 'z' {
value = int64(self.chr - 'a' + 1)
} else if 'A' <= self.chr && self.chr <= 'Z' {
value = int64(self.chr - 'A' + 1)
} else {
self.writeByte('c')
return
}
tmp := []byte{'\\', 'x', '0', 0}
if value >= 16 {
tmp = tmp[0:2]
} else {
tmp = tmp[0:3]
}
tmp = strconv.AppendInt(tmp, value, 16)
self.write(tmp)
self.read()
return
case 's':
if inClass {
self.writeString(WhitespaceChars)
} else {
self.writeString("[" + WhitespaceChars + "]")
}
self.read()
return
case 'S':
if inClass {
self.error(false, "S in class")
return
} else {
self.writeString("[^" + WhitespaceChars + "]")
}
self.read()
return
default:
// $ is an identifier character, so we have to have
// a special case for it here
if self.chr == '$' || self.chr < utf8.RuneSelf && !isIdentifierPart(self.chr) {
// A non-identifier character needs escaping
self.passString(offset-1, self.offset)
self.read()
return
}
// Unescape the character for re2
self.pass()
return
}
// Otherwise, we're a \u.... or \x...
valueOffset := self.chrOffset
if length > 0 {
for length := length; length > 0; length-- {
digit := uint32(digitValue(self.chr))
if digit >= base {
// Not a valid digit
goto skip
}
self.read()
}
} else {
for self.chr != '}' && self.chr != -1 {
digit := uint32(digitValue(self.chr))
if digit >= base {
// Not a valid digit
goto skip
}
self.read()
}
}
if length == 4 || length == 0 {
self.write([]byte{
'\\',
'x',
'{',
})
self.passString(valueOffset, self.chrOffset)
if length != 0 {
self.writeByte('}')
}
} else if length == 2 {
self.passString(offset-1, valueOffset+2)
} else {
// Should never, ever get here...
self.error(true, "re2: Illegal branch in scanEscape")
return
}
return
skip:
self.passString(offset, self.chrOffset)
}
func (self *_RegExp_parser) pass() {
if self.passOffset == self.chrOffset {
self.passOffset = self.offset
} else {
if self.passOffset != -1 {
self.stopPassing()
}
if self.chr != -1 {
self.goRegexp.WriteRune(self.chr)
}
}
self.read()
}
func (self *_RegExp_parser) passString(start, end int) {
if self.passOffset == start {
self.passOffset = end
return
}
if self.passOffset != -1 {
self.stopPassing()
}
self.goRegexp.WriteString(self.str[start:end])
}
func (self *_RegExp_parser) error(fatal bool, msg string, msgValues ...interface{}) {
if self.err != nil {
return
}
e := regexpParseError{
offset: self.offset,
err: fmt.Sprintf(msg, msgValues...),
}
if fatal {
self.err = RegexpSyntaxError{e}
} else {
self.err = RegexpErrorIncompatible{e}
}
self.offset = self.length
self.chr = -1
}

50
server/vendor/github.com/dop251/goja/parser/scope.go generated vendored Normal file
View File

@@ -0,0 +1,50 @@
package parser
import (
"github.com/dop251/goja/ast"
"github.com/dop251/goja/unistring"
)
type _scope struct {
outer *_scope
allowIn bool
allowLet bool
inIteration bool
inSwitch bool
inFuncParams bool
inFunction bool
inAsync bool
allowAwait bool
allowYield bool
declarationList []*ast.VariableDeclaration
labels []unistring.String
}
func (self *_parser) openScope() {
self.scope = &_scope{
outer: self.scope,
allowIn: true,
}
}
func (self *_parser) closeScope() {
self.scope = self.scope.outer
}
func (self *_scope) declare(declaration *ast.VariableDeclaration) {
self.declarationList = append(self.declarationList, declaration)
}
func (self *_scope) hasLabel(name unistring.String) bool {
for _, label := range self.labels {
if label == name {
return true
}
}
if self.outer != nil && !self.inFunction {
// Crossing a function boundary to look for a label is verboten
return self.outer.hasLabel(name)
}
return false
}

1076
server/vendor/github.com/dop251/goja/parser/statement.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

308
server/vendor/github.com/dop251/goja/profiler.go generated vendored Normal file
View File

@@ -0,0 +1,308 @@
package goja
import (
"errors"
"io"
"strconv"
"sync"
"sync/atomic"
"time"
"github.com/google/pprof/profile"
)
const profInterval = 10 * time.Millisecond
const profMaxStackDepth = 64
const (
profReqNone int32 = iota
profReqDoSample
profReqSampleReady
profReqStop
)
type _globalProfiler struct {
p profiler
w io.Writer
enabled int32
}
var globalProfiler _globalProfiler
type profTracker struct {
req, finished int32
start, stop time.Time
numFrames int
frames [profMaxStackDepth]StackFrame
}
type profiler struct {
mu sync.Mutex
trackers []*profTracker
buf *profBuffer
running bool
}
type profFunc struct {
f profile.Function
locs map[int32]*profile.Location
}
type profSampleNode struct {
loc *profile.Location
sample *profile.Sample
parent *profSampleNode
children map[*profile.Location]*profSampleNode
}
type profBuffer struct {
funcs map[*Program]*profFunc
root profSampleNode
}
func (pb *profBuffer) addSample(pt *profTracker) {
sampleFrames := pt.frames[:pt.numFrames]
n := &pb.root
for j := len(sampleFrames) - 1; j >= 0; j-- {
frame := sampleFrames[j]
if frame.prg == nil {
continue
}
var f *profFunc
if f = pb.funcs[frame.prg]; f == nil {
f = &profFunc{
locs: make(map[int32]*profile.Location),
}
if pb.funcs == nil {
pb.funcs = make(map[*Program]*profFunc)
}
pb.funcs[frame.prg] = f
}
var loc *profile.Location
if loc = f.locs[int32(frame.pc)]; loc == nil {
loc = &profile.Location{}
f.locs[int32(frame.pc)] = loc
}
if nn := n.children[loc]; nn == nil {
if n.children == nil {
n.children = make(map[*profile.Location]*profSampleNode, 1)
}
nn = &profSampleNode{
parent: n,
loc: loc,
}
n.children[loc] = nn
n = nn
} else {
n = nn
}
}
smpl := n.sample
if smpl == nil {
locs := make([]*profile.Location, 0, len(sampleFrames))
for n1 := n; n1.loc != nil; n1 = n1.parent {
locs = append(locs, n1.loc)
}
smpl = &profile.Sample{
Location: locs,
Value: make([]int64, 2),
}
n.sample = smpl
}
smpl.Value[0]++
smpl.Value[1] += int64(pt.stop.Sub(pt.start))
}
func (pb *profBuffer) profile() *profile.Profile {
pr := profile.Profile{}
pr.SampleType = []*profile.ValueType{
{Type: "samples", Unit: "count"},
{Type: "cpu", Unit: "nanoseconds"},
}
pr.PeriodType = pr.SampleType[1]
pr.Period = int64(profInterval)
mapping := &profile.Mapping{
ID: 1,
File: "[ECMAScript code]",
}
pr.Mapping = make([]*profile.Mapping, 1, len(pb.funcs)+1)
pr.Mapping[0] = mapping
pr.Function = make([]*profile.Function, 0, len(pb.funcs))
funcNames := make(map[string]struct{})
var funcId, locId uint64
for prg, f := range pb.funcs {
fileName := prg.src.Name()
funcId++
f.f.ID = funcId
f.f.Filename = fileName
var funcName string
if prg.funcName != "" {
funcName = prg.funcName.String()
} else {
funcName = "<anonymous>"
}
// Make sure the function name is unique, otherwise the graph display merges them into one node, even
// if they are in different mappings.
if _, exists := funcNames[funcName]; exists {
funcName += "." + strconv.FormatUint(f.f.ID, 10)
} else {
funcNames[funcName] = struct{}{}
}
f.f.Name = funcName
pr.Function = append(pr.Function, &f.f)
for pc, loc := range f.locs {
locId++
loc.ID = locId
pos := prg.src.Position(prg.sourceOffset(int(pc)))
loc.Line = []profile.Line{
{
Function: &f.f,
Line: int64(pos.Line),
},
}
loc.Mapping = mapping
pr.Location = append(pr.Location, loc)
}
}
pb.addSamples(&pr, &pb.root)
return &pr
}
func (pb *profBuffer) addSamples(p *profile.Profile, n *profSampleNode) {
if n.sample != nil {
p.Sample = append(p.Sample, n.sample)
}
for _, child := range n.children {
pb.addSamples(p, child)
}
}
func (p *profiler) run() {
ticker := time.NewTicker(profInterval)
counter := 0
L:
for ts := range ticker.C {
p.mu.Lock()
left := len(p.trackers)
for {
// This loop runs until either one of the VMs is signalled or all of the VMs are scanned and found
// busy or deleted.
if counter >= len(p.trackers) {
counter = 0
}
tracker := p.trackers[counter]
req := atomic.LoadInt32(&tracker.req)
if req == profReqSampleReady {
if p.buf != nil {
p.buf.addSample(tracker)
}
}
if atomic.LoadInt32(&tracker.finished) != 0 {
p.trackers[counter] = p.trackers[len(p.trackers)-1]
p.trackers[len(p.trackers)-1] = nil
p.trackers = p.trackers[:len(p.trackers)-1]
if len(p.trackers) == 0 {
break L
}
} else {
counter++
if p.buf != nil {
if req != profReqDoSample {
// signal the VM to take a sample
tracker.start = ts
atomic.StoreInt32(&tracker.req, profReqDoSample)
break
}
} else {
atomic.StoreInt32(&tracker.req, profReqStop)
}
}
left--
if left <= 0 {
// all VMs are busy
break
}
}
p.mu.Unlock()
}
ticker.Stop()
p.running = false
p.mu.Unlock()
}
func (p *profiler) registerVm() *profTracker {
pt := new(profTracker)
p.mu.Lock()
p.trackers = append(p.trackers, pt)
if !p.running {
go p.run()
p.running = true
}
p.mu.Unlock()
return pt
}
func (p *profiler) start() error {
p.mu.Lock()
if p.buf != nil {
p.mu.Unlock()
return errors.New("profiler is already active")
}
p.buf = new(profBuffer)
p.mu.Unlock()
return nil
}
func (p *profiler) stop() *profile.Profile {
p.mu.Lock()
buf := p.buf
p.buf = nil
p.mu.Unlock()
if buf != nil {
return buf.profile()
}
return nil
}
/*
StartProfile enables execution time profiling for all Runtimes within the current process.
This works similar to pprof.StartCPUProfile and produces the same format which can be consumed by `go tool pprof`.
There are, however, a few notable differences. Firstly, it's not a CPU profile, rather "execution time" profile.
It measures the time the VM spends executing an instruction. If this instruction happens to be a call to a
blocking Go function, the waiting time will be measured. Secondly, the 'cpu' sample isn't simply `count*period`,
it's the time interval between when sampling was requested and when the instruction has finished. If a VM is still
executing the same instruction when the time comes for the next sample, the sampling is skipped (i.e. `count` doesn't
grow).
If there are multiple functions with the same name, their names get a '.N' suffix, where N is a unique number,
because otherwise the graph view merges them together (even if they are in different mappings). This includes
"<anonymous>" functions.
The sampling period is set to 10ms.
It returns an error if profiling is already active.
*/
func StartProfile(w io.Writer) error {
err := globalProfiler.p.start()
if err != nil {
return err
}
globalProfiler.w = w
atomic.StoreInt32(&globalProfiler.enabled, 1)
return nil
}
/*
StopProfile stops the current profile initiated by StartProfile, if any.
*/
func StopProfile() {
atomic.StoreInt32(&globalProfiler.enabled, 0)
pr := globalProfiler.p.stop()
if pr != nil {
_ = pr.Write(globalProfiler.w)
}
globalProfiler.w = nil
}

1074
server/vendor/github.com/dop251/goja/proxy.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

643
server/vendor/github.com/dop251/goja/regexp.go generated vendored Normal file
View File

@@ -0,0 +1,643 @@
package goja
import (
"fmt"
"github.com/dlclark/regexp2"
"github.com/dop251/goja/unistring"
"io"
"regexp"
"sort"
"strings"
"unicode/utf16"
)
type regexp2MatchCache struct {
target valueString
runes []rune
posMap []int
}
// Not goroutine-safe. Use regexp2Wrapper.clone()
type regexp2Wrapper struct {
rx *regexp2.Regexp
cache *regexp2MatchCache
}
type regexpWrapper regexp.Regexp
type positionMapItem struct {
src, dst int
}
type positionMap []positionMapItem
func (m positionMap) get(src int) int {
if src <= 0 {
return src
}
res := sort.Search(len(m), func(n int) bool { return m[n].src >= src })
if res >= len(m) || m[res].src != src {
panic("index not found")
}
return m[res].dst
}
type arrayRuneReader struct {
runes []rune
pos int
}
func (rd *arrayRuneReader) ReadRune() (r rune, size int, err error) {
if rd.pos < len(rd.runes) {
r = rd.runes[rd.pos]
size = 1
rd.pos++
} else {
err = io.EOF
}
return
}
// Not goroutine-safe. Use regexpPattern.clone()
type regexpPattern struct {
src string
global, ignoreCase, multiline, sticky, unicode bool
regexpWrapper *regexpWrapper
regexp2Wrapper *regexp2Wrapper
}
func compileRegexp2(src string, multiline, ignoreCase bool) (*regexp2Wrapper, error) {
var opts regexp2.RegexOptions = regexp2.ECMAScript
if multiline {
opts |= regexp2.Multiline
}
if ignoreCase {
opts |= regexp2.IgnoreCase
}
regexp2Pattern, err1 := regexp2.Compile(src, opts)
if err1 != nil {
return nil, fmt.Errorf("Invalid regular expression (regexp2): %s (%v)", src, err1)
}
return &regexp2Wrapper{rx: regexp2Pattern}, nil
}
func (p *regexpPattern) createRegexp2() {
if p.regexp2Wrapper != nil {
return
}
rx, err := compileRegexp2(p.src, p.multiline, p.ignoreCase)
if err != nil {
// At this point the regexp should have been successfully converted to re2, if it fails now, it's a bug.
panic(err)
}
p.regexp2Wrapper = rx
}
func buildUTF8PosMap(s unicodeString) (positionMap, string) {
pm := make(positionMap, 0, s.length())
rd := s.reader()
sPos, utf8Pos := 0, 0
var sb strings.Builder
for {
r, size, err := rd.ReadRune()
if err == io.EOF {
break
}
if err != nil {
// the string contains invalid UTF-16, bailing out
return nil, ""
}
utf8Size, _ := sb.WriteRune(r)
sPos += size
utf8Pos += utf8Size
pm = append(pm, positionMapItem{src: utf8Pos, dst: sPos})
}
return pm, sb.String()
}
func (p *regexpPattern) findSubmatchIndex(s valueString, start int) []int {
if p.regexpWrapper == nil {
return p.regexp2Wrapper.findSubmatchIndex(s, start, p.unicode, p.global || p.sticky)
}
if start != 0 {
// Unfortunately Go's regexp library does not allow starting from an arbitrary position.
// If we just drop the first _start_ characters of the string the assertions (^, $, \b and \B) will not
// work correctly.
p.createRegexp2()
return p.regexp2Wrapper.findSubmatchIndex(s, start, p.unicode, p.global || p.sticky)
}
return p.regexpWrapper.findSubmatchIndex(s, p.unicode)
}
func (p *regexpPattern) findAllSubmatchIndex(s valueString, start int, limit int, sticky bool) [][]int {
if p.regexpWrapper == nil {
return p.regexp2Wrapper.findAllSubmatchIndex(s, start, limit, sticky, p.unicode)
}
if start == 0 {
a, u := devirtualizeString(s)
if u == nil {
return p.regexpWrapper.findAllSubmatchIndex(string(a), limit, sticky)
}
if limit == 1 {
result := p.regexpWrapper.findSubmatchIndexUnicode(u, p.unicode)
if result == nil {
return nil
}
return [][]int{result}
}
// Unfortunately Go's regexp library lacks FindAllReaderSubmatchIndex(), so we have to use a UTF-8 string as an
// input.
if p.unicode {
// Try to convert s to UTF-8. If it does not contain any invalid UTF-16 we can do the matching in UTF-8.
pm, str := buildUTF8PosMap(u)
if pm != nil {
res := p.regexpWrapper.findAllSubmatchIndex(str, limit, sticky)
for _, result := range res {
for i, idx := range result {
result[i] = pm.get(idx)
}
}
return res
}
}
}
p.createRegexp2()
return p.regexp2Wrapper.findAllSubmatchIndex(s, start, limit, sticky, p.unicode)
}
// clone creates a copy of the regexpPattern which can be used concurrently.
func (p *regexpPattern) clone() *regexpPattern {
ret := &regexpPattern{
src: p.src,
global: p.global,
ignoreCase: p.ignoreCase,
multiline: p.multiline,
sticky: p.sticky,
unicode: p.unicode,
}
if p.regexpWrapper != nil {
ret.regexpWrapper = p.regexpWrapper.clone()
}
if p.regexp2Wrapper != nil {
ret.regexp2Wrapper = p.regexp2Wrapper.clone()
}
return ret
}
type regexpObject struct {
baseObject
pattern *regexpPattern
source valueString
standard bool
}
func (r *regexp2Wrapper) findSubmatchIndex(s valueString, start int, fullUnicode, doCache bool) (result []int) {
if fullUnicode {
return r.findSubmatchIndexUnicode(s, start, doCache)
}
return r.findSubmatchIndexUTF16(s, start, doCache)
}
func (r *regexp2Wrapper) findUTF16Cached(s valueString, start int, doCache bool) (match *regexp2.Match, runes []rune, err error) {
wrapped := r.rx
cache := r.cache
if cache != nil && cache.posMap == nil && cache.target.SameAs(s) {
runes = cache.runes
} else {
runes = s.utf16Runes()
cache = nil
}
match, err = wrapped.FindRunesMatchStartingAt(runes, start)
if doCache && match != nil && err == nil {
if cache == nil {
if r.cache == nil {
r.cache = new(regexp2MatchCache)
}
*r.cache = regexp2MatchCache{
target: s,
runes: runes,
}
}
} else {
r.cache = nil
}
return
}
func (r *regexp2Wrapper) findSubmatchIndexUTF16(s valueString, start int, doCache bool) (result []int) {
match, _, err := r.findUTF16Cached(s, start, doCache)
if err != nil {
return
}
if match == nil {
return
}
groups := match.Groups()
result = make([]int, 0, len(groups)<<1)
for _, group := range groups {
if len(group.Captures) > 0 {
result = append(result, group.Index, group.Index+group.Length)
} else {
result = append(result, -1, 0)
}
}
return
}
func (r *regexp2Wrapper) findUnicodeCached(s valueString, start int, doCache bool) (match *regexp2.Match, posMap []int, err error) {
var (
runes []rune
mappedStart int
splitPair bool
savedRune rune
)
wrapped := r.rx
cache := r.cache
if cache != nil && cache.posMap != nil && cache.target.SameAs(s) {
runes, posMap = cache.runes, cache.posMap
mappedStart, splitPair = posMapReverseLookup(posMap, start)
} else {
posMap, runes, mappedStart, splitPair = buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader()}, s.length(), start)
cache = nil
}
if splitPair {
// temporarily set the rune at mappedStart to the second code point of the pair
_, second := utf16.EncodeRune(runes[mappedStart])
savedRune, runes[mappedStart] = runes[mappedStart], second
}
match, err = wrapped.FindRunesMatchStartingAt(runes, mappedStart)
if doCache && match != nil && err == nil {
if splitPair {
runes[mappedStart] = savedRune
}
if cache == nil {
if r.cache == nil {
r.cache = new(regexp2MatchCache)
}
*r.cache = regexp2MatchCache{
target: s,
runes: runes,
posMap: posMap,
}
}
} else {
r.cache = nil
}
return
}
func (r *regexp2Wrapper) findSubmatchIndexUnicode(s valueString, start int, doCache bool) (result []int) {
match, posMap, err := r.findUnicodeCached(s, start, doCache)
if match == nil || err != nil {
return
}
groups := match.Groups()
result = make([]int, 0, len(groups)<<1)
for _, group := range groups {
if len(group.Captures) > 0 {
result = append(result, posMap[group.Index], posMap[group.Index+group.Length])
} else {
result = append(result, -1, 0)
}
}
return
}
func (r *regexp2Wrapper) findAllSubmatchIndexUTF16(s valueString, start, limit int, sticky bool) [][]int {
wrapped := r.rx
match, runes, err := r.findUTF16Cached(s, start, false)
if match == nil || err != nil {
return nil
}
if limit < 0 {
limit = len(runes) + 1
}
results := make([][]int, 0, limit)
for match != nil {
groups := match.Groups()
result := make([]int, 0, len(groups)<<1)
for _, group := range groups {
if len(group.Captures) > 0 {
startPos := group.Index
endPos := group.Index + group.Length
result = append(result, startPos, endPos)
} else {
result = append(result, -1, 0)
}
}
if sticky && len(result) > 1 {
if result[0] != start {
break
}
start = result[1]
}
results = append(results, result)
limit--
if limit <= 0 {
break
}
match, err = wrapped.FindNextMatch(match)
if err != nil {
return nil
}
}
return results
}
func buildPosMap(rd io.RuneReader, l, start int) (posMap []int, runes []rune, mappedStart int, splitPair bool) {
posMap = make([]int, 0, l+1)
curPos := 0
runes = make([]rune, 0, l)
startFound := false
for {
if !startFound {
if curPos == start {
mappedStart = len(runes)
startFound = true
}
if curPos > start {
// start position splits a surrogate pair
mappedStart = len(runes) - 1
splitPair = true
startFound = true
}
}
rn, size, err := rd.ReadRune()
if err != nil {
break
}
runes = append(runes, rn)
posMap = append(posMap, curPos)
curPos += size
}
posMap = append(posMap, curPos)
return
}
func posMapReverseLookup(posMap []int, pos int) (int, bool) {
mapped := sort.SearchInts(posMap, pos)
if mapped < len(posMap) && posMap[mapped] != pos {
return mapped - 1, true
}
return mapped, false
}
func (r *regexp2Wrapper) findAllSubmatchIndexUnicode(s unicodeString, start, limit int, sticky bool) [][]int {
wrapped := r.rx
if limit < 0 {
limit = len(s) + 1
}
results := make([][]int, 0, limit)
match, posMap, err := r.findUnicodeCached(s, start, false)
if err != nil {
return nil
}
for match != nil {
groups := match.Groups()
result := make([]int, 0, len(groups)<<1)
for _, group := range groups {
if len(group.Captures) > 0 {
start := posMap[group.Index]
end := posMap[group.Index+group.Length]
result = append(result, start, end)
} else {
result = append(result, -1, 0)
}
}
if sticky && len(result) > 1 {
if result[0] != start {
break
}
start = result[1]
}
results = append(results, result)
match, err = wrapped.FindNextMatch(match)
if err != nil {
return nil
}
}
return results
}
func (r *regexp2Wrapper) findAllSubmatchIndex(s valueString, start, limit int, sticky, fullUnicode bool) [][]int {
a, u := devirtualizeString(s)
if u != nil {
if fullUnicode {
return r.findAllSubmatchIndexUnicode(u, start, limit, sticky)
}
return r.findAllSubmatchIndexUTF16(u, start, limit, sticky)
}
return r.findAllSubmatchIndexUTF16(a, start, limit, sticky)
}
func (r *regexp2Wrapper) clone() *regexp2Wrapper {
return &regexp2Wrapper{
rx: r.rx,
}
}
func (r *regexpWrapper) findAllSubmatchIndex(s string, limit int, sticky bool) (results [][]int) {
wrapped := (*regexp.Regexp)(r)
results = wrapped.FindAllStringSubmatchIndex(s, limit)
pos := 0
if sticky {
for i, result := range results {
if len(result) > 1 {
if result[0] != pos {
return results[:i]
}
pos = result[1]
}
}
}
return
}
func (r *regexpWrapper) findSubmatchIndex(s valueString, fullUnicode bool) []int {
a, u := devirtualizeString(s)
if u != nil {
return r.findSubmatchIndexUnicode(u, fullUnicode)
}
return r.findSubmatchIndexASCII(string(a))
}
func (r *regexpWrapper) findSubmatchIndexASCII(s string) []int {
wrapped := (*regexp.Regexp)(r)
return wrapped.FindStringSubmatchIndex(s)
}
func (r *regexpWrapper) findSubmatchIndexUnicode(s unicodeString, fullUnicode bool) (result []int) {
wrapped := (*regexp.Regexp)(r)
if fullUnicode {
posMap, runes, _, _ := buildPosMap(&lenientUtf16Decoder{utf16Reader: s.utf16Reader()}, s.length(), 0)
res := wrapped.FindReaderSubmatchIndex(&arrayRuneReader{runes: runes})
for i, item := range res {
if item >= 0 {
res[i] = posMap[item]
}
}
return res
}
return wrapped.FindReaderSubmatchIndex(s.utf16Reader())
}
func (r *regexpWrapper) clone() *regexpWrapper {
return r
}
func (r *regexpObject) execResultToArray(target valueString, result []int) Value {
captureCount := len(result) >> 1
valueArray := make([]Value, captureCount)
matchIndex := result[0]
valueArray[0] = target.substring(result[0], result[1])
lowerBound := 0
for index := 1; index < captureCount; index++ {
offset := index << 1
if result[offset] >= 0 && result[offset+1] >= lowerBound {
valueArray[index] = target.substring(result[offset], result[offset+1])
lowerBound = result[offset]
} else {
valueArray[index] = _undefined
}
}
match := r.val.runtime.newArrayValues(valueArray)
match.self.setOwnStr("input", target, false)
match.self.setOwnStr("index", intToValue(int64(matchIndex)), false)
return match
}
func (r *regexpObject) getLastIndex() int64 {
lastIndex := toLength(r.getStr("lastIndex", nil))
if !r.pattern.global && !r.pattern.sticky {
return 0
}
return lastIndex
}
func (r *regexpObject) updateLastIndex(index int64, firstResult, lastResult []int) bool {
if r.pattern.sticky {
if firstResult == nil || int64(firstResult[0]) != index {
r.setOwnStr("lastIndex", intToValue(0), true)
return false
}
} else {
if firstResult == nil {
if r.pattern.global {
r.setOwnStr("lastIndex", intToValue(0), true)
}
return false
}
}
if r.pattern.global || r.pattern.sticky {
r.setOwnStr("lastIndex", intToValue(int64(lastResult[1])), true)
}
return true
}
func (r *regexpObject) execRegexp(target valueString) (match bool, result []int) {
index := r.getLastIndex()
if index >= 0 && index <= int64(target.length()) {
result = r.pattern.findSubmatchIndex(target, int(index))
}
match = r.updateLastIndex(index, result, result)
return
}
func (r *regexpObject) exec(target valueString) Value {
match, result := r.execRegexp(target)
if match {
return r.execResultToArray(target, result)
}
return _null
}
func (r *regexpObject) test(target valueString) bool {
match, _ := r.execRegexp(target)
return match
}
func (r *regexpObject) clone() *regexpObject {
r1 := r.val.runtime.newRegexpObject(r.prototype)
r1.source = r.source
r1.pattern = r.pattern
return r1
}
func (r *regexpObject) init() {
r.baseObject.init()
r.standard = true
r._putProp("lastIndex", intToValue(0), true, false, false)
}
func (r *regexpObject) setProto(proto *Object, throw bool) bool {
res := r.baseObject.setProto(proto, throw)
if res {
r.standard = false
}
return res
}
func (r *regexpObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
res := r.baseObject.defineOwnPropertyStr(name, desc, throw)
if res {
r.standard = false
}
return res
}
func (r *regexpObject) defineOwnPropertySym(name *Symbol, desc PropertyDescriptor, throw bool) bool {
res := r.baseObject.defineOwnPropertySym(name, desc, throw)
if res && r.standard {
switch name {
case SymMatch, SymMatchAll, SymSearch, SymSplit, SymReplace:
r.standard = false
}
}
return res
}
func (r *regexpObject) deleteStr(name unistring.String, throw bool) bool {
res := r.baseObject.deleteStr(name, throw)
if res {
r.standard = false
}
return res
}
func (r *regexpObject) setOwnStr(name unistring.String, value Value, throw bool) bool {
res := r.baseObject.setOwnStr(name, value, throw)
if res && r.standard && name == "exec" {
r.standard = false
}
return res
}
func (r *regexpObject) setOwnSym(name *Symbol, value Value, throw bool) bool {
res := r.baseObject.setOwnSym(name, value, throw)
if res && r.standard {
switch name {
case SymMatch, SymMatchAll, SymSearch, SymSplit, SymReplace:
r.standard = false
}
}
return res
}

3184
server/vendor/github.com/dop251/goja/runtime.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
checks = ["all", "-ST1000", "-ST1003", "-ST1005", "-ST1006", "-ST1012", "-ST1021", "-ST1020", "-ST1008"]

329
server/vendor/github.com/dop251/goja/string.go generated vendored Normal file
View File

@@ -0,0 +1,329 @@
package goja
import (
"io"
"strconv"
"strings"
"unicode/utf8"
"github.com/dop251/goja/unistring"
)
const (
__proto__ = "__proto__"
)
var (
stringTrue valueString = asciiString("true")
stringFalse valueString = asciiString("false")
stringNull valueString = asciiString("null")
stringUndefined valueString = asciiString("undefined")
stringObjectC valueString = asciiString("object")
stringFunction valueString = asciiString("function")
stringBoolean valueString = asciiString("boolean")
stringString valueString = asciiString("string")
stringSymbol valueString = asciiString("symbol")
stringNumber valueString = asciiString("number")
stringNaN valueString = asciiString("NaN")
stringInfinity = asciiString("Infinity")
stringNegInfinity = asciiString("-Infinity")
stringBound_ valueString = asciiString("bound ")
stringEmpty valueString = asciiString("")
stringError valueString = asciiString("Error")
stringAggregateError valueString = asciiString("AggregateError")
stringTypeError valueString = asciiString("TypeError")
stringReferenceError valueString = asciiString("ReferenceError")
stringSyntaxError valueString = asciiString("SyntaxError")
stringRangeError valueString = asciiString("RangeError")
stringEvalError valueString = asciiString("EvalError")
stringURIError valueString = asciiString("URIError")
stringGoError valueString = asciiString("GoError")
stringObjectNull valueString = asciiString("[object Null]")
stringObjectUndefined valueString = asciiString("[object Undefined]")
stringInvalidDate valueString = asciiString("Invalid Date")
)
type valueString interface {
Value
charAt(int) rune
length() int
concat(valueString) valueString
substring(start, end int) valueString
compareTo(valueString) int
reader() io.RuneReader
utf16Reader() io.RuneReader
utf16Runes() []rune
index(valueString, int) int
lastIndex(valueString, int) int
toLower() valueString
toUpper() valueString
toTrimmedUTF8() string
}
type stringIterObject struct {
baseObject
reader io.RuneReader
}
func isUTF16FirstSurrogate(r rune) bool {
return r >= 0xD800 && r <= 0xDBFF
}
func isUTF16SecondSurrogate(r rune) bool {
return r >= 0xDC00 && r <= 0xDFFF
}
func (si *stringIterObject) next() Value {
if si.reader == nil {
return si.val.runtime.createIterResultObject(_undefined, true)
}
r, _, err := si.reader.ReadRune()
if err == io.EOF {
si.reader = nil
return si.val.runtime.createIterResultObject(_undefined, true)
}
return si.val.runtime.createIterResultObject(stringFromRune(r), false)
}
func stringFromRune(r rune) valueString {
if r < utf8.RuneSelf {
var sb strings.Builder
sb.WriteByte(byte(r))
return asciiString(sb.String())
}
var sb unicodeStringBuilder
sb.WriteRune(r)
return sb.String()
}
func (r *Runtime) createStringIterator(s valueString) Value {
o := &Object{runtime: r}
si := &stringIterObject{
reader: &lenientUtf16Decoder{utf16Reader: s.utf16Reader()},
}
si.class = classObject
si.val = o
si.extensible = true
o.self = si
si.prototype = r.getStringIteratorPrototype()
si.init()
return o
}
type stringObject struct {
baseObject
value valueString
length int
lengthProp valueProperty
}
func newStringValue(s string) valueString {
if u := unistring.Scan(s); u != nil {
return unicodeString(u)
}
return asciiString(s)
}
func stringValueFromRaw(raw unistring.String) valueString {
if b := raw.AsUtf16(); b != nil {
return unicodeString(b)
}
return asciiString(raw)
}
func (s *stringObject) init() {
s.baseObject.init()
s.setLength()
}
func (s *stringObject) setLength() {
if s.value != nil {
s.length = s.value.length()
}
s.lengthProp.value = intToValue(int64(s.length))
s._put("length", &s.lengthProp)
}
func (s *stringObject) getStr(name unistring.String, receiver Value) Value {
if i := strToGoIdx(name); i >= 0 && i < s.length {
return s._getIdx(i)
}
return s.baseObject.getStr(name, receiver)
}
func (s *stringObject) getIdx(idx valueInt, receiver Value) Value {
i := int(idx)
if i >= 0 && i < s.length {
return s._getIdx(i)
}
return s.baseObject.getStr(idx.string(), receiver)
}
func (s *stringObject) getOwnPropStr(name unistring.String) Value {
if i := strToGoIdx(name); i >= 0 && i < s.length {
val := s._getIdx(i)
return &valueProperty{
value: val,
enumerable: true,
}
}
return s.baseObject.getOwnPropStr(name)
}
func (s *stringObject) getOwnPropIdx(idx valueInt) Value {
i := int64(idx)
if i >= 0 {
if i < int64(s.length) {
val := s._getIdx(int(i))
return &valueProperty{
value: val,
enumerable: true,
}
}
return nil
}
return s.baseObject.getOwnPropStr(idx.string())
}
func (s *stringObject) _getIdx(idx int) Value {
return s.value.substring(idx, idx+1)
}
func (s *stringObject) setOwnStr(name unistring.String, val Value, throw bool) bool {
if i := strToGoIdx(name); i >= 0 && i < s.length {
s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
return false
}
return s.baseObject.setOwnStr(name, val, throw)
}
func (s *stringObject) setOwnIdx(idx valueInt, val Value, throw bool) bool {
i := int64(idx)
if i >= 0 && i < int64(s.length) {
s.val.runtime.typeErrorResult(throw, "Cannot assign to read only property '%d' of a String", i)
return false
}
return s.baseObject.setOwnStr(idx.string(), val, throw)
}
func (s *stringObject) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
return s._setForeignStr(name, s.getOwnPropStr(name), val, receiver, throw)
}
func (s *stringObject) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
return s._setForeignIdx(idx, s.getOwnPropIdx(idx), val, receiver, throw)
}
func (s *stringObject) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
if i := strToGoIdx(name); i >= 0 && i < s.length {
_, ok := s._defineOwnProperty(name, &valueProperty{enumerable: true}, descr, throw)
return ok
}
return s.baseObject.defineOwnPropertyStr(name, descr, throw)
}
func (s *stringObject) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool {
i := int64(idx)
if i >= 0 && i < int64(s.length) {
s.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", i)
return false
}
return s.baseObject.defineOwnPropertyStr(idx.string(), descr, throw)
}
type stringPropIter struct {
str valueString // separate, because obj can be the singleton
obj *stringObject
idx, length int
}
func (i *stringPropIter) next() (propIterItem, iterNextFunc) {
if i.idx < i.length {
name := strconv.Itoa(i.idx)
i.idx++
return propIterItem{name: asciiString(name), enumerable: _ENUM_TRUE}, i.next
}
return i.obj.baseObject.iterateStringKeys()()
}
func (s *stringObject) iterateStringKeys() iterNextFunc {
return (&stringPropIter{
str: s.value,
obj: s,
length: s.length,
}).next
}
func (s *stringObject) stringKeys(all bool, accum []Value) []Value {
for i := 0; i < s.length; i++ {
accum = append(accum, asciiString(strconv.Itoa(i)))
}
return s.baseObject.stringKeys(all, accum)
}
func (s *stringObject) deleteStr(name unistring.String, throw bool) bool {
if i := strToGoIdx(name); i >= 0 && i < s.length {
s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
return false
}
return s.baseObject.deleteStr(name, throw)
}
func (s *stringObject) deleteIdx(idx valueInt, throw bool) bool {
i := int64(idx)
if i >= 0 && i < int64(s.length) {
s.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of a String", i)
return false
}
return s.baseObject.deleteStr(idx.string(), throw)
}
func (s *stringObject) hasOwnPropertyStr(name unistring.String) bool {
if i := strToGoIdx(name); i >= 0 && i < s.length {
return true
}
return s.baseObject.hasOwnPropertyStr(name)
}
func (s *stringObject) hasOwnPropertyIdx(idx valueInt) bool {
i := int64(idx)
if i >= 0 && i < int64(s.length) {
return true
}
return s.baseObject.hasOwnPropertyStr(idx.string())
}
func devirtualizeString(s valueString) (asciiString, unicodeString) {
switch s := s.(type) {
case asciiString:
return s, nil
case unicodeString:
return "", s
case *importedString:
s.ensureScanned()
if s.u != nil {
return "", s.u
}
return asciiString(s.s), nil
default:
panic(unknownStringTypeErr(s))
}
}
func unknownStringTypeErr(v Value) interface{} {
return newTypeError("Internal bug: unknown string type: %T", v)
}

327
server/vendor/github.com/dop251/goja/string_ascii.go generated vendored Normal file
View File

@@ -0,0 +1,327 @@
package goja
import (
"hash/maphash"
"io"
"math"
"reflect"
"strconv"
"strings"
"github.com/dop251/goja/unistring"
)
type asciiString string
type asciiRuneReader struct {
s asciiString
pos int
}
func (rr *asciiRuneReader) ReadRune() (r rune, size int, err error) {
if rr.pos < len(rr.s) {
r = rune(rr.s[rr.pos])
size = 1
rr.pos++
} else {
err = io.EOF
}
return
}
func (s asciiString) reader() io.RuneReader {
return &asciiRuneReader{
s: s,
}
}
func (s asciiString) utf16Reader() io.RuneReader {
return s.reader()
}
func (s asciiString) utf16Runes() []rune {
runes := make([]rune, len(s))
for i := 0; i < len(s); i++ {
runes[i] = rune(s[i])
}
return runes
}
// ss must be trimmed
func stringToInt(ss string) (int64, error) {
if ss == "" {
return 0, nil
}
if ss == "-0" {
return 0, strconv.ErrSyntax
}
if len(ss) > 2 {
switch ss[:2] {
case "0x", "0X":
return strconv.ParseInt(ss[2:], 16, 64)
case "0b", "0B":
return strconv.ParseInt(ss[2:], 2, 64)
case "0o", "0O":
return strconv.ParseInt(ss[2:], 8, 64)
}
}
return strconv.ParseInt(ss, 10, 64)
}
func (s asciiString) _toInt() (int64, error) {
return stringToInt(strings.TrimSpace(string(s)))
}
func isRangeErr(err error) bool {
if err, ok := err.(*strconv.NumError); ok {
return err.Err == strconv.ErrRange
}
return false
}
func (s asciiString) _toFloat() (float64, error) {
ss := strings.TrimSpace(string(s))
if ss == "" {
return 0, nil
}
if ss == "-0" {
var f float64
return -f, nil
}
f, err := strconv.ParseFloat(ss, 64)
if isRangeErr(err) {
err = nil
}
return f, err
}
func (s asciiString) ToInteger() int64 {
if s == "" {
return 0
}
if s == "Infinity" || s == "+Infinity" {
return math.MaxInt64
}
if s == "-Infinity" {
return math.MinInt64
}
i, err := s._toInt()
if err != nil {
f, err := s._toFloat()
if err == nil {
return int64(f)
}
}
return i
}
func (s asciiString) toString() valueString {
return s
}
func (s asciiString) ToString() Value {
return s
}
func (s asciiString) String() string {
return string(s)
}
func (s asciiString) ToFloat() float64 {
if s == "" {
return 0
}
if s == "Infinity" || s == "+Infinity" {
return math.Inf(1)
}
if s == "-Infinity" {
return math.Inf(-1)
}
f, err := s._toFloat()
if err != nil {
i, err := s._toInt()
if err == nil {
return float64(i)
}
f = math.NaN()
}
return f
}
func (s asciiString) ToBoolean() bool {
return s != ""
}
func (s asciiString) ToNumber() Value {
if s == "" {
return intToValue(0)
}
if s == "Infinity" || s == "+Infinity" {
return _positiveInf
}
if s == "-Infinity" {
return _negativeInf
}
if i, err := s._toInt(); err == nil {
return intToValue(i)
}
if f, err := s._toFloat(); err == nil {
return floatToValue(f)
}
return _NaN
}
func (s asciiString) ToObject(r *Runtime) *Object {
return r._newString(s, r.global.StringPrototype)
}
func (s asciiString) SameAs(other Value) bool {
return s.StrictEquals(other)
}
func (s asciiString) Equals(other Value) bool {
if s.StrictEquals(other) {
return true
}
if o, ok := other.(valueInt); ok {
if o1, e := s._toInt(); e == nil {
return o1 == int64(o)
}
return false
}
if o, ok := other.(valueFloat); ok {
return s.ToFloat() == float64(o)
}
if o, ok := other.(valueBool); ok {
if o1, e := s._toFloat(); e == nil {
return o1 == o.ToFloat()
}
return false
}
if o, ok := other.(*Object); ok {
return s.Equals(o.toPrimitive())
}
return false
}
func (s asciiString) StrictEquals(other Value) bool {
if otherStr, ok := other.(asciiString); ok {
return s == otherStr
}
if otherStr, ok := other.(*importedString); ok {
if otherStr.u == nil {
return string(s) == otherStr.s
}
}
return false
}
func (s asciiString) baseObject(r *Runtime) *Object {
ss := r.stringSingleton
ss.value = s
ss.setLength()
return ss.val
}
func (s asciiString) hash(hash *maphash.Hash) uint64 {
_, _ = hash.WriteString(string(s))
h := hash.Sum64()
hash.Reset()
return h
}
func (s asciiString) charAt(idx int) rune {
return rune(s[idx])
}
func (s asciiString) length() int {
return len(s)
}
func (s asciiString) concat(other valueString) valueString {
a, u := devirtualizeString(other)
if u != nil {
b := make([]uint16, len(s)+len(u))
b[0] = unistring.BOM
for i := 0; i < len(s); i++ {
b[i+1] = uint16(s[i])
}
copy(b[len(s)+1:], u[1:])
return unicodeString(b)
}
return s + a
}
func (s asciiString) substring(start, end int) valueString {
return s[start:end]
}
func (s asciiString) compareTo(other valueString) int {
switch other := other.(type) {
case asciiString:
return strings.Compare(string(s), string(other))
case unicodeString:
return strings.Compare(string(s), other.String())
case *importedString:
return strings.Compare(string(s), other.s)
default:
panic(newTypeError("Internal bug: unknown string type: %T", other))
}
}
func (s asciiString) index(substr valueString, start int) int {
a, u := devirtualizeString(substr)
if u == nil {
p := strings.Index(string(s[start:]), string(a))
if p >= 0 {
return p + start
}
}
return -1
}
func (s asciiString) lastIndex(substr valueString, pos int) int {
a, u := devirtualizeString(substr)
if u == nil {
end := pos + len(a)
var ss string
if end > len(s) {
ss = string(s)
} else {
ss = string(s[:end])
}
return strings.LastIndex(ss, string(a))
}
return -1
}
func (s asciiString) toLower() valueString {
return asciiString(strings.ToLower(string(s)))
}
func (s asciiString) toUpper() valueString {
return asciiString(strings.ToUpper(string(s)))
}
func (s asciiString) toTrimmedUTF8() string {
return strings.TrimSpace(string(s))
}
func (s asciiString) string() unistring.String {
return unistring.String(s)
}
func (s asciiString) Export() interface{} {
return string(s)
}
func (s asciiString) ExportType() reflect.Type {
return reflectTypeString
}

288
server/vendor/github.com/dop251/goja/string_imported.go generated vendored Normal file
View File

@@ -0,0 +1,288 @@
package goja
import (
"hash/maphash"
"io"
"math"
"reflect"
"strings"
"unicode/utf16"
"unicode/utf8"
"github.com/dop251/goja/parser"
"github.com/dop251/goja/unistring"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
// Represents a string imported from Go. The idea is to delay the scanning for unicode characters and converting
// to unicodeString until necessary. This way strings that are merely passed through never get scanned which
// saves CPU and memory.
// Currently, importedString is created in 2 cases: Runtime.ToValue() for strings longer than 16 bytes and as a result
// of JSON.stringify() if it may contain unicode characters. More cases could be added in the future.
type importedString struct {
s string
u unicodeString
scanned bool
}
func (i *importedString) scan() {
i.u = unistring.Scan(i.s)
i.scanned = true
}
func (i *importedString) ensureScanned() {
if !i.scanned {
i.scan()
}
}
func (i *importedString) ToInteger() int64 {
i.ensureScanned()
if i.u != nil {
return 0
}
return asciiString(i.s).ToInteger()
}
func (i *importedString) toString() valueString {
return i
}
func (i *importedString) string() unistring.String {
i.ensureScanned()
if i.u != nil {
return unistring.FromUtf16(i.u)
}
return unistring.String(i.s)
}
func (i *importedString) ToString() Value {
return i
}
func (i *importedString) String() string {
return i.s
}
func (i *importedString) ToFloat() float64 {
i.ensureScanned()
if i.u != nil {
return math.NaN()
}
return asciiString(i.s).ToFloat()
}
func (i *importedString) ToNumber() Value {
i.ensureScanned()
if i.u != nil {
return i.u.ToNumber()
}
return asciiString(i.s).ToNumber()
}
func (i *importedString) ToBoolean() bool {
return len(i.s) != 0
}
func (i *importedString) ToObject(r *Runtime) *Object {
return r._newString(i, r.global.StringPrototype)
}
func (i *importedString) SameAs(other Value) bool {
return i.StrictEquals(other)
}
func (i *importedString) Equals(other Value) bool {
if i.StrictEquals(other) {
return true
}
i.ensureScanned()
if i.u != nil {
return i.u.Equals(other)
}
return asciiString(i.s).Equals(other)
}
func (i *importedString) StrictEquals(other Value) bool {
switch otherStr := other.(type) {
case asciiString:
if i.u != nil {
return false
}
return i.s == string(otherStr)
case unicodeString:
i.ensureScanned()
if i.u != nil && i.u.equals(otherStr) {
return true
}
case *importedString:
return i.s == otherStr.s
}
return false
}
func (i *importedString) Export() interface{} {
return i.s
}
func (i *importedString) ExportType() reflect.Type {
return reflectTypeString
}
func (i *importedString) baseObject(r *Runtime) *Object {
i.ensureScanned()
if i.u != nil {
return i.u.baseObject(r)
}
return asciiString(i.s).baseObject(r)
}
func (i *importedString) hash(hasher *maphash.Hash) uint64 {
i.ensureScanned()
if i.u != nil {
return i.u.hash(hasher)
}
return asciiString(i.s).hash(hasher)
}
func (i *importedString) charAt(idx int) rune {
i.ensureScanned()
if i.u != nil {
return i.u.charAt(idx)
}
return asciiString(i.s).charAt(idx)
}
func (i *importedString) length() int {
i.ensureScanned()
if i.u != nil {
return i.u.length()
}
return asciiString(i.s).length()
}
func (i *importedString) concat(v valueString) valueString {
if !i.scanned {
if v, ok := v.(*importedString); ok {
if !v.scanned {
return &importedString{s: i.s + v.s}
}
}
i.ensureScanned()
}
if i.u != nil {
return i.u.concat(v)
}
return asciiString(i.s).concat(v)
}
func (i *importedString) substring(start, end int) valueString {
i.ensureScanned()
if i.u != nil {
return i.u.substring(start, end)
}
return asciiString(i.s).substring(start, end)
}
func (i *importedString) compareTo(v valueString) int {
return strings.Compare(i.s, v.String())
}
func (i *importedString) reader() io.RuneReader {
if i.scanned {
if i.u != nil {
return i.u.reader()
}
return asciiString(i.s).reader()
}
return strings.NewReader(i.s)
}
type stringUtf16Reader struct {
s string
pos int
second rune
}
func (s *stringUtf16Reader) ReadRune() (r rune, size int, err error) {
if s.second >= 0 {
r = s.second
s.second = -1
size = 1
return
}
if s.pos < len(s.s) {
r1, size1 := utf8.DecodeRuneInString(s.s[s.pos:])
s.pos += size1
size = 1
if r1 <= 0xFFFF {
r = r1
} else {
r, s.second = utf16.EncodeRune(r1)
}
} else {
err = io.EOF
}
return
}
func (i *importedString) utf16Reader() io.RuneReader {
if i.scanned {
if i.u != nil {
return i.u.utf16Reader()
}
return asciiString(i.s).utf16Reader()
}
return &stringUtf16Reader{
s: i.s,
second: -1,
}
}
func (i *importedString) utf16Runes() []rune {
i.ensureScanned()
if i.u != nil {
return i.u.utf16Runes()
}
return asciiString(i.s).utf16Runes()
}
func (i *importedString) index(v valueString, start int) int {
i.ensureScanned()
if i.u != nil {
return i.u.index(v, start)
}
return asciiString(i.s).index(v, start)
}
func (i *importedString) lastIndex(v valueString, pos int) int {
i.ensureScanned()
if i.u != nil {
return i.u.lastIndex(v, pos)
}
return asciiString(i.s).lastIndex(v, pos)
}
func (i *importedString) toLower() valueString {
i.ensureScanned()
if i.u != nil {
return toLower(i.s)
}
return asciiString(i.s).toLower()
}
func (i *importedString) toUpper() valueString {
i.ensureScanned()
if i.u != nil {
caser := cases.Upper(language.Und)
return newStringValue(caser.String(i.s))
}
return asciiString(i.s).toUpper()
}
func (i *importedString) toTrimmedUTF8() string {
return strings.Trim(i.s, parser.WhitespaceChars)
}

560
server/vendor/github.com/dop251/goja/string_unicode.go generated vendored Normal file
View File

@@ -0,0 +1,560 @@
package goja
import (
"errors"
"hash/maphash"
"io"
"math"
"reflect"
"strings"
"unicode/utf16"
"unicode/utf8"
"github.com/dop251/goja/parser"
"github.com/dop251/goja/unistring"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
type unicodeString []uint16
type unicodeRuneReader struct {
s unicodeString
pos int
}
type utf16RuneReader struct {
s unicodeString
pos int
}
// passes through invalid surrogate pairs
type lenientUtf16Decoder struct {
utf16Reader io.RuneReader
prev rune
prevSet bool
}
type valueStringBuilder struct {
asciiBuilder strings.Builder
unicodeBuilder unicodeStringBuilder
}
type unicodeStringBuilder struct {
buf []uint16
unicode bool
}
var (
InvalidRuneError = errors.New("invalid rune")
)
func (rr *utf16RuneReader) ReadRune() (r rune, size int, err error) {
if rr.pos < len(rr.s) {
r = rune(rr.s[rr.pos])
size++
rr.pos++
return
}
err = io.EOF
return
}
func (rr *lenientUtf16Decoder) ReadRune() (r rune, size int, err error) {
if rr.prevSet {
r = rr.prev
size = 1
rr.prevSet = false
} else {
r, size, err = rr.utf16Reader.ReadRune()
if err != nil {
return
}
}
if isUTF16FirstSurrogate(r) {
second, _, err1 := rr.utf16Reader.ReadRune()
if err1 != nil {
if err1 != io.EOF {
err = err1
}
return
}
if isUTF16SecondSurrogate(second) {
r = utf16.DecodeRune(r, second)
size++
} else {
rr.prev = second
rr.prevSet = true
}
}
return
}
func (rr *unicodeRuneReader) ReadRune() (r rune, size int, err error) {
if rr.pos < len(rr.s) {
r = rune(rr.s[rr.pos])
size++
rr.pos++
if isUTF16FirstSurrogate(r) {
if rr.pos < len(rr.s) {
second := rune(rr.s[rr.pos])
if isUTF16SecondSurrogate(second) {
r = utf16.DecodeRune(r, second)
size++
rr.pos++
} else {
err = InvalidRuneError
}
} else {
err = InvalidRuneError
}
} else if isUTF16SecondSurrogate(r) {
err = InvalidRuneError
}
} else {
err = io.EOF
}
return
}
func (b *unicodeStringBuilder) Grow(n int) {
if len(b.buf) == 0 {
n++
}
if cap(b.buf)-len(b.buf) < n {
buf := make([]uint16, len(b.buf), 2*cap(b.buf)+n)
copy(buf, b.buf)
b.buf = buf
}
}
func (b *unicodeStringBuilder) ensureStarted(initialSize int) {
b.Grow(initialSize)
if len(b.buf) == 0 {
b.buf = append(b.buf, unistring.BOM)
}
}
func (b *unicodeStringBuilder) WriteString(s valueString) {
b.ensureStarted(s.length())
a, u := devirtualizeString(s)
if u != nil {
b.buf = append(b.buf, u[1:]...)
b.unicode = true
} else {
for i := 0; i < len(a); i++ {
b.buf = append(b.buf, uint16(a[i]))
}
}
}
func (b *unicodeStringBuilder) String() valueString {
if b.unicode {
return unicodeString(b.buf)
}
if len(b.buf) == 0 {
return stringEmpty
}
buf := make([]byte, 0, len(b.buf)-1)
for _, c := range b.buf[1:] {
buf = append(buf, byte(c))
}
return asciiString(buf)
}
func (b *unicodeStringBuilder) WriteRune(r rune) {
if r <= 0xFFFF {
b.ensureStarted(1)
b.buf = append(b.buf, uint16(r))
if !b.unicode && r >= utf8.RuneSelf {
b.unicode = true
}
} else {
b.ensureStarted(2)
first, second := utf16.EncodeRune(r)
b.buf = append(b.buf, uint16(first), uint16(second))
b.unicode = true
}
}
func (b *unicodeStringBuilder) writeASCIIString(bytes string) {
b.ensureStarted(len(bytes))
for _, c := range bytes {
b.buf = append(b.buf, uint16(c))
}
}
func (b *unicodeStringBuilder) writeUnicodeString(str unicodeString) {
b.ensureStarted(str.length())
b.buf = append(b.buf, str[1:]...)
b.unicode = true
}
func (b *valueStringBuilder) ascii() bool {
return len(b.unicodeBuilder.buf) == 0
}
func (b *valueStringBuilder) WriteString(s valueString) {
a, u := devirtualizeString(s)
if u != nil {
b.switchToUnicode(u.length())
b.unicodeBuilder.writeUnicodeString(u)
} else {
if b.ascii() {
b.asciiBuilder.WriteString(string(a))
} else {
b.unicodeBuilder.writeASCIIString(string(a))
}
}
}
func (b *valueStringBuilder) WriteASCII(s string) {
if b.ascii() {
b.asciiBuilder.WriteString(s)
} else {
b.unicodeBuilder.writeASCIIString(s)
}
}
func (b *valueStringBuilder) WriteRune(r rune) {
if r < utf8.RuneSelf {
if b.ascii() {
b.asciiBuilder.WriteByte(byte(r))
} else {
b.unicodeBuilder.WriteRune(r)
}
} else {
var extraLen int
if r <= 0xFFFF {
extraLen = 1
} else {
extraLen = 2
}
b.switchToUnicode(extraLen)
b.unicodeBuilder.WriteRune(r)
}
}
func (b *valueStringBuilder) String() valueString {
if b.ascii() {
return asciiString(b.asciiBuilder.String())
}
return b.unicodeBuilder.String()
}
func (b *valueStringBuilder) Grow(n int) {
if b.ascii() {
b.asciiBuilder.Grow(n)
} else {
b.unicodeBuilder.Grow(n)
}
}
func (b *valueStringBuilder) switchToUnicode(extraLen int) {
if b.ascii() {
b.unicodeBuilder.ensureStarted(b.asciiBuilder.Len() + extraLen)
b.unicodeBuilder.writeASCIIString(b.asciiBuilder.String())
b.asciiBuilder.Reset()
}
}
func (b *valueStringBuilder) WriteSubstring(source valueString, start int, end int) {
a, us := devirtualizeString(source)
if us == nil {
if b.ascii() {
b.asciiBuilder.WriteString(string(a[start:end]))
} else {
b.unicodeBuilder.writeASCIIString(string(a[start:end]))
}
return
}
if b.ascii() {
uc := false
for i := start; i < end; i++ {
if us.charAt(i) >= utf8.RuneSelf {
uc = true
break
}
}
if uc {
b.switchToUnicode(end - start + 1)
} else {
b.asciiBuilder.Grow(end - start + 1)
for i := start; i < end; i++ {
b.asciiBuilder.WriteByte(byte(us.charAt(i)))
}
return
}
}
b.unicodeBuilder.buf = append(b.unicodeBuilder.buf, us[start+1:end+1]...)
b.unicodeBuilder.unicode = true
}
func (s unicodeString) reader() io.RuneReader {
return &unicodeRuneReader{
s: s[1:],
}
}
func (s unicodeString) utf16Reader() io.RuneReader {
return &utf16RuneReader{
s: s[1:],
}
}
func (s unicodeString) utf16Runes() []rune {
runes := make([]rune, len(s)-1)
for i, ch := range s[1:] {
runes[i] = rune(ch)
}
return runes
}
func (s unicodeString) ToInteger() int64 {
return 0
}
func (s unicodeString) toString() valueString {
return s
}
func (s unicodeString) ToString() Value {
return s
}
func (s unicodeString) ToFloat() float64 {
return math.NaN()
}
func (s unicodeString) ToBoolean() bool {
return len(s) > 0
}
func (s unicodeString) toTrimmedUTF8() string {
if len(s) == 0 {
return ""
}
return strings.Trim(s.String(), parser.WhitespaceChars)
}
func (s unicodeString) ToNumber() Value {
return asciiString(s.toTrimmedUTF8()).ToNumber()
}
func (s unicodeString) ToObject(r *Runtime) *Object {
return r._newString(s, r.global.StringPrototype)
}
func (s unicodeString) equals(other unicodeString) bool {
if len(s) != len(other) {
return false
}
for i, r := range s {
if r != other[i] {
return false
}
}
return true
}
func (s unicodeString) SameAs(other Value) bool {
return s.StrictEquals(other)
}
func (s unicodeString) Equals(other Value) bool {
if s.StrictEquals(other) {
return true
}
if o, ok := other.(*Object); ok {
return s.Equals(o.toPrimitive())
}
return false
}
func (s unicodeString) StrictEquals(other Value) bool {
if otherStr, ok := other.(unicodeString); ok {
return s.equals(otherStr)
}
if otherStr, ok := other.(*importedString); ok {
otherStr.ensureScanned()
if otherStr.u != nil {
return s.equals(otherStr.u)
}
}
return false
}
func (s unicodeString) baseObject(r *Runtime) *Object {
ss := r.stringSingleton
ss.value = s
ss.setLength()
return ss.val
}
func (s unicodeString) charAt(idx int) rune {
return rune(s[idx+1])
}
func (s unicodeString) length() int {
return len(s) - 1
}
func (s unicodeString) concat(other valueString) valueString {
a, u := devirtualizeString(other)
if u != nil {
b := make(unicodeString, len(s)+len(u)-1)
copy(b, s)
copy(b[len(s):], u[1:])
return b
}
b := make([]uint16, len(s)+len(a))
copy(b, s)
b1 := b[len(s):]
for i := 0; i < len(a); i++ {
b1[i] = uint16(a[i])
}
return unicodeString(b)
}
func (s unicodeString) substring(start, end int) valueString {
ss := s[start+1 : end+1]
for _, c := range ss {
if c >= utf8.RuneSelf {
b := make(unicodeString, end-start+1)
b[0] = unistring.BOM
copy(b[1:], ss)
return b
}
}
as := make([]byte, end-start)
for i, c := range ss {
as[i] = byte(c)
}
return asciiString(as)
}
func (s unicodeString) String() string {
return string(utf16.Decode(s[1:]))
}
func (s unicodeString) compareTo(other valueString) int {
// TODO handle invalid UTF-16
return strings.Compare(s.String(), other.String())
}
func (s unicodeString) index(substr valueString, start int) int {
var ss []uint16
a, u := devirtualizeString(substr)
if u != nil {
ss = u[1:]
} else {
ss = make([]uint16, len(a))
for i := 0; i < len(a); i++ {
ss[i] = uint16(a[i])
}
}
s1 := s[1:]
// TODO: optimise
end := len(s1) - len(ss)
for start <= end {
for i := 0; i < len(ss); i++ {
if s1[start+i] != ss[i] {
goto nomatch
}
}
return start
nomatch:
start++
}
return -1
}
func (s unicodeString) lastIndex(substr valueString, start int) int {
var ss []uint16
a, u := devirtualizeString(substr)
if u != nil {
ss = u[1:]
} else {
ss = make([]uint16, len(a))
for i := 0; i < len(a); i++ {
ss[i] = uint16(a[i])
}
}
s1 := s[1:]
if maxStart := len(s1) - len(ss); start > maxStart {
start = maxStart
}
// TODO: optimise
for start >= 0 {
for i := 0; i < len(ss); i++ {
if s1[start+i] != ss[i] {
goto nomatch
}
}
return start
nomatch:
start--
}
return -1
}
func unicodeStringFromRunes(r []rune) unicodeString {
return unistring.NewFromRunes(r).AsUtf16()
}
func toLower(s string) valueString {
caser := cases.Lower(language.Und)
r := []rune(caser.String(s))
// Workaround
ascii := true
for i := 0; i < len(r)-1; i++ {
if (i == 0 || r[i-1] != 0x3b1) && r[i] == 0x345 && r[i+1] == 0x3c2 {
i++
r[i] = 0x3c3
}
if r[i] >= utf8.RuneSelf {
ascii = false
}
}
if ascii {
ascii = r[len(r)-1] < utf8.RuneSelf
}
if ascii {
return asciiString(r)
}
return unicodeStringFromRunes(r)
}
func (s unicodeString) toLower() valueString {
return toLower(s.String())
}
func (s unicodeString) toUpper() valueString {
caser := cases.Upper(language.Und)
return newStringValue(caser.String(s.String()))
}
func (s unicodeString) Export() interface{} {
return s.String()
}
func (s unicodeString) ExportType() reflect.Type {
return reflectTypeString
}
func (s unicodeString) hash(hash *maphash.Hash) uint64 {
_, _ = hash.WriteString(string(unistring.FromUtf16(s)))
h := hash.Sum64()
hash.Reset()
return h
}
func (s unicodeString) string() unistring.String {
return unistring.FromUtf16(s)
}

2
server/vendor/github.com/dop251/goja/token/Makefile generated vendored Normal file
View File

@@ -0,0 +1,2 @@
token_const.go: tokenfmt
./$^ | gofmt > $@

View File

@@ -0,0 +1,171 @@
# token
--
import "github.com/dop251/goja/token"
Package token defines constants representing the lexical tokens of JavaScript
(ECMA5).
## Usage
```go
const (
ILLEGAL
EOF
COMMENT
KEYWORD
STRING
BOOLEAN
NULL
NUMBER
IDENTIFIER
PLUS // +
MINUS // -
MULTIPLY // *
SLASH // /
REMAINDER // %
AND // &
OR // |
EXCLUSIVE_OR // ^
SHIFT_LEFT // <<
SHIFT_RIGHT // >>
UNSIGNED_SHIFT_RIGHT // >>>
AND_NOT // &^
ADD_ASSIGN // +=
SUBTRACT_ASSIGN // -=
MULTIPLY_ASSIGN // *=
QUOTIENT_ASSIGN // /=
REMAINDER_ASSIGN // %=
AND_ASSIGN // &=
OR_ASSIGN // |=
EXCLUSIVE_OR_ASSIGN // ^=
SHIFT_LEFT_ASSIGN // <<=
SHIFT_RIGHT_ASSIGN // >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>=
AND_NOT_ASSIGN // &^=
LOGICAL_AND // &&
LOGICAL_OR // ||
INCREMENT // ++
DECREMENT // --
EQUAL // ==
STRICT_EQUAL // ===
LESS // <
GREATER // >
ASSIGN // =
NOT // !
BITWISE_NOT // ~
NOT_EQUAL // !=
STRICT_NOT_EQUAL // !==
LESS_OR_EQUAL // <=
GREATER_OR_EQUAL // >=
LEFT_PARENTHESIS // (
LEFT_BRACKET // [
LEFT_BRACE // {
COMMA // ,
PERIOD // .
RIGHT_PARENTHESIS // )
RIGHT_BRACKET // ]
RIGHT_BRACE // }
SEMICOLON // ;
COLON // :
QUESTION_MARK // ?
IF
IN
DO
VAR
FOR
NEW
TRY
THIS
ELSE
CASE
VOID
WITH
WHILE
BREAK
CATCH
THROW
RETURN
TYPEOF
DELETE
SWITCH
DEFAULT
FINALLY
FUNCTION
CONTINUE
DEBUGGER
INSTANCEOF
)
```
#### type Token
```go
type Token int
```
Token is the set of lexical tokens in JavaScript (ECMA5).
#### func IsKeyword
```go
func IsKeyword(literal string) (Token, bool)
```
IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token if
the literal is a future keyword (const, let, class, super, ...), or 0 if the
literal is not a keyword.
If the literal is a keyword, IsKeyword returns a second value indicating if the
literal is considered a future keyword in strict-mode only.
7.6.1.2 Future Reserved Words:
const
class
enum
export
extends
import
super
7.6.1.2 Future Reserved Words (strict):
implements
interface
let
package
private
protected
public
static
#### func (Token) String
```go
func (tkn Token) String() string
```
String returns the string corresponding to the token. For operators, delimiters,
and keywords the string is the actual token string (e.g., for the token PLUS,
the String() is "+"). For all other tokens the string corresponds to the token
name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER").
--
**godocdown** http://github.com/robertkrimen/godocdown

122
server/vendor/github.com/dop251/goja/token/token.go generated vendored Normal file
View File

@@ -0,0 +1,122 @@
// Package token defines constants representing the lexical tokens of JavaScript (ECMA5).
package token
import (
"strconv"
)
// Token is the set of lexical tokens in JavaScript (ECMA5).
type Token int
// String returns the string corresponding to the token.
// For operators, delimiters, and keywords the string is the actual
// token string (e.g., for the token PLUS, the String() is
// "+"). For all other tokens the string corresponds to the token
// name (e.g. for the token IDENTIFIER, the string is "IDENTIFIER").
func (tkn Token) String() string {
if tkn == 0 {
return "UNKNOWN"
}
if tkn < Token(len(token2string)) {
return token2string[tkn]
}
return "token(" + strconv.Itoa(int(tkn)) + ")"
}
//lint:ignore U1000 This is not used for anything
func (tkn Token) precedence(in bool) int {
switch tkn {
case LOGICAL_OR:
return 1
case LOGICAL_AND:
return 2
case OR, OR_ASSIGN:
return 3
case EXCLUSIVE_OR:
return 4
case AND, AND_ASSIGN:
return 5
case EQUAL,
NOT_EQUAL,
STRICT_EQUAL,
STRICT_NOT_EQUAL:
return 6
case LESS, GREATER, LESS_OR_EQUAL, GREATER_OR_EQUAL, INSTANCEOF:
return 7
case IN:
if in {
return 7
}
return 0
case SHIFT_LEFT, SHIFT_RIGHT, UNSIGNED_SHIFT_RIGHT:
fallthrough
case SHIFT_LEFT_ASSIGN, SHIFT_RIGHT_ASSIGN, UNSIGNED_SHIFT_RIGHT_ASSIGN:
return 8
case PLUS, MINUS, ADD_ASSIGN, SUBTRACT_ASSIGN:
return 9
case MULTIPLY, SLASH, REMAINDER, MULTIPLY_ASSIGN, QUOTIENT_ASSIGN, REMAINDER_ASSIGN:
return 11
}
return 0
}
type _keyword struct {
token Token
futureKeyword bool
strict bool
}
// IsKeyword returns the keyword token if literal is a keyword, a KEYWORD token
// if the literal is a future keyword (const, let, class, super, ...), or 0 if the literal is not a keyword.
//
// If the literal is a keyword, IsKeyword returns a second value indicating if the literal
// is considered a future keyword in strict-mode only.
//
// 7.6.1.2 Future Reserved Words:
//
// const
// class
// enum
// export
// extends
// import
// super
//
// 7.6.1.2 Future Reserved Words (strict):
//
// implements
// interface
// let
// package
// private
// protected
// public
// static
func IsKeyword(literal string) (Token, bool) {
if keyword, exists := keywordTable[literal]; exists {
if keyword.futureKeyword {
return KEYWORD, keyword.strict
}
return keyword.token, false
}
return 0, false
}
func IsId(tkn Token) bool {
return tkn >= IDENTIFIER
}
func IsUnreservedWord(tkn Token) bool {
return tkn > ESCAPED_RESERVED_WORD
}

View File

@@ -0,0 +1,400 @@
package token
const (
_ Token = iota
ILLEGAL
EOF
COMMENT
STRING
NUMBER
PLUS // +
MINUS // -
MULTIPLY // *
EXPONENT // **
SLASH // /
REMAINDER // %
AND // &
OR // |
EXCLUSIVE_OR // ^
SHIFT_LEFT // <<
SHIFT_RIGHT // >>
UNSIGNED_SHIFT_RIGHT // >>>
ADD_ASSIGN // +=
SUBTRACT_ASSIGN // -=
MULTIPLY_ASSIGN // *=
EXPONENT_ASSIGN // **=
QUOTIENT_ASSIGN // /=
REMAINDER_ASSIGN // %=
AND_ASSIGN // &=
OR_ASSIGN // |=
EXCLUSIVE_OR_ASSIGN // ^=
SHIFT_LEFT_ASSIGN // <<=
SHIFT_RIGHT_ASSIGN // >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN // >>>=
LOGICAL_AND // &&
LOGICAL_OR // ||
COALESCE // ??
INCREMENT // ++
DECREMENT // --
EQUAL // ==
STRICT_EQUAL // ===
LESS // <
GREATER // >
ASSIGN // =
NOT // !
BITWISE_NOT // ~
NOT_EQUAL // !=
STRICT_NOT_EQUAL // !==
LESS_OR_EQUAL // <=
GREATER_OR_EQUAL // >=
LEFT_PARENTHESIS // (
LEFT_BRACKET // [
LEFT_BRACE // {
COMMA // ,
PERIOD // .
RIGHT_PARENTHESIS // )
RIGHT_BRACKET // ]
RIGHT_BRACE // }
SEMICOLON // ;
COLON // :
QUESTION_MARK // ?
QUESTION_DOT // ?.
ARROW // =>
ELLIPSIS // ...
BACKTICK // `
PRIVATE_IDENTIFIER
// tokens below (and only them) are syntactically valid identifiers
IDENTIFIER
KEYWORD
BOOLEAN
NULL
IF
IN
OF
DO
VAR
FOR
NEW
TRY
THIS
ELSE
CASE
VOID
WITH
CONST
WHILE
BREAK
CATCH
THROW
CLASS
SUPER
RETURN
TYPEOF
DELETE
SWITCH
DEFAULT
FINALLY
EXTENDS
FUNCTION
CONTINUE
DEBUGGER
INSTANCEOF
ESCAPED_RESERVED_WORD
// Non-reserved keywords below
LET
STATIC
ASYNC
AWAIT
YIELD
)
var token2string = [...]string{
ILLEGAL: "ILLEGAL",
EOF: "EOF",
COMMENT: "COMMENT",
KEYWORD: "KEYWORD",
STRING: "STRING",
BOOLEAN: "BOOLEAN",
NULL: "NULL",
NUMBER: "NUMBER",
IDENTIFIER: "IDENTIFIER",
PRIVATE_IDENTIFIER: "PRIVATE_IDENTIFIER",
PLUS: "+",
MINUS: "-",
EXPONENT: "**",
MULTIPLY: "*",
SLASH: "/",
REMAINDER: "%",
AND: "&",
OR: "|",
EXCLUSIVE_OR: "^",
SHIFT_LEFT: "<<",
SHIFT_RIGHT: ">>",
UNSIGNED_SHIFT_RIGHT: ">>>",
ADD_ASSIGN: "+=",
SUBTRACT_ASSIGN: "-=",
MULTIPLY_ASSIGN: "*=",
EXPONENT_ASSIGN: "**=",
QUOTIENT_ASSIGN: "/=",
REMAINDER_ASSIGN: "%=",
AND_ASSIGN: "&=",
OR_ASSIGN: "|=",
EXCLUSIVE_OR_ASSIGN: "^=",
SHIFT_LEFT_ASSIGN: "<<=",
SHIFT_RIGHT_ASSIGN: ">>=",
UNSIGNED_SHIFT_RIGHT_ASSIGN: ">>>=",
LOGICAL_AND: "&&",
LOGICAL_OR: "||",
COALESCE: "??",
INCREMENT: "++",
DECREMENT: "--",
EQUAL: "==",
STRICT_EQUAL: "===",
LESS: "<",
GREATER: ">",
ASSIGN: "=",
NOT: "!",
BITWISE_NOT: "~",
NOT_EQUAL: "!=",
STRICT_NOT_EQUAL: "!==",
LESS_OR_EQUAL: "<=",
GREATER_OR_EQUAL: ">=",
LEFT_PARENTHESIS: "(",
LEFT_BRACKET: "[",
LEFT_BRACE: "{",
COMMA: ",",
PERIOD: ".",
RIGHT_PARENTHESIS: ")",
RIGHT_BRACKET: "]",
RIGHT_BRACE: "}",
SEMICOLON: ";",
COLON: ":",
QUESTION_MARK: "?",
QUESTION_DOT: "?.",
ARROW: "=>",
ELLIPSIS: "...",
BACKTICK: "`",
IF: "if",
IN: "in",
OF: "of",
DO: "do",
VAR: "var",
LET: "let",
FOR: "for",
NEW: "new",
TRY: "try",
THIS: "this",
ELSE: "else",
CASE: "case",
VOID: "void",
WITH: "with",
ASYNC: "async",
AWAIT: "await",
YIELD: "yield",
CONST: "const",
WHILE: "while",
BREAK: "break",
CATCH: "catch",
THROW: "throw",
CLASS: "class",
SUPER: "super",
RETURN: "return",
TYPEOF: "typeof",
DELETE: "delete",
SWITCH: "switch",
STATIC: "static",
DEFAULT: "default",
FINALLY: "finally",
EXTENDS: "extends",
FUNCTION: "function",
CONTINUE: "continue",
DEBUGGER: "debugger",
INSTANCEOF: "instanceof",
}
var keywordTable = map[string]_keyword{
"if": {
token: IF,
},
"in": {
token: IN,
},
"do": {
token: DO,
},
"var": {
token: VAR,
},
"for": {
token: FOR,
},
"new": {
token: NEW,
},
"try": {
token: TRY,
},
"this": {
token: THIS,
},
"else": {
token: ELSE,
},
"case": {
token: CASE,
},
"void": {
token: VOID,
},
"with": {
token: WITH,
},
"async": {
token: ASYNC,
},
"while": {
token: WHILE,
},
"break": {
token: BREAK,
},
"catch": {
token: CATCH,
},
"throw": {
token: THROW,
},
"return": {
token: RETURN,
},
"typeof": {
token: TYPEOF,
},
"delete": {
token: DELETE,
},
"switch": {
token: SWITCH,
},
"default": {
token: DEFAULT,
},
"finally": {
token: FINALLY,
},
"function": {
token: FUNCTION,
},
"continue": {
token: CONTINUE,
},
"debugger": {
token: DEBUGGER,
},
"instanceof": {
token: INSTANCEOF,
},
"const": {
token: CONST,
},
"class": {
token: CLASS,
},
"enum": {
token: KEYWORD,
futureKeyword: true,
},
"export": {
token: KEYWORD,
futureKeyword: true,
},
"extends": {
token: EXTENDS,
},
"import": {
token: KEYWORD,
futureKeyword: true,
},
"super": {
token: SUPER,
},
/*
"implements": {
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"interface": {
token: KEYWORD,
futureKeyword: true,
strict: true,
},*/
"let": {
token: LET,
strict: true,
},
/*"package": {
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"private": {
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"protected": {
token: KEYWORD,
futureKeyword: true,
strict: true,
},
"public": {
token: KEYWORD,
futureKeyword: true,
strict: true,
},*/
"static": {
token: STATIC,
strict: true,
},
"await": {
token: AWAIT,
},
"yield": {
token: YIELD,
},
"false": {
token: BOOLEAN,
},
"true": {
token: BOOLEAN,
},
"null": {
token: NULL,
},
}

222
server/vendor/github.com/dop251/goja/token/tokenfmt generated vendored Normal file
View File

@@ -0,0 +1,222 @@
#!/usr/bin/env perl
use strict;
use warnings;
my (%token, @order, @keywords);
{
my $keywords;
my @const;
push @const, <<_END_;
package token
const(
_ Token = iota
_END_
for (split m/\n/, <<_END_) {
ILLEGAL
EOF
COMMENT
KEYWORD
STRING
BOOLEAN
NULL
NUMBER
IDENTIFIER
PLUS +
MINUS -
MULTIPLY *
SLASH /
REMAINDER %
AND &
OR |
EXCLUSIVE_OR ^
SHIFT_LEFT <<
SHIFT_RIGHT >>
UNSIGNED_SHIFT_RIGHT >>>
AND_NOT &^
ADD_ASSIGN +=
SUBTRACT_ASSIGN -=
MULTIPLY_ASSIGN *=
QUOTIENT_ASSIGN /=
REMAINDER_ASSIGN %=
AND_ASSIGN &=
OR_ASSIGN |=
EXCLUSIVE_OR_ASSIGN ^=
SHIFT_LEFT_ASSIGN <<=
SHIFT_RIGHT_ASSIGN >>=
UNSIGNED_SHIFT_RIGHT_ASSIGN >>>=
AND_NOT_ASSIGN &^=
LOGICAL_AND &&
LOGICAL_OR ||
INCREMENT ++
DECREMENT --
EQUAL ==
STRICT_EQUAL ===
LESS <
GREATER >
ASSIGN =
NOT !
BITWISE_NOT ~
NOT_EQUAL !=
STRICT_NOT_EQUAL !==
LESS_OR_EQUAL <=
GREATER_OR_EQUAL <=
LEFT_PARENTHESIS (
LEFT_BRACKET [
LEFT_BRACE {
COMMA ,
PERIOD .
RIGHT_PARENTHESIS )
RIGHT_BRACKET ]
RIGHT_BRACE }
SEMICOLON ;
COLON :
QUESTION_MARK ?
firstKeyword
IF
IN
DO
VAR
FOR
NEW
TRY
THIS
ELSE
CASE
VOID
WITH
WHILE
BREAK
CATCH
THROW
RETURN
TYPEOF
DELETE
SWITCH
DEFAULT
FINALLY
FUNCTION
CONTINUE
DEBUGGER
INSTANCEOF
lastKeyword
_END_
chomp;
next if m/^\s*#/;
my ($name, $symbol) = m/(\w+)\s*(\S+)?/;
if (defined $symbol) {
push @order, $name;
push @const, "$name // $symbol";
$token{$name} = $symbol;
} elsif (defined $name) {
$keywords ||= $name eq 'firstKeyword';
push @const, $name;
#$const[-1] .= " Token = iota" if 2 == @const;
if ($name =~ m/^([A-Z]+)/) {
push @keywords, $name if $keywords;
push @order, $name;
if ($token{SEMICOLON}) {
$token{$name} = lc $1;
} else {
$token{$name} = $name;
}
}
} else {
push @const, "";
}
}
push @const, ")";
print join "\n", @const, "";
}
{
print <<_END_;
var token2string = [...]string{
_END_
for my $name (@order) {
print "$name: \"$token{$name}\",\n";
}
print <<_END_;
}
_END_
print <<_END_;
var keywordTable = map[string]_keyword{
_END_
for my $name (@keywords) {
print <<_END_
"@{[ lc $name ]}": _keyword{
token: $name,
},
_END_
}
for my $name (qw/
const
class
enum
export
extends
import
super
/) {
print <<_END_
"$name": _keyword{
token: KEYWORD,
futureKeyword: true,
},
_END_
}
for my $name (qw/
implements
interface
let
package
private
protected
public
static
/) {
print <<_END_
"$name": _keyword{
token: KEYWORD,
futureKeyword: true,
strict: true,
},
_END_
}
print <<_END_;
}
_END_
}

918
server/vendor/github.com/dop251/goja/typedarrays.go generated vendored Normal file
View File

@@ -0,0 +1,918 @@
package goja
import (
"math"
"reflect"
"strconv"
"unsafe"
"github.com/dop251/goja/unistring"
)
type byteOrder bool
const (
bigEndian byteOrder = false
littleEndian byteOrder = true
)
var (
nativeEndian byteOrder
arrayBufferType = reflect.TypeOf(ArrayBuffer{})
)
type typedArrayObjectCtor func(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject
type arrayBufferObject struct {
baseObject
detached bool
data []byte
}
// ArrayBuffer is a Go wrapper around ECMAScript ArrayBuffer. Calling Runtime.ToValue() on it
// returns the underlying ArrayBuffer. Calling Export() on an ECMAScript ArrayBuffer returns a wrapper.
// Use Runtime.NewArrayBuffer([]byte) to create one.
type ArrayBuffer struct {
buf *arrayBufferObject
}
type dataViewObject struct {
baseObject
viewedArrayBuf *arrayBufferObject
byteLen, byteOffset int
}
type typedArray interface {
toRaw(Value) uint64
get(idx int) Value
set(idx int, value Value)
getRaw(idx int) uint64
setRaw(idx int, raw uint64)
less(i, j int) bool
swap(i, j int)
typeMatch(v Value) bool
}
type uint8Array []uint8
type uint8ClampedArray []uint8
type int8Array []int8
type uint16Array []uint16
type int16Array []int16
type uint32Array []uint32
type int32Array []int32
type float32Array []float32
type float64Array []float64
type typedArrayObject struct {
baseObject
viewedArrayBuf *arrayBufferObject
defaultCtor *Object
length, offset int
elemSize int
typedArray typedArray
}
func (a ArrayBuffer) toValue(r *Runtime) Value {
if a.buf == nil {
return _null
}
v := a.buf.val
if v.runtime != r {
panic(r.NewTypeError("Illegal runtime transition of an ArrayBuffer"))
}
return v
}
// Bytes returns the underlying []byte for this ArrayBuffer.
// For detached ArrayBuffers returns nil.
func (a ArrayBuffer) Bytes() []byte {
return a.buf.data
}
// Detach the ArrayBuffer. After this, the underlying []byte becomes unreferenced and any attempt
// to use this ArrayBuffer results in a TypeError.
// Returns false if it was already detached, true otherwise.
// Note, this method may only be called from the goroutine that 'owns' the Runtime, it may not
// be called concurrently.
func (a ArrayBuffer) Detach() bool {
if a.buf.detached {
return false
}
a.buf.detach()
return true
}
// Detached returns true if the ArrayBuffer is detached.
func (a ArrayBuffer) Detached() bool {
return a.buf.detached
}
func (r *Runtime) NewArrayBuffer(data []byte) ArrayBuffer {
buf := r._newArrayBuffer(r.global.ArrayBufferPrototype, nil)
buf.data = data
return ArrayBuffer{
buf: buf,
}
}
func (a *uint8Array) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *uint8Array) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *uint8Array) set(idx int, value Value) {
(*a)[idx] = toUint8(value)
}
func (a *uint8Array) toRaw(v Value) uint64 {
return uint64(toUint8(v))
}
func (a *uint8Array) setRaw(idx int, v uint64) {
(*a)[idx] = uint8(v)
}
func (a *uint8Array) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *uint8Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *uint8Array) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= 0 && i <= 255
}
return false
}
func (a *uint8ClampedArray) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *uint8ClampedArray) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *uint8ClampedArray) set(idx int, value Value) {
(*a)[idx] = toUint8Clamp(value)
}
func (a *uint8ClampedArray) toRaw(v Value) uint64 {
return uint64(toUint8Clamp(v))
}
func (a *uint8ClampedArray) setRaw(idx int, v uint64) {
(*a)[idx] = uint8(v)
}
func (a *uint8ClampedArray) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *uint8ClampedArray) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *uint8ClampedArray) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= 0 && i <= 255
}
return false
}
func (a *int8Array) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *int8Array) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *int8Array) set(idx int, value Value) {
(*a)[idx] = toInt8(value)
}
func (a *int8Array) toRaw(v Value) uint64 {
return uint64(toInt8(v))
}
func (a *int8Array) setRaw(idx int, v uint64) {
(*a)[idx] = int8(v)
}
func (a *int8Array) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *int8Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *int8Array) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= math.MinInt8 && i <= math.MaxInt8
}
return false
}
func (a *uint16Array) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *uint16Array) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *uint16Array) set(idx int, value Value) {
(*a)[idx] = toUint16(value)
}
func (a *uint16Array) toRaw(v Value) uint64 {
return uint64(toUint16(v))
}
func (a *uint16Array) setRaw(idx int, v uint64) {
(*a)[idx] = uint16(v)
}
func (a *uint16Array) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *uint16Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *uint16Array) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= 0 && i <= math.MaxUint16
}
return false
}
func (a *int16Array) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *int16Array) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *int16Array) set(idx int, value Value) {
(*a)[idx] = toInt16(value)
}
func (a *int16Array) toRaw(v Value) uint64 {
return uint64(toInt16(v))
}
func (a *int16Array) setRaw(idx int, v uint64) {
(*a)[idx] = int16(v)
}
func (a *int16Array) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *int16Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *int16Array) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= math.MinInt16 && i <= math.MaxInt16
}
return false
}
func (a *uint32Array) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *uint32Array) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *uint32Array) set(idx int, value Value) {
(*a)[idx] = toUint32(value)
}
func (a *uint32Array) toRaw(v Value) uint64 {
return uint64(toUint32(v))
}
func (a *uint32Array) setRaw(idx int, v uint64) {
(*a)[idx] = uint32(v)
}
func (a *uint32Array) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *uint32Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *uint32Array) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= 0 && i <= math.MaxUint32
}
return false
}
func (a *int32Array) get(idx int) Value {
return intToValue(int64((*a)[idx]))
}
func (a *int32Array) getRaw(idx int) uint64 {
return uint64((*a)[idx])
}
func (a *int32Array) set(idx int, value Value) {
(*a)[idx] = toInt32(value)
}
func (a *int32Array) toRaw(v Value) uint64 {
return uint64(toInt32(v))
}
func (a *int32Array) setRaw(idx int, v uint64) {
(*a)[idx] = int32(v)
}
func (a *int32Array) less(i, j int) bool {
return (*a)[i] < (*a)[j]
}
func (a *int32Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *int32Array) typeMatch(v Value) bool {
if i, ok := v.(valueInt); ok {
return i >= math.MinInt32 && i <= math.MaxInt32
}
return false
}
func (a *float32Array) get(idx int) Value {
return floatToValue(float64((*a)[idx]))
}
func (a *float32Array) getRaw(idx int) uint64 {
return uint64(math.Float32bits((*a)[idx]))
}
func (a *float32Array) set(idx int, value Value) {
(*a)[idx] = toFloat32(value)
}
func (a *float32Array) toRaw(v Value) uint64 {
return uint64(math.Float32bits(toFloat32(v)))
}
func (a *float32Array) setRaw(idx int, v uint64) {
(*a)[idx] = math.Float32frombits(uint32(v))
}
func typedFloatLess(x, y float64) bool {
xNan := math.IsNaN(x)
yNan := math.IsNaN(y)
if yNan {
return !xNan
} else if xNan {
return false
}
if x == 0 && y == 0 { // handle neg zero
return math.Signbit(x)
}
return x < y
}
func (a *float32Array) less(i, j int) bool {
return typedFloatLess(float64((*a)[i]), float64((*a)[j]))
}
func (a *float32Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *float32Array) typeMatch(v Value) bool {
switch v.(type) {
case valueInt, valueFloat:
return true
}
return false
}
func (a *float64Array) get(idx int) Value {
return floatToValue((*a)[idx])
}
func (a *float64Array) getRaw(idx int) uint64 {
return math.Float64bits((*a)[idx])
}
func (a *float64Array) set(idx int, value Value) {
(*a)[idx] = value.ToFloat()
}
func (a *float64Array) toRaw(v Value) uint64 {
return math.Float64bits(v.ToFloat())
}
func (a *float64Array) setRaw(idx int, v uint64) {
(*a)[idx] = math.Float64frombits(v)
}
func (a *float64Array) less(i, j int) bool {
return typedFloatLess((*a)[i], (*a)[j])
}
func (a *float64Array) swap(i, j int) {
(*a)[i], (*a)[j] = (*a)[j], (*a)[i]
}
func (a *float64Array) typeMatch(v Value) bool {
switch v.(type) {
case valueInt, valueFloat:
return true
}
return false
}
func (a *typedArrayObject) _getIdx(idx int) Value {
if 0 <= idx && idx < a.length {
if !a.viewedArrayBuf.ensureNotDetached(false) {
return nil
}
return a.typedArray.get(idx + a.offset)
}
return nil
}
func (a *typedArrayObject) getOwnPropStr(name unistring.String) Value {
idx, ok := strToIntNum(name)
if ok {
v := a._getIdx(idx)
if v != nil {
return &valueProperty{
value: v,
writable: true,
enumerable: true,
configurable: true,
}
}
return nil
}
if idx == 0 {
return nil
}
return a.baseObject.getOwnPropStr(name)
}
func (a *typedArrayObject) getOwnPropIdx(idx valueInt) Value {
v := a._getIdx(toIntClamp(int64(idx)))
if v != nil {
return &valueProperty{
value: v,
writable: true,
enumerable: true,
configurable: true,
}
}
return nil
}
func (a *typedArrayObject) getStr(name unistring.String, receiver Value) Value {
idx, ok := strToIntNum(name)
if ok {
return a._getIdx(idx)
}
if idx == 0 {
return nil
}
return a.baseObject.getStr(name, receiver)
}
func (a *typedArrayObject) getIdx(idx valueInt, receiver Value) Value {
return a._getIdx(toIntClamp(int64(idx)))
}
func (a *typedArrayObject) isValidIntegerIndex(idx int) bool {
if a.viewedArrayBuf.ensureNotDetached(false) {
if idx >= 0 && idx < a.length {
return true
}
}
return false
}
func (a *typedArrayObject) _putIdx(idx int, v Value) {
v = v.ToNumber()
if a.isValidIntegerIndex(idx) {
a.typedArray.set(idx+a.offset, v)
}
}
func (a *typedArrayObject) _hasIdx(idx int) bool {
return a.isValidIntegerIndex(idx)
}
func (a *typedArrayObject) setOwnStr(p unistring.String, v Value, throw bool) bool {
idx, ok := strToIntNum(p)
if ok {
a._putIdx(idx, v)
return true
}
if idx == 0 {
v.ToNumber() // make sure it throws
return true
}
return a.baseObject.setOwnStr(p, v, throw)
}
func (a *typedArrayObject) setOwnIdx(p valueInt, v Value, throw bool) bool {
a._putIdx(toIntClamp(int64(p)), v)
return true
}
func (a *typedArrayObject) setForeignStr(p unistring.String, v, receiver Value, throw bool) (res bool, handled bool) {
return a._setForeignStr(p, a.getOwnPropStr(p), v, receiver, throw)
}
func (a *typedArrayObject) setForeignIdx(p valueInt, v, receiver Value, throw bool) (res bool, handled bool) {
return a._setForeignIdx(p, trueValIfPresent(a.hasOwnPropertyIdx(p)), v, receiver, throw)
}
func (a *typedArrayObject) hasOwnPropertyStr(name unistring.String) bool {
idx, ok := strToIntNum(name)
if ok {
return a._hasIdx(idx)
}
if idx == 0 {
return false
}
return a.baseObject.hasOwnPropertyStr(name)
}
func (a *typedArrayObject) hasOwnPropertyIdx(idx valueInt) bool {
return a._hasIdx(toIntClamp(int64(idx)))
}
func (a *typedArrayObject) hasPropertyStr(name unistring.String) bool {
idx, ok := strToIntNum(name)
if ok {
return a._hasIdx(idx)
}
if idx == 0 {
return false
}
return a.baseObject.hasPropertyStr(name)
}
func (a *typedArrayObject) hasPropertyIdx(idx valueInt) bool {
return a.hasOwnPropertyIdx(idx)
}
func (a *typedArrayObject) _defineIdxProperty(idx int, desc PropertyDescriptor, throw bool) bool {
if desc.Configurable == FLAG_FALSE || desc.Enumerable == FLAG_FALSE || desc.IsAccessor() || desc.Writable == FLAG_FALSE {
a.val.runtime.typeErrorResult(throw, "Cannot redefine property: %d", idx)
return false
}
_, ok := a._defineOwnProperty(unistring.String(strconv.Itoa(idx)), a.getOwnPropIdx(valueInt(idx)), desc, throw)
if ok {
if !a.isValidIntegerIndex(idx) {
a.val.runtime.typeErrorResult(throw, "Invalid typed array index")
return false
}
a._putIdx(idx, desc.Value)
return true
}
return ok
}
func (a *typedArrayObject) defineOwnPropertyStr(name unistring.String, desc PropertyDescriptor, throw bool) bool {
idx, ok := strToIntNum(name)
if ok {
return a._defineIdxProperty(idx, desc, throw)
}
if idx == 0 {
a.viewedArrayBuf.ensureNotDetached(throw)
a.val.runtime.typeErrorResult(throw, "Invalid typed array index")
return false
}
return a.baseObject.defineOwnPropertyStr(name, desc, throw)
}
func (a *typedArrayObject) defineOwnPropertyIdx(name valueInt, desc PropertyDescriptor, throw bool) bool {
return a._defineIdxProperty(toIntClamp(int64(name)), desc, throw)
}
func (a *typedArrayObject) deleteStr(name unistring.String, throw bool) bool {
idx, ok := strToIntNum(name)
if ok {
if a.isValidIntegerIndex(idx) {
a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.String())
return false
}
return true
}
if idx == 0 {
return true
}
return a.baseObject.deleteStr(name, throw)
}
func (a *typedArrayObject) deleteIdx(idx valueInt, throw bool) bool {
if a.viewedArrayBuf.ensureNotDetached(false) && idx >= 0 && int64(idx) < int64(a.length) {
a.val.runtime.typeErrorResult(throw, "Cannot delete property '%d' of %s", idx, a.val.String())
return false
}
return true
}
func (a *typedArrayObject) stringKeys(all bool, accum []Value) []Value {
if accum == nil {
accum = make([]Value, 0, a.length)
}
for i := 0; i < a.length; i++ {
accum = append(accum, asciiString(strconv.Itoa(i)))
}
return a.baseObject.stringKeys(all, accum)
}
type typedArrayPropIter struct {
a *typedArrayObject
idx int
}
func (i *typedArrayPropIter) next() (propIterItem, iterNextFunc) {
if i.idx < i.a.length {
name := strconv.Itoa(i.idx)
prop := i.a._getIdx(i.idx)
i.idx++
return propIterItem{name: asciiString(name), value: prop}, i.next
}
return i.a.baseObject.iterateStringKeys()()
}
func (a *typedArrayObject) iterateStringKeys() iterNextFunc {
return (&typedArrayPropIter{
a: a,
}).next
}
func (r *Runtime) _newTypedArrayObject(buf *arrayBufferObject, offset, length, elemSize int, defCtor *Object, arr typedArray, proto *Object) *typedArrayObject {
o := &Object{runtime: r}
a := &typedArrayObject{
baseObject: baseObject{
val: o,
class: classObject,
prototype: proto,
extensible: true,
},
viewedArrayBuf: buf,
offset: offset,
length: length,
elemSize: elemSize,
defaultCtor: defCtor,
typedArray: arr,
}
o.self = a
a.init()
return a
}
func (r *Runtime) newUint8ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 1, r.global.Uint8Array, (*uint8Array)(&buf.data), proto)
}
func (r *Runtime) newUint8ClampedArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 1, r.global.Uint8ClampedArray, (*uint8ClampedArray)(&buf.data), proto)
}
func (r *Runtime) newInt8ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 1, r.global.Int8Array, (*int8Array)(unsafe.Pointer(&buf.data)), proto)
}
func (r *Runtime) newUint16ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 2, r.global.Uint16Array, (*uint16Array)(unsafe.Pointer(&buf.data)), proto)
}
func (r *Runtime) newInt16ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 2, r.global.Int16Array, (*int16Array)(unsafe.Pointer(&buf.data)), proto)
}
func (r *Runtime) newUint32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 4, r.global.Uint32Array, (*uint32Array)(unsafe.Pointer(&buf.data)), proto)
}
func (r *Runtime) newInt32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 4, r.global.Int32Array, (*int32Array)(unsafe.Pointer(&buf.data)), proto)
}
func (r *Runtime) newFloat32ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 4, r.global.Float32Array, (*float32Array)(unsafe.Pointer(&buf.data)), proto)
}
func (r *Runtime) newFloat64ArrayObject(buf *arrayBufferObject, offset, length int, proto *Object) *typedArrayObject {
return r._newTypedArrayObject(buf, offset, length, 8, r.global.Float64Array, (*float64Array)(unsafe.Pointer(&buf.data)), proto)
}
func (o *dataViewObject) getIdxAndByteOrder(getIdx int, littleEndianVal Value, size int) (int, byteOrder) {
o.viewedArrayBuf.ensureNotDetached(true)
if getIdx+size > o.byteLen {
panic(o.val.runtime.newError(o.val.runtime.global.RangeError, "Index %d is out of bounds", getIdx))
}
getIdx += o.byteOffset
var bo byteOrder
if littleEndianVal != nil {
if littleEndianVal.ToBoolean() {
bo = littleEndian
} else {
bo = bigEndian
}
} else {
bo = nativeEndian
}
return getIdx, bo
}
func (o *arrayBufferObject) ensureNotDetached(throw bool) bool {
if o.detached {
o.val.runtime.typeErrorResult(throw, "ArrayBuffer is detached")
return false
}
return true
}
func (o *arrayBufferObject) getFloat32(idx int, byteOrder byteOrder) float32 {
return math.Float32frombits(o.getUint32(idx, byteOrder))
}
func (o *arrayBufferObject) setFloat32(idx int, val float32, byteOrder byteOrder) {
o.setUint32(idx, math.Float32bits(val), byteOrder)
}
func (o *arrayBufferObject) getFloat64(idx int, byteOrder byteOrder) float64 {
return math.Float64frombits(o.getUint64(idx, byteOrder))
}
func (o *arrayBufferObject) setFloat64(idx int, val float64, byteOrder byteOrder) {
o.setUint64(idx, math.Float64bits(val), byteOrder)
}
func (o *arrayBufferObject) getUint64(idx int, byteOrder byteOrder) uint64 {
var b []byte
if byteOrder == nativeEndian {
b = o.data[idx : idx+8]
} else {
b = make([]byte, 8)
d := o.data[idx : idx+8]
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7] = d[7], d[6], d[5], d[4], d[3], d[2], d[1], d[0]
}
return *((*uint64)(unsafe.Pointer(&b[0])))
}
func (o *arrayBufferObject) setUint64(idx int, val uint64, byteOrder byteOrder) {
if byteOrder == nativeEndian {
*(*uint64)(unsafe.Pointer(&o.data[idx])) = val
} else {
b := (*[8]byte)(unsafe.Pointer(&val))
d := o.data[idx : idx+8]
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7] = b[7], b[6], b[5], b[4], b[3], b[2], b[1], b[0]
}
}
func (o *arrayBufferObject) getUint32(idx int, byteOrder byteOrder) uint32 {
var b []byte
if byteOrder == nativeEndian {
b = o.data[idx : idx+4]
} else {
b = make([]byte, 4)
d := o.data[idx : idx+4]
b[0], b[1], b[2], b[3] = d[3], d[2], d[1], d[0]
}
return *((*uint32)(unsafe.Pointer(&b[0])))
}
func (o *arrayBufferObject) setUint32(idx int, val uint32, byteOrder byteOrder) {
o.ensureNotDetached(true)
if byteOrder == nativeEndian {
*(*uint32)(unsafe.Pointer(&o.data[idx])) = val
} else {
b := (*[4]byte)(unsafe.Pointer(&val))
d := o.data[idx : idx+4]
d[0], d[1], d[2], d[3] = b[3], b[2], b[1], b[0]
}
}
func (o *arrayBufferObject) getUint16(idx int, byteOrder byteOrder) uint16 {
var b []byte
if byteOrder == nativeEndian {
b = o.data[idx : idx+2]
} else {
b = make([]byte, 2)
d := o.data[idx : idx+2]
b[0], b[1] = d[1], d[0]
}
return *((*uint16)(unsafe.Pointer(&b[0])))
}
func (o *arrayBufferObject) setUint16(idx int, val uint16, byteOrder byteOrder) {
if byteOrder == nativeEndian {
*(*uint16)(unsafe.Pointer(&o.data[idx])) = val
} else {
b := (*[2]byte)(unsafe.Pointer(&val))
d := o.data[idx : idx+2]
d[0], d[1] = b[1], b[0]
}
}
func (o *arrayBufferObject) getUint8(idx int) uint8 {
return o.data[idx]
}
func (o *arrayBufferObject) setUint8(idx int, val uint8) {
o.data[idx] = val
}
func (o *arrayBufferObject) getInt32(idx int, byteOrder byteOrder) int32 {
return int32(o.getUint32(idx, byteOrder))
}
func (o *arrayBufferObject) setInt32(idx int, val int32, byteOrder byteOrder) {
o.setUint32(idx, uint32(val), byteOrder)
}
func (o *arrayBufferObject) getInt16(idx int, byteOrder byteOrder) int16 {
return int16(o.getUint16(idx, byteOrder))
}
func (o *arrayBufferObject) setInt16(idx int, val int16, byteOrder byteOrder) {
o.setUint16(idx, uint16(val), byteOrder)
}
func (o *arrayBufferObject) getInt8(idx int) int8 {
return int8(o.data[idx])
}
func (o *arrayBufferObject) setInt8(idx int, val int8) {
o.setUint8(idx, uint8(val))
}
func (o *arrayBufferObject) detach() {
o.data = nil
o.detached = true
}
func (o *arrayBufferObject) exportType() reflect.Type {
return arrayBufferType
}
func (o *arrayBufferObject) export(*objectExportCtx) interface{} {
return ArrayBuffer{
buf: o,
}
}
func (r *Runtime) _newArrayBuffer(proto *Object, o *Object) *arrayBufferObject {
if o == nil {
o = &Object{runtime: r}
}
b := &arrayBufferObject{
baseObject: baseObject{
class: classObject,
val: o,
prototype: proto,
extensible: true,
},
}
o.self = b
b.init()
return b
}
func init() {
buf := [2]byte{}
*(*uint16)(unsafe.Pointer(&buf[0])) = uint16(0xCAFE)
switch buf {
case [2]byte{0xFE, 0xCA}:
nativeEndian = littleEndian
case [2]byte{0xCA, 0xFE}:
nativeEndian = bigEndian
default:
panic("Could not determine native endianness.")
}
}

View File

@@ -0,0 +1,137 @@
// Package unistring contains an implementation of a hybrid ASCII/UTF-16 string.
// For ASCII strings the underlying representation is equivalent to a normal Go string.
// For unicode strings the underlying representation is UTF-16 as []uint16 with 0th element set to 0xFEFF.
// unicode.String allows representing malformed UTF-16 values (e.g. stand-alone parts of surrogate pairs)
// which cannot be represented in UTF-8.
// At the same time it is possible to use unicode.String as property keys just as efficiently as simple strings,
// (the leading 0xFEFF ensures there is no clash with ASCII string), and it is possible to convert it
// to valueString without extra allocations.
package unistring
import (
"reflect"
"unicode/utf16"
"unicode/utf8"
"unsafe"
)
const (
BOM = 0xFEFF
)
type String string
// Scan checks if the string contains any unicode characters. If it does, converts to an array suitable for creating
// a String using FromUtf16, otherwise returns nil.
func Scan(s string) []uint16 {
utf16Size := 0
for ; utf16Size < len(s); utf16Size++ {
if s[utf16Size] >= utf8.RuneSelf {
goto unicode
}
}
return nil
unicode:
for _, chr := range s[utf16Size:] {
utf16Size++
if chr > 0xFFFF {
utf16Size++
}
}
buf := make([]uint16, utf16Size+1)
buf[0] = BOM
c := 1
for _, chr := range s {
if chr <= 0xFFFF {
buf[c] = uint16(chr)
} else {
first, second := utf16.EncodeRune(chr)
buf[c] = uint16(first)
c++
buf[c] = uint16(second)
}
c++
}
return buf
}
func NewFromString(s string) String {
if buf := Scan(s); buf != nil {
return FromUtf16(buf)
}
return String(s)
}
func NewFromRunes(s []rune) String {
ascii := true
size := 0
for _, c := range s {
if c >= utf8.RuneSelf {
ascii = false
if c > 0xFFFF {
size++
}
}
size++
}
if ascii {
return String(s)
}
b := make([]uint16, size+1)
b[0] = BOM
i := 1
for _, c := range s {
if c <= 0xFFFF {
b[i] = uint16(c)
} else {
first, second := utf16.EncodeRune(c)
b[i] = uint16(first)
i++
b[i] = uint16(second)
}
i++
}
return FromUtf16(b)
}
func FromUtf16(b []uint16) String {
var str string
hdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
hdr.Data = uintptr(unsafe.Pointer(&b[0]))
hdr.Len = len(b) * 2
return String(str)
}
func (s String) String() string {
if b := s.AsUtf16(); b != nil {
return string(utf16.Decode(b[1:]))
}
return string(s)
}
func (s String) AsUtf16() []uint16 {
if len(s) < 4 || len(s)&1 != 0 {
return nil
}
var a []uint16
raw := string(s)
sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&a))
sliceHeader.Data = (*reflect.StringHeader)(unsafe.Pointer(&raw)).Data
l := len(raw) / 2
sliceHeader.Len = l
sliceHeader.Cap = l
if a[0] == BOM {
return a
}
return nil
}

1177
server/vendor/github.com/dop251/goja/value.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

5613
server/vendor/github.com/dop251/goja/vm.go generated vendored Normal file

File diff suppressed because it is too large Load Diff