From 4633788b3de62a7bed2559c119610239d7eac631 Mon Sep 17 00:00:00 2001 From: Paul Jolly Date: Wed, 18 Apr 2018 08:45:07 +0100 Subject: [PATCH 1/2] compiler/prelude: move prelude to separate .js files I've been working with the prelude quite a lot recently. One of the really painful things with the current implementation is that the JavaScript for the prelude exists as a const string in a .go file, which makes properly writing and formatting the JavaScript itself very difficult. This PR splits the prelude into separate .js files to make editing the JavaScript prelude more straightforward. genmin.go becomes genprelude.go where these .js files are catted together into a single prelude.go file. The minified prelude_min.go is as before. Automated formatting of these .js files will follow in a later PR. --- compiler/prelude/generate.go | 3 + compiler/prelude/genmin.go | 63 --- compiler/prelude/genprelude.go | 96 ++++ .../prelude/{goroutines.go => goroutines.js} | 4 - .../prelude/{jsmapping.go => jsmapping.js} | 4 - compiler/prelude/jspmapping.js | 0 compiler/prelude/{numeric.go => numeric.js} | 4 - compiler/prelude/prelude.go | 422 +----------------- compiler/prelude/prelude.js | 414 +++++++++++++++++ compiler/prelude/prelude_min.go | 2 +- compiler/prelude/{types.go => types.js} | 4 - 11 files changed, 517 insertions(+), 499 deletions(-) create mode 100644 compiler/prelude/generate.go delete mode 100644 compiler/prelude/genmin.go create mode 100644 compiler/prelude/genprelude.go rename compiler/prelude/{goroutines.go => goroutines.js} (99%) rename compiler/prelude/{jsmapping.go => jsmapping.js} (99%) create mode 100644 compiler/prelude/jspmapping.js rename compiler/prelude/{numeric.go => numeric.js} (99%) create mode 100644 compiler/prelude/prelude.js rename compiler/prelude/{types.go => types.js} (99%) diff --git a/compiler/prelude/generate.go b/compiler/prelude/generate.go new file mode 100644 index 000000000..bc4b2cea7 --- /dev/null +++ b/compiler/prelude/generate.go @@ -0,0 +1,3 @@ +package prelude + +//go:generate go run genprelude.go diff --git a/compiler/prelude/genmin.go b/compiler/prelude/genmin.go deleted file mode 100644 index 739dbf216..000000000 --- a/compiler/prelude/genmin.go +++ /dev/null @@ -1,63 +0,0 @@ -// +build ignore - -package main - -import ( - "bytes" - "fmt" - "go/build" - "io/ioutil" - "log" - "os/exec" - "path/filepath" - "strings" - - "github.com/gopherjs/gopherjs/compiler/prelude" -) - -func main() { - if err := run(); err != nil { - log.Fatalln(err) - } -} - -func run() error { - bpkg, err := build.Import("github.com/gopherjs/gopherjs", "", build.FindOnly) - if err != nil { - return fmt.Errorf("failed to locate path for github.com/gopherjs/gopherjs: %v", err) - } - - preludeDir := filepath.Join(bpkg.Dir, "compiler", "prelude") - - args := []string{ - filepath.Join(bpkg.Dir, "node_modules", ".bin", "uglifyjs"), - "--config-file", - filepath.Join(preludeDir, "uglifyjs_options.json"), - } - - stderr := new(bytes.Buffer) - cmd := exec.Command(args[0], args[1:]...) - cmd.Stdin = strings.NewReader(prelude.Prelude) - cmd.Stderr = stderr - - out, err := cmd.Output() - if err != nil { - return fmt.Errorf("failed to run %v: %v\n%s", strings.Join(args, " "), err, stderr.String()) - } - - fn := "prelude_min.go" - - outStr := fmt.Sprintf(`// Code generated by genmin; DO NOT EDIT. - -package prelude - -// Minified is an uglifyjs-minified version of Prelude. -const Minified = %q -`, out) - - if err := ioutil.WriteFile(fn, []byte(outStr), 0644); err != nil { - return fmt.Errorf("failed to write to %v: %v", fn, err) - } - - return nil -} diff --git a/compiler/prelude/genprelude.go b/compiler/prelude/genprelude.go new file mode 100644 index 000000000..05c241528 --- /dev/null +++ b/compiler/prelude/genprelude.go @@ -0,0 +1,96 @@ +// +build ignore + +package main + +import ( + "bytes" + "fmt" + "go/build" + "io/ioutil" + "log" + "os/exec" + "path/filepath" + "strings" +) + +const ( + fn = "prelude.go" + minFn = "prelude_min.go" +) + +func main() { + if err := run(); err != nil { + log.Fatalln(err) + } +} + +func run() error { + bpkg, err := build.Import("github.com/gopherjs/gopherjs", "", build.FindOnly) + if err != nil { + return fmt.Errorf("failed to locate path for github.com/gopherjs/gopherjs: %v", err) + } + + preludeDir := filepath.Join(bpkg.Dir, "compiler", "prelude") + + files := []string{ + "prelude.js", + "numeric.js", + "types.js", + "goroutines.js", + "jsmapping.js", + } + + prelude := new(bytes.Buffer) + + for _, f := range files { + p := filepath.Join(preludeDir, f) + out, err := ioutil.ReadFile(p) + if err != nil { + return fmt.Errorf("failed to read from %v: %v", p, err) + } + if _, err := prelude.Write(out); err != nil { + return fmt.Errorf("failed to append prelude: %v", err) + } + } + + args := append([]string{ + filepath.Join(bpkg.Dir, "node_modules", ".bin", "uglifyjs"), + "--config-file", + filepath.Join(preludeDir, "uglifyjs_options.json"), + }, files...) + + stderr := new(bytes.Buffer) + + cmd := exec.Command(args[0], args[1:]...) + cmd.Stderr = stderr + + minout, err := cmd.Output() + if err != nil { + return fmt.Errorf("failed to run %v: %v\n%s", strings.Join(args, " "), err, stderr.Bytes()) + } + + err = writeOutput("prelude.go", ""+ + "// Prelude is the GopherJS JavaScript interop layer.\n"+ + "const Prelude = %q", prelude.Bytes()) + + if err != nil { + return err + } + + err = writeOutput("prelude_min.go", ""+ + "// Minified is an uglifyjs-minified version of Prelude.\n"+ + "const Minified = %q", minout) + + return err +} + +func writeOutput(fn string, format string, byts []byte) error { + content := fmt.Sprintf("// Code generated by genprelude; DO NOT EDIT.\n\n"+ + "package prelude\n\n"+format+"\n", byts) + + if err := ioutil.WriteFile(fn, []byte(content), 0644); err != nil { + return fmt.Errorf("failed to write to %v: %v", fn, err) + } + + return nil +} diff --git a/compiler/prelude/goroutines.go b/compiler/prelude/goroutines.js similarity index 99% rename from compiler/prelude/goroutines.go rename to compiler/prelude/goroutines.js index d9780b65d..f1ae2d37e 100644 --- a/compiler/prelude/goroutines.go +++ b/compiler/prelude/goroutines.js @@ -1,6 +1,3 @@ -package prelude - -const goroutines = ` var $stackDepthOffset = 0; var $getStackDepth = function() { var err = new Error(); @@ -355,4 +352,3 @@ var $select = function(comms) { $block(); return f; }; -` diff --git a/compiler/prelude/jsmapping.go b/compiler/prelude/jsmapping.js similarity index 99% rename from compiler/prelude/jsmapping.go rename to compiler/prelude/jsmapping.js index dc29cba6b..44a2a96a4 100644 --- a/compiler/prelude/jsmapping.go +++ b/compiler/prelude/jsmapping.js @@ -1,6 +1,3 @@ -package prelude - -const jsmapping = ` var $jsObjectPtr, $jsErrorPtr; var $needsExternalization = function(t) { @@ -376,4 +373,3 @@ var $isASCII = function(s) { } return true; }; -` diff --git a/compiler/prelude/jspmapping.js b/compiler/prelude/jspmapping.js new file mode 100644 index 000000000..e69de29bb diff --git a/compiler/prelude/numeric.go b/compiler/prelude/numeric.js similarity index 99% rename from compiler/prelude/numeric.go rename to compiler/prelude/numeric.js index 063d09f46..3064e33ab 100644 --- a/compiler/prelude/numeric.go +++ b/compiler/prelude/numeric.js @@ -1,6 +1,3 @@ -package prelude - -const numeric = ` var $min = Math.min; var $mod = function(x, y) { return x % y; }; var $parseInt = parseInt; @@ -193,4 +190,3 @@ var $divComplex = function(n, d) { var denom = d.$imag * ratio + d.$real; return new n.constructor((n.$imag * ratio + n.$real) / denom, (n.$imag - n.$real * ratio) / denom); }; -` diff --git a/compiler/prelude/prelude.go b/compiler/prelude/prelude.go index 1eed6c4dc..caa1d2ade 100644 --- a/compiler/prelude/prelude.go +++ b/compiler/prelude/prelude.go @@ -1,422 +1,6 @@ -package prelude +// Code generated by genprelude; DO NOT EDIT. -//go:generate go run genmin.go +package prelude // Prelude is the GopherJS JavaScript interop layer. -const Prelude = prelude + numeric + types + goroutines + jsmapping - -const prelude = `Error.stackTraceLimit = Infinity; - -var $global, $module; -if (typeof window !== "undefined") { /* web page */ - $global = window; -} else if (typeof self !== "undefined") { /* web worker */ - $global = self; -} else if (typeof global !== "undefined") { /* Node.js */ - $global = global; - $global.require = require; -} else { /* others (e.g. Nashorn) */ - $global = this; -} - -if ($global === undefined || $global.Array === undefined) { - throw new Error("no global object found"); -} -if (typeof module !== "undefined") { - $module = module; -} - -var $packages = {}, $idCounter = 0; -var $keys = function(m) { return m ? Object.keys(m) : []; }; -var $flushConsole = function() {}; -var $throwRuntimeError; /* set by package "runtime" */ -var $throwNilPointerError = function() { $throwRuntimeError("invalid memory address or nil pointer dereference"); }; -var $call = function(fn, rcvr, args) { return fn.apply(rcvr, args); }; -var $makeFunc = function(fn) { return function() { return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface); }; }; -var $unused = function(v) {}; - -var $mapArray = function(array, f) { - var newArray = new array.constructor(array.length); - for (var i = 0; i < array.length; i++) { - newArray[i] = f(array[i]); - } - return newArray; -}; - -var $methodVal = function(recv, name) { - var vals = recv.$methodVals || {}; - recv.$methodVals = vals; /* noop for primitives */ - var f = vals[name]; - if (f !== undefined) { - return f; - } - var method = recv[name]; - f = function() { - $stackDepthOffset--; - try { - return method.apply(recv, arguments); - } finally { - $stackDepthOffset++; - } - }; - vals[name] = f; - return f; -}; - -var $methodExpr = function(typ, name) { - var method = typ.prototype[name]; - if (method.$expr === undefined) { - method.$expr = function() { - $stackDepthOffset--; - try { - if (typ.wrapped) { - arguments[0] = new typ(arguments[0]); - } - return Function.call.apply(method, arguments); - } finally { - $stackDepthOffset++; - } - }; - } - return method.$expr; -}; - -var $ifaceMethodExprs = {}; -var $ifaceMethodExpr = function(name) { - var expr = $ifaceMethodExprs["$" + name]; - if (expr === undefined) { - expr = $ifaceMethodExprs["$" + name] = function() { - $stackDepthOffset--; - try { - return Function.call.apply(arguments[0][name], arguments); - } finally { - $stackDepthOffset++; - } - }; - } - return expr; -}; - -var $subslice = function(slice, low, high, max) { - if (high === undefined) { - high = slice.$length; - } - if (max === undefined) { - max = slice.$capacity; - } - if (low < 0 || high < low || max < high || high > slice.$capacity || max > slice.$capacity) { - $throwRuntimeError("slice bounds out of range"); - } - var s = new slice.constructor(slice.$array); - s.$offset = slice.$offset + low; - s.$length = high - low; - s.$capacity = max - low; - return s; -}; - -var $substring = function(str, low, high) { - if (low < 0 || high < low || high > str.length) { - $throwRuntimeError("slice bounds out of range"); - } - return str.substring(low, high); -}; - -var $sliceToArray = function(slice) { - if (slice.$array.constructor !== Array) { - return slice.$array.subarray(slice.$offset, slice.$offset + slice.$length); - } - return slice.$array.slice(slice.$offset, slice.$offset + slice.$length); -}; - -var $decodeRune = function(str, pos) { - var c0 = str.charCodeAt(pos); - - if (c0 < 0x80) { - return [c0, 1]; - } - - if (c0 !== c0 || c0 < 0xC0) { - return [0xFFFD, 1]; - } - - var c1 = str.charCodeAt(pos + 1); - if (c1 !== c1 || c1 < 0x80 || 0xC0 <= c1) { - return [0xFFFD, 1]; - } - - if (c0 < 0xE0) { - var r = (c0 & 0x1F) << 6 | (c1 & 0x3F); - if (r <= 0x7F) { - return [0xFFFD, 1]; - } - return [r, 2]; - } - - var c2 = str.charCodeAt(pos + 2); - if (c2 !== c2 || c2 < 0x80 || 0xC0 <= c2) { - return [0xFFFD, 1]; - } - - if (c0 < 0xF0) { - var r = (c0 & 0x0F) << 12 | (c1 & 0x3F) << 6 | (c2 & 0x3F); - if (r <= 0x7FF) { - return [0xFFFD, 1]; - } - if (0xD800 <= r && r <= 0xDFFF) { - return [0xFFFD, 1]; - } - return [r, 3]; - } - - var c3 = str.charCodeAt(pos + 3); - if (c3 !== c3 || c3 < 0x80 || 0xC0 <= c3) { - return [0xFFFD, 1]; - } - - if (c0 < 0xF8) { - var r = (c0 & 0x07) << 18 | (c1 & 0x3F) << 12 | (c2 & 0x3F) << 6 | (c3 & 0x3F); - if (r <= 0xFFFF || 0x10FFFF < r) { - return [0xFFFD, 1]; - } - return [r, 4]; - } - - return [0xFFFD, 1]; -}; - -var $encodeRune = function(r) { - if (r < 0 || r > 0x10FFFF || (0xD800 <= r && r <= 0xDFFF)) { - r = 0xFFFD; - } - if (r <= 0x7F) { - return String.fromCharCode(r); - } - if (r <= 0x7FF) { - return String.fromCharCode(0xC0 | r >> 6, 0x80 | (r & 0x3F)); - } - if (r <= 0xFFFF) { - return String.fromCharCode(0xE0 | r >> 12, 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F)); - } - return String.fromCharCode(0xF0 | r >> 18, 0x80 | (r >> 12 & 0x3F), 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F)); -}; - -var $stringToBytes = function(str) { - var array = new Uint8Array(str.length); - for (var i = 0; i < str.length; i++) { - array[i] = str.charCodeAt(i); - } - return array; -}; - -var $bytesToString = function(slice) { - if (slice.$length === 0) { - return ""; - } - var str = ""; - for (var i = 0; i < slice.$length; i += 10000) { - str += String.fromCharCode.apply(undefined, slice.$array.subarray(slice.$offset + i, slice.$offset + Math.min(slice.$length, i + 10000))); - } - return str; -}; - -var $stringToRunes = function(str) { - var array = new Int32Array(str.length); - var rune, j = 0; - for (var i = 0; i < str.length; i += rune[1], j++) { - rune = $decodeRune(str, i); - array[j] = rune[0]; - } - return array.subarray(0, j); -}; - -var $runesToString = function(slice) { - if (slice.$length === 0) { - return ""; - } - var str = ""; - for (var i = 0; i < slice.$length; i++) { - str += $encodeRune(slice.$array[slice.$offset + i]); - } - return str; -}; - -var $copyString = function(dst, src) { - var n = Math.min(src.length, dst.$length); - for (var i = 0; i < n; i++) { - dst.$array[dst.$offset + i] = src.charCodeAt(i); - } - return n; -}; - -var $copySlice = function(dst, src) { - var n = Math.min(src.$length, dst.$length); - $copyArray(dst.$array, src.$array, dst.$offset, src.$offset, n, dst.constructor.elem); - return n; -}; - -var $copyArray = function(dst, src, dstOffset, srcOffset, n, elem) { - if (n === 0 || (dst === src && dstOffset === srcOffset)) { - return; - } - - if (src.subarray) { - dst.set(src.subarray(srcOffset, srcOffset + n), dstOffset); - return; - } - - switch (elem.kind) { - case $kindArray: - case $kindStruct: - if (dst === src && dstOffset > srcOffset) { - for (var i = n - 1; i >= 0; i--) { - elem.copy(dst[dstOffset + i], src[srcOffset + i]); - } - return; - } - for (var i = 0; i < n; i++) { - elem.copy(dst[dstOffset + i], src[srcOffset + i]); - } - return; - } - - if (dst === src && dstOffset > srcOffset) { - for (var i = n - 1; i >= 0; i--) { - dst[dstOffset + i] = src[srcOffset + i]; - } - return; - } - for (var i = 0; i < n; i++) { - dst[dstOffset + i] = src[srcOffset + i]; - } -}; - -var $clone = function(src, type) { - var clone = type.zero(); - type.copy(clone, src); - return clone; -}; - -var $pointerOfStructConversion = function(obj, type) { - if(obj.$proxies === undefined) { - obj.$proxies = {}; - obj.$proxies[obj.constructor.string] = obj; - } - var proxy = obj.$proxies[type.string]; - if (proxy === undefined) { - var properties = {}; - for (var i = 0; i < type.elem.fields.length; i++) { - (function(fieldProp) { - properties[fieldProp] = { - get: function() { return obj[fieldProp]; }, - set: function(value) { obj[fieldProp] = value; } - }; - })(type.elem.fields[i].prop); - } - proxy = Object.create(type.prototype, properties); - proxy.$val = proxy; - obj.$proxies[type.string] = proxy; - proxy.$proxies = obj.$proxies; - } - return proxy; -}; - -var $append = function(slice) { - return $internalAppend(slice, arguments, 1, arguments.length - 1); -}; - -var $appendSlice = function(slice, toAppend) { - if (toAppend.constructor === String) { - var bytes = $stringToBytes(toAppend); - return $internalAppend(slice, bytes, 0, bytes.length); - } - return $internalAppend(slice, toAppend.$array, toAppend.$offset, toAppend.$length); -}; - -var $internalAppend = function(slice, array, offset, length) { - if (length === 0) { - return slice; - } - - var newArray = slice.$array; - var newOffset = slice.$offset; - var newLength = slice.$length + length; - var newCapacity = slice.$capacity; - - if (newLength > newCapacity) { - newOffset = 0; - newCapacity = Math.max(newLength, slice.$capacity < 1024 ? slice.$capacity * 2 : Math.floor(slice.$capacity * 5 / 4)); - - if (slice.$array.constructor === Array) { - newArray = slice.$array.slice(slice.$offset, slice.$offset + slice.$length); - newArray.length = newCapacity; - var zero = slice.constructor.elem.zero; - for (var i = slice.$length; i < newCapacity; i++) { - newArray[i] = zero(); - } - } else { - newArray = new slice.$array.constructor(newCapacity); - newArray.set(slice.$array.subarray(slice.$offset, slice.$offset + slice.$length)); - } - } - - $copyArray(newArray, array, newOffset + slice.$length, offset, length, slice.constructor.elem); - - var newSlice = new slice.constructor(newArray); - newSlice.$offset = newOffset; - newSlice.$length = newLength; - newSlice.$capacity = newCapacity; - return newSlice; -}; - -var $equal = function(a, b, type) { - if (type === $jsObjectPtr) { - return a === b; - } - switch (type.kind) { - case $kindComplex64: - case $kindComplex128: - return a.$real === b.$real && a.$imag === b.$imag; - case $kindInt64: - case $kindUint64: - return a.$high === b.$high && a.$low === b.$low; - case $kindArray: - if (a.length !== b.length) { - return false; - } - for (var i = 0; i < a.length; i++) { - if (!$equal(a[i], b[i], type.elem)) { - return false; - } - } - return true; - case $kindStruct: - for (var i = 0; i < type.fields.length; i++) { - var f = type.fields[i]; - if (!$equal(a[f.prop], b[f.prop], f.typ)) { - return false; - } - } - return true; - case $kindInterface: - return $interfaceIsEqual(a, b); - default: - return a === b; - } -}; - -var $interfaceIsEqual = function(a, b) { - if (a === $ifaceNil || b === $ifaceNil) { - return a === b; - } - if (a.constructor !== b.constructor) { - return false; - } - if (a.constructor === $jsObjectPtr) { - return a.object === b.object; - } - if (!a.constructor.comparable) { - $throwRuntimeError("comparing uncomparable type " + a.constructor.string); - } - return $equal(a.$val, b.$val, a.constructor); -}; -` +const Prelude = "Error.stackTraceLimit = Infinity;\n\nvar $global, $module;\nif (typeof window !== \"undefined\") { /* web page */\n $global = window;\n} else if (typeof self !== \"undefined\") { /* web worker */\n $global = self;\n} else if (typeof global !== \"undefined\") { /* Node.js */\n $global = global;\n $global.require = require;\n} else { /* others (e.g. Nashorn) */\n $global = this;\n}\n\nif ($global === undefined || $global.Array === undefined) {\n throw new Error(\"no global object found\");\n}\nif (typeof module !== \"undefined\") {\n $module = module;\n}\n\nvar $packages = {}, $idCounter = 0;\nvar $keys = function(m) { return m ? Object.keys(m) : []; };\nvar $flushConsole = function() {};\nvar $throwRuntimeError; /* set by package \"runtime\" */\nvar $throwNilPointerError = function() { $throwRuntimeError(\"invalid memory address or nil pointer dereference\"); };\nvar $call = function(fn, rcvr, args) { return fn.apply(rcvr, args); };\nvar $makeFunc = function(fn) { return function() { return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface); }; };\nvar $unused = function(v) {};\n\nvar $mapArray = function(array, f) {\n var newArray = new array.constructor(array.length);\n for (var i = 0; i < array.length; i++) {\n newArray[i] = f(array[i]);\n }\n return newArray;\n};\n\nvar $methodVal = function(recv, name) {\n var vals = recv.$methodVals || {};\n recv.$methodVals = vals; /* noop for primitives */\n var f = vals[name];\n if (f !== undefined) {\n return f;\n }\n var method = recv[name];\n f = function() {\n $stackDepthOffset--;\n try {\n return method.apply(recv, arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n vals[name] = f;\n return f;\n};\n\nvar $methodExpr = function(typ, name) {\n var method = typ.prototype[name];\n if (method.$expr === undefined) {\n method.$expr = function() {\n $stackDepthOffset--;\n try {\n if (typ.wrapped) {\n arguments[0] = new typ(arguments[0]);\n }\n return Function.call.apply(method, arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n }\n return method.$expr;\n};\n\nvar $ifaceMethodExprs = {};\nvar $ifaceMethodExpr = function(name) {\n var expr = $ifaceMethodExprs[\"$\" + name];\n if (expr === undefined) {\n expr = $ifaceMethodExprs[\"$\" + name] = function() {\n $stackDepthOffset--;\n try {\n return Function.call.apply(arguments[0][name], arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n }\n return expr;\n};\n\nvar $subslice = function(slice, low, high, max) {\n if (high === undefined) {\n high = slice.$length;\n }\n if (max === undefined) {\n max = slice.$capacity;\n }\n if (low < 0 || high < low || max < high || high > slice.$capacity || max > slice.$capacity) {\n $throwRuntimeError(\"slice bounds out of range\");\n }\n var s = new slice.constructor(slice.$array);\n s.$offset = slice.$offset + low;\n s.$length = high - low;\n s.$capacity = max - low;\n return s;\n};\n\nvar $substring = function(str, low, high) {\n if (low < 0 || high < low || high > str.length) {\n $throwRuntimeError(\"slice bounds out of range\");\n }\n return str.substring(low, high);\n};\n\nvar $sliceToArray = function(slice) {\n if (slice.$array.constructor !== Array) {\n return slice.$array.subarray(slice.$offset, slice.$offset + slice.$length);\n }\n return slice.$array.slice(slice.$offset, slice.$offset + slice.$length);\n};\n\nvar $decodeRune = function(str, pos) {\n var c0 = str.charCodeAt(pos);\n\n if (c0 < 0x80) {\n return [c0, 1];\n }\n\n if (c0 !== c0 || c0 < 0xC0) {\n return [0xFFFD, 1];\n }\n\n var c1 = str.charCodeAt(pos + 1);\n if (c1 !== c1 || c1 < 0x80 || 0xC0 <= c1) {\n return [0xFFFD, 1];\n }\n\n if (c0 < 0xE0) {\n var r = (c0 & 0x1F) << 6 | (c1 & 0x3F);\n if (r <= 0x7F) {\n return [0xFFFD, 1];\n }\n return [r, 2];\n }\n\n var c2 = str.charCodeAt(pos + 2);\n if (c2 !== c2 || c2 < 0x80 || 0xC0 <= c2) {\n return [0xFFFD, 1];\n }\n\n if (c0 < 0xF0) {\n var r = (c0 & 0x0F) << 12 | (c1 & 0x3F) << 6 | (c2 & 0x3F);\n if (r <= 0x7FF) {\n return [0xFFFD, 1];\n }\n if (0xD800 <= r && r <= 0xDFFF) {\n return [0xFFFD, 1];\n }\n return [r, 3];\n }\n\n var c3 = str.charCodeAt(pos + 3);\n if (c3 !== c3 || c3 < 0x80 || 0xC0 <= c3) {\n return [0xFFFD, 1];\n }\n\n if (c0 < 0xF8) {\n var r = (c0 & 0x07) << 18 | (c1 & 0x3F) << 12 | (c2 & 0x3F) << 6 | (c3 & 0x3F);\n if (r <= 0xFFFF || 0x10FFFF < r) {\n return [0xFFFD, 1];\n }\n return [r, 4];\n }\n\n return [0xFFFD, 1];\n};\n\nvar $encodeRune = function(r) {\n if (r < 0 || r > 0x10FFFF || (0xD800 <= r && r <= 0xDFFF)) {\n r = 0xFFFD;\n }\n if (r <= 0x7F) {\n return String.fromCharCode(r);\n }\n if (r <= 0x7FF) {\n return String.fromCharCode(0xC0 | r >> 6, 0x80 | (r & 0x3F));\n }\n if (r <= 0xFFFF) {\n return String.fromCharCode(0xE0 | r >> 12, 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F));\n }\n return String.fromCharCode(0xF0 | r >> 18, 0x80 | (r >> 12 & 0x3F), 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F));\n};\n\nvar $stringToBytes = function(str) {\n var array = new Uint8Array(str.length);\n for (var i = 0; i < str.length; i++) {\n array[i] = str.charCodeAt(i);\n }\n return array;\n};\n\nvar $bytesToString = function(slice) {\n if (slice.$length === 0) {\n return \"\";\n }\n var str = \"\";\n for (var i = 0; i < slice.$length; i += 10000) {\n str += String.fromCharCode.apply(undefined, slice.$array.subarray(slice.$offset + i, slice.$offset + Math.min(slice.$length, i + 10000)));\n }\n return str;\n};\n\nvar $stringToRunes = function(str) {\n var array = new Int32Array(str.length);\n var rune, j = 0;\n for (var i = 0; i < str.length; i += rune[1], j++) {\n rune = $decodeRune(str, i);\n array[j] = rune[0];\n }\n return array.subarray(0, j);\n};\n\nvar $runesToString = function(slice) {\n if (slice.$length === 0) {\n return \"\";\n }\n var str = \"\";\n for (var i = 0; i < slice.$length; i++) {\n str += $encodeRune(slice.$array[slice.$offset + i]);\n }\n return str;\n};\n\nvar $copyString = function(dst, src) {\n var n = Math.min(src.length, dst.$length);\n for (var i = 0; i < n; i++) {\n dst.$array[dst.$offset + i] = src.charCodeAt(i);\n }\n return n;\n};\n\nvar $copySlice = function(dst, src) {\n var n = Math.min(src.$length, dst.$length);\n $copyArray(dst.$array, src.$array, dst.$offset, src.$offset, n, dst.constructor.elem);\n return n;\n};\n\nvar $copyArray = function(dst, src, dstOffset, srcOffset, n, elem) {\n if (n === 0 || (dst === src && dstOffset === srcOffset)) {\n return;\n }\n\n if (src.subarray) {\n dst.set(src.subarray(srcOffset, srcOffset + n), dstOffset);\n return;\n }\n\n switch (elem.kind) {\n case $kindArray:\n case $kindStruct:\n if (dst === src && dstOffset > srcOffset) {\n for (var i = n - 1; i >= 0; i--) {\n elem.copy(dst[dstOffset + i], src[srcOffset + i]);\n }\n return;\n }\n for (var i = 0; i < n; i++) {\n elem.copy(dst[dstOffset + i], src[srcOffset + i]);\n }\n return;\n }\n\n if (dst === src && dstOffset > srcOffset) {\n for (var i = n - 1; i >= 0; i--) {\n dst[dstOffset + i] = src[srcOffset + i];\n }\n return;\n }\n for (var i = 0; i < n; i++) {\n dst[dstOffset + i] = src[srcOffset + i];\n }\n};\n\nvar $clone = function(src, type) {\n var clone = type.zero();\n type.copy(clone, src);\n return clone;\n};\n\nvar $pointerOfStructConversion = function(obj, type) {\n if(obj.$proxies === undefined) {\n obj.$proxies = {};\n obj.$proxies[obj.constructor.string] = obj;\n }\n var proxy = obj.$proxies[type.string];\n if (proxy === undefined) {\n var properties = {};\n for (var i = 0; i < type.elem.fields.length; i++) {\n (function(fieldProp) {\n properties[fieldProp] = {\n get: function() { return obj[fieldProp]; },\n set: function(value) { obj[fieldProp] = value; }\n };\n })(type.elem.fields[i].prop);\n }\n proxy = Object.create(type.prototype, properties);\n proxy.$val = proxy;\n obj.$proxies[type.string] = proxy;\n proxy.$proxies = obj.$proxies;\n }\n return proxy;\n};\n\nvar $append = function(slice) {\n return $internalAppend(slice, arguments, 1, arguments.length - 1);\n};\n\nvar $appendSlice = function(slice, toAppend) {\n if (toAppend.constructor === String) {\n var bytes = $stringToBytes(toAppend);\n return $internalAppend(slice, bytes, 0, bytes.length);\n }\n return $internalAppend(slice, toAppend.$array, toAppend.$offset, toAppend.$length);\n};\n\nvar $internalAppend = function(slice, array, offset, length) {\n if (length === 0) {\n return slice;\n }\n\n var newArray = slice.$array;\n var newOffset = slice.$offset;\n var newLength = slice.$length + length;\n var newCapacity = slice.$capacity;\n\n if (newLength > newCapacity) {\n newOffset = 0;\n newCapacity = Math.max(newLength, slice.$capacity < 1024 ? slice.$capacity * 2 : Math.floor(slice.$capacity * 5 / 4));\n\n if (slice.$array.constructor === Array) {\n newArray = slice.$array.slice(slice.$offset, slice.$offset + slice.$length);\n newArray.length = newCapacity;\n var zero = slice.constructor.elem.zero;\n for (var i = slice.$length; i < newCapacity; i++) {\n newArray[i] = zero();\n }\n } else {\n newArray = new slice.$array.constructor(newCapacity);\n newArray.set(slice.$array.subarray(slice.$offset, slice.$offset + slice.$length));\n }\n }\n\n $copyArray(newArray, array, newOffset + slice.$length, offset, length, slice.constructor.elem);\n\n var newSlice = new slice.constructor(newArray);\n newSlice.$offset = newOffset;\n newSlice.$length = newLength;\n newSlice.$capacity = newCapacity;\n return newSlice;\n};\n\nvar $equal = function(a, b, type) {\n if (type === $jsObjectPtr) {\n return a === b;\n }\n switch (type.kind) {\n case $kindComplex64:\n case $kindComplex128:\n return a.$real === b.$real && a.$imag === b.$imag;\n case $kindInt64:\n case $kindUint64:\n return a.$high === b.$high && a.$low === b.$low;\n case $kindArray:\n if (a.length !== b.length) {\n return false;\n }\n for (var i = 0; i < a.length; i++) {\n if (!$equal(a[i], b[i], type.elem)) {\n return false;\n }\n }\n return true;\n case $kindStruct:\n for (var i = 0; i < type.fields.length; i++) {\n var f = type.fields[i];\n if (!$equal(a[f.prop], b[f.prop], f.typ)) {\n return false;\n }\n }\n return true;\n case $kindInterface:\n return $interfaceIsEqual(a, b);\n default:\n return a === b;\n }\n};\n\nvar $interfaceIsEqual = function(a, b) {\n if (a === $ifaceNil || b === $ifaceNil) {\n return a === b;\n }\n if (a.constructor !== b.constructor) {\n return false;\n }\n if (a.constructor === $jsObjectPtr) {\n return a.object === b.object;\n }\n if (!a.constructor.comparable) {\n $throwRuntimeError(\"comparing uncomparable type \" + a.constructor.string);\n }\n return $equal(a.$val, b.$val, a.constructor);\n};\nvar $min = Math.min;\nvar $mod = function(x, y) { return x % y; };\nvar $parseInt = parseInt;\nvar $parseFloat = function(f) {\n if (f !== undefined && f !== null && f.constructor === Number) {\n return f;\n }\n return parseFloat(f);\n};\n\nvar $froundBuf = new Float32Array(1);\nvar $fround = Math.fround || function(f) {\n $froundBuf[0] = f;\n return $froundBuf[0];\n};\n\nvar $imul = Math.imul || function(a, b) {\n var ah = (a >>> 16) & 0xffff;\n var al = a & 0xffff;\n var bh = (b >>> 16) & 0xffff;\n var bl = b & 0xffff;\n return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) >> 0);\n};\n\nvar $floatKey = function(f) {\n if (f !== f) {\n $idCounter++;\n return \"NaN$\" + $idCounter;\n }\n return String(f);\n};\n\nvar $flatten64 = function(x) {\n return x.$high * 4294967296 + x.$low;\n};\n\nvar $shiftLeft64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high << y | x.$low >>> (32 - y), (x.$low << y) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(x.$low << (y - 32), 0);\n }\n return new x.constructor(0, 0);\n};\n\nvar $shiftRightInt64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high >> y, (x.$low >>> y | x.$high << (32 - y)) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(x.$high >> 31, (x.$high >> (y - 32)) >>> 0);\n }\n if (x.$high < 0) {\n return new x.constructor(-1, 4294967295);\n }\n return new x.constructor(0, 0);\n};\n\nvar $shiftRightUint64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high >>> y, (x.$low >>> y | x.$high << (32 - y)) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(0, x.$high >>> (y - 32));\n }\n return new x.constructor(0, 0);\n};\n\nvar $mul64 = function(x, y) {\n var high = 0, low = 0;\n if ((y.$low & 1) !== 0) {\n high = x.$high;\n low = x.$low;\n }\n for (var i = 1; i < 32; i++) {\n if ((y.$low & 1<>> (32 - i);\n low += (x.$low << i) >>> 0;\n }\n }\n for (var i = 0; i < 32; i++) {\n if ((y.$high & 1< yHigh) || (xHigh === yHigh && xLow > yLow))) {\n yHigh = (yHigh << 1 | yLow >>> 31) >>> 0;\n yLow = (yLow << 1) >>> 0;\n n++;\n }\n for (var i = 0; i <= n; i++) {\n high = high << 1 | low >>> 31;\n low = (low << 1) >>> 0;\n if ((xHigh > yHigh) || (xHigh === yHigh && xLow >= yLow)) {\n xHigh = xHigh - yHigh;\n xLow = xLow - yLow;\n if (xLow < 0) {\n xHigh--;\n xLow += 4294967296;\n }\n low++;\n if (low === 4294967296) {\n high++;\n low = 0;\n }\n }\n yLow = (yLow >>> 1 | yHigh << (32 - 1)) >>> 0;\n yHigh = yHigh >>> 1;\n }\n\n if (returnRemainder) {\n return new x.constructor(xHigh * rs, xLow * rs);\n }\n return new x.constructor(high * s, low * s);\n};\n\nvar $divComplex = function(n, d) {\n var ninf = n.$real === Infinity || n.$real === -Infinity || n.$imag === Infinity || n.$imag === -Infinity;\n var dinf = d.$real === Infinity || d.$real === -Infinity || d.$imag === Infinity || d.$imag === -Infinity;\n var nnan = !ninf && (n.$real !== n.$real || n.$imag !== n.$imag);\n var dnan = !dinf && (d.$real !== d.$real || d.$imag !== d.$imag);\n if(nnan || dnan) {\n return new n.constructor(NaN, NaN);\n }\n if (ninf && !dinf) {\n return new n.constructor(Infinity, Infinity);\n }\n if (!ninf && dinf) {\n return new n.constructor(0, 0);\n }\n if (d.$real === 0 && d.$imag === 0) {\n if (n.$real === 0 && n.$imag === 0) {\n return new n.constructor(NaN, NaN);\n }\n return new n.constructor(Infinity, Infinity);\n }\n var a = Math.abs(d.$real);\n var b = Math.abs(d.$imag);\n if (a <= b) {\n var ratio = d.$real / d.$imag;\n var denom = d.$real * ratio + d.$imag;\n return new n.constructor((n.$real * ratio + n.$imag) / denom, (n.$imag * ratio - n.$real) / denom);\n }\n var ratio = d.$imag / d.$real;\n var denom = d.$imag * ratio + d.$real;\n return new n.constructor((n.$imag * ratio + n.$real) / denom, (n.$imag - n.$real * ratio) / denom);\n};\nvar $kindBool = 1;\nvar $kindInt = 2;\nvar $kindInt8 = 3;\nvar $kindInt16 = 4;\nvar $kindInt32 = 5;\nvar $kindInt64 = 6;\nvar $kindUint = 7;\nvar $kindUint8 = 8;\nvar $kindUint16 = 9;\nvar $kindUint32 = 10;\nvar $kindUint64 = 11;\nvar $kindUintptr = 12;\nvar $kindFloat32 = 13;\nvar $kindFloat64 = 14;\nvar $kindComplex64 = 15;\nvar $kindComplex128 = 16;\nvar $kindArray = 17;\nvar $kindChan = 18;\nvar $kindFunc = 19;\nvar $kindInterface = 20;\nvar $kindMap = 21;\nvar $kindPtr = 22;\nvar $kindSlice = 23;\nvar $kindString = 24;\nvar $kindStruct = 25;\nvar $kindUnsafePointer = 26;\n\nvar $methodSynthesizers = [];\nvar $addMethodSynthesizer = function(f) {\n if ($methodSynthesizers === null) {\n f();\n return;\n }\n $methodSynthesizers.push(f);\n};\nvar $synthesizeMethods = function() {\n $methodSynthesizers.forEach(function(f) { f(); });\n $methodSynthesizers = null;\n};\n\nvar $ifaceKeyFor = function(x) {\n if (x === $ifaceNil) {\n return 'nil';\n }\n var c = x.constructor;\n return c.string + '$' + c.keyFor(x.$val);\n};\n\nvar $identity = function(x) { return x; };\n\nvar $typeIDCounter = 0;\n\nvar $idKey = function(x) {\n if (x.$id === undefined) {\n $idCounter++;\n x.$id = $idCounter;\n }\n return String(x.$id);\n};\n\nvar $newType = function(size, kind, string, named, pkg, exported, constructor) {\n var typ;\n switch(kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindUnsafePointer:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = $identity;\n break;\n\n case $kindString:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = function(x) { return \"$\" + x; };\n break;\n\n case $kindFloat32:\n case $kindFloat64:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = function(x) { return $floatKey(x); };\n break;\n\n case $kindInt64:\n typ = function(high, low) {\n this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >> 0;\n this.$low = low >>> 0;\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$high + \"$\" + x.$low; };\n break;\n\n case $kindUint64:\n typ = function(high, low) {\n this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >>> 0;\n this.$low = low >>> 0;\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$high + \"$\" + x.$low; };\n break;\n\n case $kindComplex64:\n typ = function(real, imag) {\n this.$real = $fround(real);\n this.$imag = $fround(imag);\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$real + \"$\" + x.$imag; };\n break;\n\n case $kindComplex128:\n typ = function(real, imag) {\n this.$real = real;\n this.$imag = imag;\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$real + \"$\" + x.$imag; };\n break;\n\n case $kindArray:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.ptr = $newType(4, $kindPtr, \"*\" + string, false, \"\", false, function(array) {\n this.$get = function() { return array; };\n this.$set = function(v) { typ.copy(this, v); };\n this.$val = array;\n });\n typ.init = function(elem, len) {\n typ.elem = elem;\n typ.len = len;\n typ.comparable = elem.comparable;\n typ.keyFor = function(x) {\n return Array.prototype.join.call($mapArray(x, function(e) {\n return String(elem.keyFor(e)).replace(/\\\\/g, \"\\\\\\\\\").replace(/\\$/g, \"\\\\$\");\n }), \"$\");\n };\n typ.copy = function(dst, src) {\n $copyArray(dst, src, 0, 0, src.length, elem);\n };\n typ.ptr.init(typ);\n Object.defineProperty(typ.ptr.nil, \"nilCheck\", { get: $throwNilPointerError });\n };\n break;\n\n case $kindChan:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = $idKey;\n typ.init = function(elem, sendOnly, recvOnly) {\n typ.elem = elem;\n typ.sendOnly = sendOnly;\n typ.recvOnly = recvOnly;\n };\n break;\n\n case $kindFunc:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.init = function(params, results, variadic) {\n typ.params = params;\n typ.results = results;\n typ.variadic = variadic;\n typ.comparable = false;\n };\n break;\n\n case $kindInterface:\n typ = { implementedBy: {}, missingMethodFor: {} };\n typ.keyFor = $ifaceKeyFor;\n typ.init = function(methods) {\n typ.methods = methods;\n methods.forEach(function(m) {\n $ifaceNil[m.prop] = $throwNilPointerError;\n });\n };\n break;\n\n case $kindMap:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.init = function(key, elem) {\n typ.key = key;\n typ.elem = elem;\n typ.comparable = false;\n };\n break;\n\n case $kindPtr:\n typ = constructor || function(getter, setter, target) {\n this.$get = getter;\n this.$set = setter;\n this.$target = target;\n this.$val = this;\n };\n typ.keyFor = $idKey;\n typ.init = function(elem) {\n typ.elem = elem;\n typ.wrapped = (elem.kind === $kindArray);\n typ.nil = new typ($throwNilPointerError, $throwNilPointerError);\n };\n break;\n\n case $kindSlice:\n typ = function(array) {\n if (array.constructor !== typ.nativeArray) {\n array = new typ.nativeArray(array);\n }\n this.$array = array;\n this.$offset = 0;\n this.$length = array.length;\n this.$capacity = array.length;\n this.$val = this;\n };\n typ.init = function(elem) {\n typ.elem = elem;\n typ.comparable = false;\n typ.nativeArray = $nativeArray(elem.kind);\n typ.nil = new typ([]);\n };\n break;\n\n case $kindStruct:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.ptr = $newType(4, $kindPtr, \"*\" + string, false, pkg, exported, constructor);\n typ.ptr.elem = typ;\n typ.ptr.prototype.$get = function() { return this; };\n typ.ptr.prototype.$set = function(v) { typ.copy(this, v); };\n typ.init = function(pkgPath, fields) {\n typ.pkgPath = pkgPath;\n typ.fields = fields;\n fields.forEach(function(f) {\n if (!f.typ.comparable) {\n typ.comparable = false;\n }\n });\n typ.keyFor = function(x) {\n var val = x.$val;\n return $mapArray(fields, function(f) {\n return String(f.typ.keyFor(val[f.prop])).replace(/\\\\/g, \"\\\\\\\\\").replace(/\\$/g, \"\\\\$\");\n }).join(\"$\");\n };\n typ.copy = function(dst, src) {\n for (var i = 0; i < fields.length; i++) {\n var f = fields[i];\n switch (f.typ.kind) {\n case $kindArray:\n case $kindStruct:\n f.typ.copy(dst[f.prop], src[f.prop]);\n continue;\n default:\n dst[f.prop] = src[f.prop];\n continue;\n }\n }\n };\n /* nil value */\n var properties = {};\n fields.forEach(function(f) {\n properties[f.prop] = { get: $throwNilPointerError, set: $throwNilPointerError };\n });\n typ.ptr.nil = Object.create(constructor.prototype, properties);\n typ.ptr.nil.$val = typ.ptr.nil;\n /* methods for embedded fields */\n $addMethodSynthesizer(function() {\n var synthesizeMethod = function(target, m, f) {\n if (target.prototype[m.prop] !== undefined) { return; }\n target.prototype[m.prop] = function() {\n var v = this.$val[f.prop];\n if (f.typ === $jsObjectPtr) {\n v = new $jsObjectPtr(v);\n }\n if (v.$val === undefined) {\n v = new f.typ(v);\n }\n return v[m.prop].apply(v, arguments);\n };\n };\n fields.forEach(function(f) {\n if (f.anonymous) {\n $methodSet(f.typ).forEach(function(m) {\n synthesizeMethod(typ, m, f);\n synthesizeMethod(typ.ptr, m, f);\n });\n $methodSet($ptrType(f.typ)).forEach(function(m) {\n synthesizeMethod(typ.ptr, m, f);\n });\n }\n });\n });\n };\n break;\n\n default:\n $panic(new $String(\"invalid kind: \" + kind));\n }\n\n switch (kind) {\n case $kindBool:\n case $kindMap:\n typ.zero = function() { return false; };\n break;\n\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8 :\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindUnsafePointer:\n case $kindFloat32:\n case $kindFloat64:\n typ.zero = function() { return 0; };\n break;\n\n case $kindString:\n typ.zero = function() { return \"\"; };\n break;\n\n case $kindInt64:\n case $kindUint64:\n case $kindComplex64:\n case $kindComplex128:\n var zero = new typ(0, 0);\n typ.zero = function() { return zero; };\n break;\n\n case $kindPtr:\n case $kindSlice:\n typ.zero = function() { return typ.nil; };\n break;\n\n case $kindChan:\n typ.zero = function() { return $chanNil; };\n break;\n\n case $kindFunc:\n typ.zero = function() { return $throwNilPointerError; };\n break;\n\n case $kindInterface:\n typ.zero = function() { return $ifaceNil; };\n break;\n\n case $kindArray:\n typ.zero = function() {\n var arrayClass = $nativeArray(typ.elem.kind);\n if (arrayClass !== Array) {\n return new arrayClass(typ.len);\n }\n var array = new Array(typ.len);\n for (var i = 0; i < typ.len; i++) {\n array[i] = typ.elem.zero();\n }\n return array;\n };\n break;\n\n case $kindStruct:\n typ.zero = function() { return new typ.ptr(); };\n break;\n\n default:\n $panic(new $String(\"invalid kind: \" + kind));\n }\n\n typ.id = $typeIDCounter;\n $typeIDCounter++;\n typ.size = size;\n typ.kind = kind;\n typ.string = string;\n typ.named = named;\n typ.pkg = pkg;\n typ.exported = exported;\n typ.methods = [];\n typ.methodSetCache = null;\n typ.comparable = true;\n return typ;\n};\n\nvar $methodSet = function(typ) {\n if (typ.methodSetCache !== null) {\n return typ.methodSetCache;\n }\n var base = {};\n\n var isPtr = (typ.kind === $kindPtr);\n if (isPtr && typ.elem.kind === $kindInterface) {\n typ.methodSetCache = [];\n return [];\n }\n\n var current = [{typ: isPtr ? typ.elem : typ, indirect: isPtr}];\n\n var seen = {};\n\n while (current.length > 0) {\n var next = [];\n var mset = [];\n\n current.forEach(function(e) {\n if (seen[e.typ.string]) {\n return;\n }\n seen[e.typ.string] = true;\n\n if (e.typ.named) {\n mset = mset.concat(e.typ.methods);\n if (e.indirect) {\n mset = mset.concat($ptrType(e.typ).methods);\n }\n }\n\n switch (e.typ.kind) {\n case $kindStruct:\n e.typ.fields.forEach(function(f) {\n if (f.anonymous) {\n var fTyp = f.typ;\n var fIsPtr = (fTyp.kind === $kindPtr);\n next.push({typ: fIsPtr ? fTyp.elem : fTyp, indirect: e.indirect || fIsPtr});\n }\n });\n break;\n\n case $kindInterface:\n mset = mset.concat(e.typ.methods);\n break;\n }\n });\n\n mset.forEach(function(m) {\n if (base[m.name] === undefined) {\n base[m.name] = m;\n }\n });\n\n current = next;\n }\n\n typ.methodSetCache = [];\n Object.keys(base).sort().forEach(function(name) {\n typ.methodSetCache.push(base[name]);\n });\n return typ.methodSetCache;\n};\n\nvar $Bool = $newType( 1, $kindBool, \"bool\", true, \"\", false, null);\nvar $Int = $newType( 4, $kindInt, \"int\", true, \"\", false, null);\nvar $Int8 = $newType( 1, $kindInt8, \"int8\", true, \"\", false, null);\nvar $Int16 = $newType( 2, $kindInt16, \"int16\", true, \"\", false, null);\nvar $Int32 = $newType( 4, $kindInt32, \"int32\", true, \"\", false, null);\nvar $Int64 = $newType( 8, $kindInt64, \"int64\", true, \"\", false, null);\nvar $Uint = $newType( 4, $kindUint, \"uint\", true, \"\", false, null);\nvar $Uint8 = $newType( 1, $kindUint8, \"uint8\", true, \"\", false, null);\nvar $Uint16 = $newType( 2, $kindUint16, \"uint16\", true, \"\", false, null);\nvar $Uint32 = $newType( 4, $kindUint32, \"uint32\", true, \"\", false, null);\nvar $Uint64 = $newType( 8, $kindUint64, \"uint64\", true, \"\", false, null);\nvar $Uintptr = $newType( 4, $kindUintptr, \"uintptr\", true, \"\", false, null);\nvar $Float32 = $newType( 4, $kindFloat32, \"float32\", true, \"\", false, null);\nvar $Float64 = $newType( 8, $kindFloat64, \"float64\", true, \"\", false, null);\nvar $Complex64 = $newType( 8, $kindComplex64, \"complex64\", true, \"\", false, null);\nvar $Complex128 = $newType(16, $kindComplex128, \"complex128\", true, \"\", false, null);\nvar $String = $newType( 8, $kindString, \"string\", true, \"\", false, null);\nvar $UnsafePointer = $newType( 4, $kindUnsafePointer, \"unsafe.Pointer\", true, \"\", false, null);\n\nvar $nativeArray = function(elemKind) {\n switch (elemKind) {\n case $kindInt:\n return Int32Array;\n case $kindInt8:\n return Int8Array;\n case $kindInt16:\n return Int16Array;\n case $kindInt32:\n return Int32Array;\n case $kindUint:\n return Uint32Array;\n case $kindUint8:\n return Uint8Array;\n case $kindUint16:\n return Uint16Array;\n case $kindUint32:\n return Uint32Array;\n case $kindUintptr:\n return Uint32Array;\n case $kindFloat32:\n return Float32Array;\n case $kindFloat64:\n return Float64Array;\n default:\n return Array;\n }\n};\nvar $toNativeArray = function(elemKind, array) {\n var nativeArray = $nativeArray(elemKind);\n if (nativeArray === Array) {\n return array;\n }\n return new nativeArray(array);\n};\nvar $arrayTypes = {};\nvar $arrayType = function(elem, len) {\n var typeKey = elem.id + \"$\" + len;\n var typ = $arrayTypes[typeKey];\n if (typ === undefined) {\n typ = $newType(12, $kindArray, \"[\" + len + \"]\" + elem.string, false, \"\", false, null);\n $arrayTypes[typeKey] = typ;\n typ.init(elem, len);\n }\n return typ;\n};\n\nvar $chanType = function(elem, sendOnly, recvOnly) {\n var string = (recvOnly ? \"<-\" : \"\") + \"chan\" + (sendOnly ? \"<- \" : \" \") + elem.string;\n var field = sendOnly ? \"SendChan\" : (recvOnly ? \"RecvChan\" : \"Chan\");\n var typ = elem[field];\n if (typ === undefined) {\n typ = $newType(4, $kindChan, string, false, \"\", false, null);\n elem[field] = typ;\n typ.init(elem, sendOnly, recvOnly);\n }\n return typ;\n};\nvar $Chan = function(elem, capacity) {\n if (capacity < 0 || capacity > 2147483647) {\n $throwRuntimeError(\"makechan: size out of range\");\n }\n this.$elem = elem;\n this.$capacity = capacity;\n this.$buffer = [];\n this.$sendQueue = [];\n this.$recvQueue = [];\n this.$closed = false;\n};\nvar $chanNil = new $Chan(null, 0);\n$chanNil.$sendQueue = $chanNil.$recvQueue = { length: 0, push: function() {}, shift: function() { return undefined; }, indexOf: function() { return -1; } };\n\nvar $funcTypes = {};\nvar $funcType = function(params, results, variadic) {\n var typeKey = $mapArray(params, function(p) { return p.id; }).join(\",\") + \"$\" + $mapArray(results, function(r) { return r.id; }).join(\",\") + \"$\" + variadic;\n var typ = $funcTypes[typeKey];\n if (typ === undefined) {\n var paramTypes = $mapArray(params, function(p) { return p.string; });\n if (variadic) {\n paramTypes[paramTypes.length - 1] = \"...\" + paramTypes[paramTypes.length - 1].substr(2);\n }\n var string = \"func(\" + paramTypes.join(\", \") + \")\";\n if (results.length === 1) {\n string += \" \" + results[0].string;\n } else if (results.length > 1) {\n string += \" (\" + $mapArray(results, function(r) { return r.string; }).join(\", \") + \")\";\n }\n typ = $newType(4, $kindFunc, string, false, \"\", false, null);\n $funcTypes[typeKey] = typ;\n typ.init(params, results, variadic);\n }\n return typ;\n};\n\nvar $interfaceTypes = {};\nvar $interfaceType = function(methods) {\n var typeKey = $mapArray(methods, function(m) { return m.pkg + \",\" + m.name + \",\" + m.typ.id; }).join(\"$\");\n var typ = $interfaceTypes[typeKey];\n if (typ === undefined) {\n var string = \"interface {}\";\n if (methods.length !== 0) {\n string = \"interface { \" + $mapArray(methods, function(m) {\n return (m.pkg !== \"\" ? m.pkg + \".\" : \"\") + m.name + m.typ.string.substr(4);\n }).join(\"; \") + \" }\";\n }\n typ = $newType(8, $kindInterface, string, false, \"\", false, null);\n $interfaceTypes[typeKey] = typ;\n typ.init(methods);\n }\n return typ;\n};\nvar $emptyInterface = $interfaceType([]);\nvar $ifaceNil = {};\nvar $error = $newType(8, $kindInterface, \"error\", true, \"\", false, null);\n$error.init([{prop: \"Error\", name: \"Error\", pkg: \"\", typ: $funcType([], [$String], false)}]);\n\nvar $mapTypes = {};\nvar $mapType = function(key, elem) {\n var typeKey = key.id + \"$\" + elem.id;\n var typ = $mapTypes[typeKey];\n if (typ === undefined) {\n typ = $newType(4, $kindMap, \"map[\" + key.string + \"]\" + elem.string, false, \"\", false, null);\n $mapTypes[typeKey] = typ;\n typ.init(key, elem);\n }\n return typ;\n};\nvar $makeMap = function(keyForFunc, entries) {\n var m = {};\n for (var i = 0; i < entries.length; i++) {\n var e = entries[i];\n m[keyForFunc(e.k)] = e;\n }\n return m;\n};\n\nvar $ptrType = function(elem) {\n var typ = elem.ptr;\n if (typ === undefined) {\n typ = $newType(4, $kindPtr, \"*\" + elem.string, false, \"\", elem.exported, null);\n elem.ptr = typ;\n typ.init(elem);\n }\n return typ;\n};\n\nvar $newDataPointer = function(data, constructor) {\n if (constructor.elem.kind === $kindStruct) {\n return data;\n }\n return new constructor(function() { return data; }, function(v) { data = v; });\n};\n\nvar $indexPtr = function(array, index, constructor) {\n array.$ptr = array.$ptr || {};\n return array.$ptr[index] || (array.$ptr[index] = new constructor(function() { return array[index]; }, function(v) { array[index] = v; }));\n};\n\nvar $sliceType = function(elem) {\n var typ = elem.slice;\n if (typ === undefined) {\n typ = $newType(12, $kindSlice, \"[]\" + elem.string, false, \"\", false, null);\n elem.slice = typ;\n typ.init(elem);\n }\n return typ;\n};\nvar $makeSlice = function(typ, length, capacity) {\n capacity = capacity || length;\n if (length < 0 || length > 2147483647) {\n $throwRuntimeError(\"makeslice: len out of range\");\n }\n if (capacity < 0 || capacity < length || capacity > 2147483647) {\n $throwRuntimeError(\"makeslice: cap out of range\");\n }\n var array = new typ.nativeArray(capacity);\n if (typ.nativeArray === Array) {\n for (var i = 0; i < capacity; i++) {\n array[i] = typ.elem.zero();\n }\n }\n var slice = new typ(array);\n slice.$length = length;\n return slice;\n};\n\nvar $structTypes = {};\nvar $structType = function(pkgPath, fields) {\n var typeKey = $mapArray(fields, function(f) { return f.name + \",\" + f.typ.id + \",\" + f.tag; }).join(\"$\");\n var typ = $structTypes[typeKey];\n if (typ === undefined) {\n var string = \"struct { \" + $mapArray(fields, function(f) {\n return f.name + \" \" + f.typ.string + (f.tag !== \"\" ? (\" \\\"\" + f.tag.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, \"\\\\\\\"\") + \"\\\"\") : \"\");\n }).join(\"; \") + \" }\";\n if (fields.length === 0) {\n string = \"struct {}\";\n }\n typ = $newType(0, $kindStruct, string, false, \"\", false, function() {\n this.$val = this;\n for (var i = 0; i < fields.length; i++) {\n var f = fields[i];\n var arg = arguments[i];\n this[f.prop] = arg !== undefined ? arg : f.typ.zero();\n }\n });\n $structTypes[typeKey] = typ;\n typ.init(pkgPath, fields);\n }\n return typ;\n};\n\nvar $assertType = function(value, type, returnTuple) {\n var isInterface = (type.kind === $kindInterface), ok, missingMethod = \"\";\n if (value === $ifaceNil) {\n ok = false;\n } else if (!isInterface) {\n ok = value.constructor === type;\n } else {\n var valueTypeString = value.constructor.string;\n ok = type.implementedBy[valueTypeString];\n if (ok === undefined) {\n ok = true;\n var valueMethodSet = $methodSet(value.constructor);\n var interfaceMethods = type.methods;\n for (var i = 0; i < interfaceMethods.length; i++) {\n var tm = interfaceMethods[i];\n var found = false;\n for (var j = 0; j < valueMethodSet.length; j++) {\n var vm = valueMethodSet[j];\n if (vm.name === tm.name && vm.pkg === tm.pkg && vm.typ === tm.typ) {\n found = true;\n break;\n }\n }\n if (!found) {\n ok = false;\n type.missingMethodFor[valueTypeString] = tm.name;\n break;\n }\n }\n type.implementedBy[valueTypeString] = ok;\n }\n if (!ok) {\n missingMethod = type.missingMethodFor[valueTypeString];\n }\n }\n\n if (!ok) {\n if (returnTuple) {\n return [type.zero(), false];\n }\n $panic(new $packages[\"runtime\"].TypeAssertionError.ptr(\"\", (value === $ifaceNil ? \"\" : value.constructor.string), type.string, missingMethod));\n }\n\n if (!isInterface) {\n value = value.$val;\n }\n if (type === $jsObjectPtr) {\n value = value.object;\n }\n return returnTuple ? [value, true] : value;\n};\nvar $stackDepthOffset = 0;\nvar $getStackDepth = function() {\n var err = new Error();\n if (err.stack === undefined) {\n return undefined;\n }\n return $stackDepthOffset + err.stack.split(\"\\n\").length;\n};\n\nvar $panicStackDepth = null, $panicValue;\nvar $callDeferred = function(deferred, jsErr, fromPanic) {\n if (!fromPanic && deferred !== null && deferred.index >= $curGoroutine.deferStack.length) {\n throw jsErr;\n }\n if (jsErr !== null) {\n var newErr = null;\n try {\n $curGoroutine.deferStack.push(deferred);\n $panic(new $jsErrorPtr(jsErr));\n } catch (err) {\n newErr = err;\n }\n $curGoroutine.deferStack.pop();\n $callDeferred(deferred, newErr);\n return;\n }\n if ($curGoroutine.asleep) {\n return;\n }\n\n $stackDepthOffset--;\n var outerPanicStackDepth = $panicStackDepth;\n var outerPanicValue = $panicValue;\n\n var localPanicValue = $curGoroutine.panicStack.pop();\n if (localPanicValue !== undefined) {\n $panicStackDepth = $getStackDepth();\n $panicValue = localPanicValue;\n }\n\n try {\n while (true) {\n if (deferred === null) {\n deferred = $curGoroutine.deferStack[$curGoroutine.deferStack.length - 1];\n if (deferred === undefined) {\n /* The panic reached the top of the stack. Clear it and throw it as a JavaScript error. */\n $panicStackDepth = null;\n if (localPanicValue.Object instanceof Error) {\n throw localPanicValue.Object;\n }\n var msg;\n if (localPanicValue.constructor === $String) {\n msg = localPanicValue.$val;\n } else if (localPanicValue.Error !== undefined) {\n msg = localPanicValue.Error();\n } else if (localPanicValue.String !== undefined) {\n msg = localPanicValue.String();\n } else {\n msg = localPanicValue;\n }\n throw new Error(msg);\n }\n }\n var call = deferred.pop();\n if (call === undefined) {\n $curGoroutine.deferStack.pop();\n if (localPanicValue !== undefined) {\n deferred = null;\n continue;\n }\n return;\n }\n var r = call[0].apply(call[2], call[1]);\n if (r && r.$blk !== undefined) {\n deferred.push([r.$blk, [], r]);\n if (fromPanic) {\n throw null;\n }\n return;\n }\n\n if (localPanicValue !== undefined && $panicStackDepth === null) {\n throw null; /* error was recovered */\n }\n }\n } finally {\n if (localPanicValue !== undefined) {\n if ($panicStackDepth !== null) {\n $curGoroutine.panicStack.push(localPanicValue);\n }\n $panicStackDepth = outerPanicStackDepth;\n $panicValue = outerPanicValue;\n }\n $stackDepthOffset++;\n }\n};\n\nvar $panic = function(value) {\n $curGoroutine.panicStack.push(value);\n $callDeferred(null, null, true);\n};\nvar $recover = function() {\n if ($panicStackDepth === null || ($panicStackDepth !== undefined && $panicStackDepth !== $getStackDepth() - 2)) {\n return $ifaceNil;\n }\n $panicStackDepth = null;\n return $panicValue;\n};\nvar $throw = function(err) { throw err; };\n\nvar $noGoroutine = { asleep: false, exit: false, deferStack: [], panicStack: [] };\nvar $curGoroutine = $noGoroutine, $totalGoroutines = 0, $awakeGoroutines = 0, $checkForDeadlock = true;\nvar $mainFinished = false;\nvar $go = function(fun, args) {\n $totalGoroutines++;\n $awakeGoroutines++;\n var $goroutine = function() {\n try {\n $curGoroutine = $goroutine;\n var r = fun.apply(undefined, args);\n if (r && r.$blk !== undefined) {\n fun = function() { return r.$blk(); };\n args = [];\n return;\n }\n $goroutine.exit = true;\n } catch (err) {\n if (!$goroutine.exit) {\n throw err;\n }\n } finally {\n $curGoroutine = $noGoroutine;\n if ($goroutine.exit) { /* also set by runtime.Goexit() */\n $totalGoroutines--;\n $goroutine.asleep = true;\n }\n if ($goroutine.asleep) {\n $awakeGoroutines--;\n if (!$mainFinished && $awakeGoroutines === 0 && $checkForDeadlock) {\n console.error(\"fatal error: all goroutines are asleep - deadlock!\");\n if ($global.process !== undefined) {\n $global.process.exit(2);\n }\n }\n }\n }\n };\n $goroutine.asleep = false;\n $goroutine.exit = false;\n $goroutine.deferStack = [];\n $goroutine.panicStack = [];\n $schedule($goroutine);\n};\n\nvar $scheduled = [];\nvar $runScheduled = function() {\n try {\n var r;\n while ((r = $scheduled.shift()) !== undefined) {\n r();\n }\n } finally {\n if ($scheduled.length > 0) {\n setTimeout($runScheduled, 0);\n }\n }\n};\n\nvar $schedule = function(goroutine) {\n if (goroutine.asleep) {\n goroutine.asleep = false;\n $awakeGoroutines++;\n }\n $scheduled.push(goroutine);\n if ($curGoroutine === $noGoroutine) {\n $runScheduled();\n }\n};\n\nvar $setTimeout = function(f, t) {\n $awakeGoroutines++;\n return setTimeout(function() {\n $awakeGoroutines--;\n f();\n }, t);\n};\n\nvar $block = function() {\n if ($curGoroutine === $noGoroutine) {\n $throwRuntimeError(\"cannot block in JavaScript callback, fix by wrapping code in goroutine\");\n }\n $curGoroutine.asleep = true;\n};\n\nvar $send = function(chan, value) {\n if (chan.$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n var queuedRecv = chan.$recvQueue.shift();\n if (queuedRecv !== undefined) {\n queuedRecv([value, true]);\n return;\n }\n if (chan.$buffer.length < chan.$capacity) {\n chan.$buffer.push(value);\n return;\n }\n\n var thisGoroutine = $curGoroutine;\n var closedDuringSend;\n chan.$sendQueue.push(function(closed) {\n closedDuringSend = closed;\n $schedule(thisGoroutine);\n return value;\n });\n $block();\n return {\n $blk: function() {\n if (closedDuringSend) {\n $throwRuntimeError(\"send on closed channel\");\n }\n }\n };\n};\nvar $recv = function(chan) {\n var queuedSend = chan.$sendQueue.shift();\n if (queuedSend !== undefined) {\n chan.$buffer.push(queuedSend(false));\n }\n var bufferedValue = chan.$buffer.shift();\n if (bufferedValue !== undefined) {\n return [bufferedValue, true];\n }\n if (chan.$closed) {\n return [chan.$elem.zero(), false];\n }\n\n var thisGoroutine = $curGoroutine;\n var f = { $blk: function() { return this.value; } };\n var queueEntry = function(v) {\n f.value = v;\n $schedule(thisGoroutine);\n };\n chan.$recvQueue.push(queueEntry);\n $block();\n return f;\n};\nvar $close = function(chan) {\n if (chan.$closed) {\n $throwRuntimeError(\"close of closed channel\");\n }\n chan.$closed = true;\n while (true) {\n var queuedSend = chan.$sendQueue.shift();\n if (queuedSend === undefined) {\n break;\n }\n queuedSend(true); /* will panic */\n }\n while (true) {\n var queuedRecv = chan.$recvQueue.shift();\n if (queuedRecv === undefined) {\n break;\n }\n queuedRecv([chan.$elem.zero(), false]);\n }\n};\nvar $select = function(comms) {\n var ready = [];\n var selection = -1;\n for (var i = 0; i < comms.length; i++) {\n var comm = comms[i];\n var chan = comm[0];\n switch (comm.length) {\n case 0: /* default */\n selection = i;\n break;\n case 1: /* recv */\n if (chan.$sendQueue.length !== 0 || chan.$buffer.length !== 0 || chan.$closed) {\n ready.push(i);\n }\n break;\n case 2: /* send */\n if (chan.$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n if (chan.$recvQueue.length !== 0 || chan.$buffer.length < chan.$capacity) {\n ready.push(i);\n }\n break;\n }\n }\n\n if (ready.length !== 0) {\n selection = ready[Math.floor(Math.random() * ready.length)];\n }\n if (selection !== -1) {\n var comm = comms[selection];\n switch (comm.length) {\n case 0: /* default */\n return [selection];\n case 1: /* recv */\n return [selection, $recv(comm[0])];\n case 2: /* send */\n $send(comm[0], comm[1]);\n return [selection];\n }\n }\n\n var entries = [];\n var thisGoroutine = $curGoroutine;\n var f = { $blk: function() { return this.selection; } };\n var removeFromQueues = function() {\n for (var i = 0; i < entries.length; i++) {\n var entry = entries[i];\n var queue = entry[0];\n var index = queue.indexOf(entry[1]);\n if (index !== -1) {\n queue.splice(index, 1);\n }\n }\n };\n for (var i = 0; i < comms.length; i++) {\n (function(i) {\n var comm = comms[i];\n switch (comm.length) {\n case 1: /* recv */\n var queueEntry = function(value) {\n f.selection = [i, value];\n removeFromQueues();\n $schedule(thisGoroutine);\n };\n entries.push([comm[0].$recvQueue, queueEntry]);\n comm[0].$recvQueue.push(queueEntry);\n break;\n case 2: /* send */\n var queueEntry = function() {\n if (comm[0].$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n f.selection = [i];\n removeFromQueues();\n $schedule(thisGoroutine);\n return comm[1];\n };\n entries.push([comm[0].$sendQueue, queueEntry]);\n comm[0].$sendQueue.push(queueEntry);\n break;\n }\n })(i);\n }\n $block();\n return f;\n};\nvar $jsObjectPtr, $jsErrorPtr;\n\nvar $needsExternalization = function(t) {\n switch (t.kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindFloat32:\n case $kindFloat64:\n return false;\n default:\n return t !== $jsObjectPtr;\n }\n};\n\nvar $externalize = function(v, t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n switch (t.kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindFloat32:\n case $kindFloat64:\n return v;\n case $kindInt64:\n case $kindUint64:\n return $flatten64(v);\n case $kindArray:\n if ($needsExternalization(t.elem)) {\n return $mapArray(v, function(e) { return $externalize(e, t.elem); });\n }\n return v;\n case $kindFunc:\n return $externalizeFunction(v, t, false);\n case $kindInterface:\n if (v === $ifaceNil) {\n return null;\n }\n if (v.constructor === $jsObjectPtr) {\n return v.$val.object;\n }\n return $externalize(v.$val, v.constructor);\n case $kindMap:\n var m = {};\n var keys = $keys(v);\n for (var i = 0; i < keys.length; i++) {\n var entry = v[keys[i]];\n m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem);\n }\n return m;\n case $kindPtr:\n if (v === t.nil) {\n return null;\n }\n return $externalize(v.$get(), t.elem);\n case $kindSlice:\n if ($needsExternalization(t.elem)) {\n return $mapArray($sliceToArray(v), function(e) { return $externalize(e, t.elem); });\n }\n return $sliceToArray(v);\n case $kindString:\n if ($isASCII(v)) {\n return v;\n }\n var s = \"\", r;\n for (var i = 0; i < v.length; i += r[1]) {\n r = $decodeRune(v, i);\n var c = r[0];\n if (c > 0xFFFF) {\n var h = Math.floor((c - 0x10000) / 0x400) + 0xD800;\n var l = (c - 0x10000) % 0x400 + 0xDC00;\n s += String.fromCharCode(h, l);\n continue;\n }\n s += String.fromCharCode(c);\n }\n return s;\n case $kindStruct:\n var timePkg = $packages[\"time\"];\n if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) {\n var milli = $div64(v.UnixNano(), new $Int64(0, 1000000));\n return new Date($flatten64(milli));\n }\n\n var noJsObject = {};\n var searchJsObject = function(v, t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n switch (t.kind) {\n case $kindPtr:\n if (v === t.nil) {\n return noJsObject;\n }\n return searchJsObject(v.$get(), t.elem);\n case $kindStruct:\n var f = t.fields[0];\n return searchJsObject(v[f.prop], f.typ);\n case $kindInterface:\n return searchJsObject(v.$val, v.constructor);\n default:\n return noJsObject;\n }\n };\n var o = searchJsObject(v, t);\n if (o !== noJsObject) {\n return o;\n }\n\n o = {};\n for (var i = 0; i < t.fields.length; i++) {\n var f = t.fields[i];\n if (!f.exported) {\n continue;\n }\n o[f.name] = $externalize(v[f.prop], f.typ);\n }\n return o;\n }\n $throwRuntimeError(\"cannot externalize \" + t.string);\n};\n\nvar $externalizeFunction = function(v, t, passThis) {\n if (v === $throwNilPointerError) {\n return null;\n }\n if (v.$externalizeWrapper === undefined) {\n $checkForDeadlock = false;\n v.$externalizeWrapper = function() {\n var args = [];\n for (var i = 0; i < t.params.length; i++) {\n if (t.variadic && i === t.params.length - 1) {\n var vt = t.params[i].elem, varargs = [];\n for (var j = i; j < arguments.length; j++) {\n varargs.push($internalize(arguments[j], vt));\n }\n args.push(new (t.params[i])(varargs));\n break;\n }\n args.push($internalize(arguments[i], t.params[i]));\n }\n var result = v.apply(passThis ? this : undefined, args);\n switch (t.results.length) {\n case 0:\n return;\n case 1:\n return $externalize(result, t.results[0]);\n default:\n for (var i = 0; i < t.results.length; i++) {\n result[i] = $externalize(result[i], t.results[i]);\n }\n return result;\n }\n };\n }\n return v.$externalizeWrapper;\n};\n\nvar $internalize = function(v, t, recv) {\n if (t === $jsObjectPtr) {\n return v;\n }\n if (t === $jsObjectPtr.elem) {\n $throwRuntimeError(\"cannot internalize js.Object, use *js.Object instead\");\n }\n if (v && v.__internal_object__ !== undefined) {\n return $assertType(v.__internal_object__, t, false);\n }\n var timePkg = $packages[\"time\"];\n if (timePkg !== undefined && t === timePkg.Time) {\n if (!(v !== null && v !== undefined && v.constructor === Date)) {\n $throwRuntimeError(\"cannot internalize time.Time from \" + typeof v + \", must be Date\");\n }\n return timePkg.Unix(new $Int64(0, 0), new $Int64(0, v.getTime() * 1000000));\n }\n switch (t.kind) {\n case $kindBool:\n return !!v;\n case $kindInt:\n return parseInt(v);\n case $kindInt8:\n return parseInt(v) << 24 >> 24;\n case $kindInt16:\n return parseInt(v) << 16 >> 16;\n case $kindInt32:\n return parseInt(v) >> 0;\n case $kindUint:\n return parseInt(v);\n case $kindUint8:\n return parseInt(v) << 24 >>> 24;\n case $kindUint16:\n return parseInt(v) << 16 >>> 16;\n case $kindUint32:\n case $kindUintptr:\n return parseInt(v) >>> 0;\n case $kindInt64:\n case $kindUint64:\n return new t(0, v);\n case $kindFloat32:\n case $kindFloat64:\n return parseFloat(v);\n case $kindArray:\n if (v.length !== t.len) {\n $throwRuntimeError(\"got array with wrong size from JavaScript native\");\n }\n return $mapArray(v, function(e) { return $internalize(e, t.elem); });\n case $kindFunc:\n return function() {\n var args = [];\n for (var i = 0; i < t.params.length; i++) {\n if (t.variadic && i === t.params.length - 1) {\n var vt = t.params[i].elem, varargs = arguments[i];\n for (var j = 0; j < varargs.$length; j++) {\n args.push($externalize(varargs.$array[varargs.$offset + j], vt));\n }\n break;\n }\n args.push($externalize(arguments[i], t.params[i]));\n }\n var result = v.apply(recv, args);\n switch (t.results.length) {\n case 0:\n return;\n case 1:\n return $internalize(result, t.results[0]);\n default:\n for (var i = 0; i < t.results.length; i++) {\n result[i] = $internalize(result[i], t.results[i]);\n }\n return result;\n }\n };\n case $kindInterface:\n if (t.methods.length !== 0) {\n $throwRuntimeError(\"cannot internalize \" + t.string);\n }\n if (v === null) {\n return $ifaceNil;\n }\n if (v === undefined) {\n return new $jsObjectPtr(undefined);\n }\n switch (v.constructor) {\n case Int8Array:\n return new ($sliceType($Int8))(v);\n case Int16Array:\n return new ($sliceType($Int16))(v);\n case Int32Array:\n return new ($sliceType($Int))(v);\n case Uint8Array:\n return new ($sliceType($Uint8))(v);\n case Uint16Array:\n return new ($sliceType($Uint16))(v);\n case Uint32Array:\n return new ($sliceType($Uint))(v);\n case Float32Array:\n return new ($sliceType($Float32))(v);\n case Float64Array:\n return new ($sliceType($Float64))(v);\n case Array:\n return $internalize(v, $sliceType($emptyInterface));\n case Boolean:\n return new $Bool(!!v);\n case Date:\n if (timePkg === undefined) {\n /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */\n return new $jsObjectPtr(v);\n }\n return new timePkg.Time($internalize(v, timePkg.Time));\n case Function:\n var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true);\n return new funcType($internalize(v, funcType));\n case Number:\n return new $Float64(parseFloat(v));\n case String:\n return new $String($internalize(v, $String));\n default:\n if ($global.Node && v instanceof $global.Node) {\n return new $jsObjectPtr(v);\n }\n var mapType = $mapType($String, $emptyInterface);\n return new mapType($internalize(v, mapType));\n }\n case $kindMap:\n var m = {};\n var keys = $keys(v);\n for (var i = 0; i < keys.length; i++) {\n var k = $internalize(keys[i], t.key);\n m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) };\n }\n return m;\n case $kindPtr:\n if (t.elem.kind === $kindStruct) {\n return $internalize(v, t.elem);\n }\n case $kindSlice:\n return new t($mapArray(v, function(e) { return $internalize(e, t.elem); }));\n case $kindString:\n v = String(v);\n if ($isASCII(v)) {\n return v;\n }\n var s = \"\";\n var i = 0;\n while (i < v.length) {\n var h = v.charCodeAt(i);\n if (0xD800 <= h && h <= 0xDBFF) {\n var l = v.charCodeAt(i + 1);\n var c = (h - 0xD800) * 0x400 + l - 0xDC00 + 0x10000;\n s += $encodeRune(c);\n i += 2;\n continue;\n }\n s += $encodeRune(h);\n i++;\n }\n return s;\n case $kindStruct:\n var noJsObject = {};\n var searchJsObject = function(t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n if (t === $jsObjectPtr.elem) {\n $throwRuntimeError(\"cannot internalize js.Object, use *js.Object instead\");\n }\n switch (t.kind) {\n case $kindPtr:\n return searchJsObject(t.elem);\n case $kindStruct:\n var f = t.fields[0];\n var o = searchJsObject(f.typ);\n if (o !== noJsObject) {\n var n = new t.ptr();\n n[f.prop] = o;\n return n;\n }\n return noJsObject;\n default:\n return noJsObject;\n }\n };\n var o = searchJsObject(t);\n if (o !== noJsObject) {\n return o;\n }\n }\n $throwRuntimeError(\"cannot internalize \" + t.string);\n};\n\n/* $isASCII reports whether string s contains only ASCII characters. */\nvar $isASCII = function(s) {\n for (var i = 0; i < s.length; i++) {\n if (s.charCodeAt(i) >= 128) {\n return false;\n }\n }\n return true;\n};\n" diff --git a/compiler/prelude/prelude.js b/compiler/prelude/prelude.js new file mode 100644 index 000000000..58ad4e0d3 --- /dev/null +++ b/compiler/prelude/prelude.js @@ -0,0 +1,414 @@ +Error.stackTraceLimit = Infinity; + +var $global, $module; +if (typeof window !== "undefined") { /* web page */ + $global = window; +} else if (typeof self !== "undefined") { /* web worker */ + $global = self; +} else if (typeof global !== "undefined") { /* Node.js */ + $global = global; + $global.require = require; +} else { /* others (e.g. Nashorn) */ + $global = this; +} + +if ($global === undefined || $global.Array === undefined) { + throw new Error("no global object found"); +} +if (typeof module !== "undefined") { + $module = module; +} + +var $packages = {}, $idCounter = 0; +var $keys = function(m) { return m ? Object.keys(m) : []; }; +var $flushConsole = function() {}; +var $throwRuntimeError; /* set by package "runtime" */ +var $throwNilPointerError = function() { $throwRuntimeError("invalid memory address or nil pointer dereference"); }; +var $call = function(fn, rcvr, args) { return fn.apply(rcvr, args); }; +var $makeFunc = function(fn) { return function() { return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface); }; }; +var $unused = function(v) {}; + +var $mapArray = function(array, f) { + var newArray = new array.constructor(array.length); + for (var i = 0; i < array.length; i++) { + newArray[i] = f(array[i]); + } + return newArray; +}; + +var $methodVal = function(recv, name) { + var vals = recv.$methodVals || {}; + recv.$methodVals = vals; /* noop for primitives */ + var f = vals[name]; + if (f !== undefined) { + return f; + } + var method = recv[name]; + f = function() { + $stackDepthOffset--; + try { + return method.apply(recv, arguments); + } finally { + $stackDepthOffset++; + } + }; + vals[name] = f; + return f; +}; + +var $methodExpr = function(typ, name) { + var method = typ.prototype[name]; + if (method.$expr === undefined) { + method.$expr = function() { + $stackDepthOffset--; + try { + if (typ.wrapped) { + arguments[0] = new typ(arguments[0]); + } + return Function.call.apply(method, arguments); + } finally { + $stackDepthOffset++; + } + }; + } + return method.$expr; +}; + +var $ifaceMethodExprs = {}; +var $ifaceMethodExpr = function(name) { + var expr = $ifaceMethodExprs["$" + name]; + if (expr === undefined) { + expr = $ifaceMethodExprs["$" + name] = function() { + $stackDepthOffset--; + try { + return Function.call.apply(arguments[0][name], arguments); + } finally { + $stackDepthOffset++; + } + }; + } + return expr; +}; + +var $subslice = function(slice, low, high, max) { + if (high === undefined) { + high = slice.$length; + } + if (max === undefined) { + max = slice.$capacity; + } + if (low < 0 || high < low || max < high || high > slice.$capacity || max > slice.$capacity) { + $throwRuntimeError("slice bounds out of range"); + } + var s = new slice.constructor(slice.$array); + s.$offset = slice.$offset + low; + s.$length = high - low; + s.$capacity = max - low; + return s; +}; + +var $substring = function(str, low, high) { + if (low < 0 || high < low || high > str.length) { + $throwRuntimeError("slice bounds out of range"); + } + return str.substring(low, high); +}; + +var $sliceToArray = function(slice) { + if (slice.$array.constructor !== Array) { + return slice.$array.subarray(slice.$offset, slice.$offset + slice.$length); + } + return slice.$array.slice(slice.$offset, slice.$offset + slice.$length); +}; + +var $decodeRune = function(str, pos) { + var c0 = str.charCodeAt(pos); + + if (c0 < 0x80) { + return [c0, 1]; + } + + if (c0 !== c0 || c0 < 0xC0) { + return [0xFFFD, 1]; + } + + var c1 = str.charCodeAt(pos + 1); + if (c1 !== c1 || c1 < 0x80 || 0xC0 <= c1) { + return [0xFFFD, 1]; + } + + if (c0 < 0xE0) { + var r = (c0 & 0x1F) << 6 | (c1 & 0x3F); + if (r <= 0x7F) { + return [0xFFFD, 1]; + } + return [r, 2]; + } + + var c2 = str.charCodeAt(pos + 2); + if (c2 !== c2 || c2 < 0x80 || 0xC0 <= c2) { + return [0xFFFD, 1]; + } + + if (c0 < 0xF0) { + var r = (c0 & 0x0F) << 12 | (c1 & 0x3F) << 6 | (c2 & 0x3F); + if (r <= 0x7FF) { + return [0xFFFD, 1]; + } + if (0xD800 <= r && r <= 0xDFFF) { + return [0xFFFD, 1]; + } + return [r, 3]; + } + + var c3 = str.charCodeAt(pos + 3); + if (c3 !== c3 || c3 < 0x80 || 0xC0 <= c3) { + return [0xFFFD, 1]; + } + + if (c0 < 0xF8) { + var r = (c0 & 0x07) << 18 | (c1 & 0x3F) << 12 | (c2 & 0x3F) << 6 | (c3 & 0x3F); + if (r <= 0xFFFF || 0x10FFFF < r) { + return [0xFFFD, 1]; + } + return [r, 4]; + } + + return [0xFFFD, 1]; +}; + +var $encodeRune = function(r) { + if (r < 0 || r > 0x10FFFF || (0xD800 <= r && r <= 0xDFFF)) { + r = 0xFFFD; + } + if (r <= 0x7F) { + return String.fromCharCode(r); + } + if (r <= 0x7FF) { + return String.fromCharCode(0xC0 | r >> 6, 0x80 | (r & 0x3F)); + } + if (r <= 0xFFFF) { + return String.fromCharCode(0xE0 | r >> 12, 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F)); + } + return String.fromCharCode(0xF0 | r >> 18, 0x80 | (r >> 12 & 0x3F), 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F)); +}; + +var $stringToBytes = function(str) { + var array = new Uint8Array(str.length); + for (var i = 0; i < str.length; i++) { + array[i] = str.charCodeAt(i); + } + return array; +}; + +var $bytesToString = function(slice) { + if (slice.$length === 0) { + return ""; + } + var str = ""; + for (var i = 0; i < slice.$length; i += 10000) { + str += String.fromCharCode.apply(undefined, slice.$array.subarray(slice.$offset + i, slice.$offset + Math.min(slice.$length, i + 10000))); + } + return str; +}; + +var $stringToRunes = function(str) { + var array = new Int32Array(str.length); + var rune, j = 0; + for (var i = 0; i < str.length; i += rune[1], j++) { + rune = $decodeRune(str, i); + array[j] = rune[0]; + } + return array.subarray(0, j); +}; + +var $runesToString = function(slice) { + if (slice.$length === 0) { + return ""; + } + var str = ""; + for (var i = 0; i < slice.$length; i++) { + str += $encodeRune(slice.$array[slice.$offset + i]); + } + return str; +}; + +var $copyString = function(dst, src) { + var n = Math.min(src.length, dst.$length); + for (var i = 0; i < n; i++) { + dst.$array[dst.$offset + i] = src.charCodeAt(i); + } + return n; +}; + +var $copySlice = function(dst, src) { + var n = Math.min(src.$length, dst.$length); + $copyArray(dst.$array, src.$array, dst.$offset, src.$offset, n, dst.constructor.elem); + return n; +}; + +var $copyArray = function(dst, src, dstOffset, srcOffset, n, elem) { + if (n === 0 || (dst === src && dstOffset === srcOffset)) { + return; + } + + if (src.subarray) { + dst.set(src.subarray(srcOffset, srcOffset + n), dstOffset); + return; + } + + switch (elem.kind) { + case $kindArray: + case $kindStruct: + if (dst === src && dstOffset > srcOffset) { + for (var i = n - 1; i >= 0; i--) { + elem.copy(dst[dstOffset + i], src[srcOffset + i]); + } + return; + } + for (var i = 0; i < n; i++) { + elem.copy(dst[dstOffset + i], src[srcOffset + i]); + } + return; + } + + if (dst === src && dstOffset > srcOffset) { + for (var i = n - 1; i >= 0; i--) { + dst[dstOffset + i] = src[srcOffset + i]; + } + return; + } + for (var i = 0; i < n; i++) { + dst[dstOffset + i] = src[srcOffset + i]; + } +}; + +var $clone = function(src, type) { + var clone = type.zero(); + type.copy(clone, src); + return clone; +}; + +var $pointerOfStructConversion = function(obj, type) { + if(obj.$proxies === undefined) { + obj.$proxies = {}; + obj.$proxies[obj.constructor.string] = obj; + } + var proxy = obj.$proxies[type.string]; + if (proxy === undefined) { + var properties = {}; + for (var i = 0; i < type.elem.fields.length; i++) { + (function(fieldProp) { + properties[fieldProp] = { + get: function() { return obj[fieldProp]; }, + set: function(value) { obj[fieldProp] = value; } + }; + })(type.elem.fields[i].prop); + } + proxy = Object.create(type.prototype, properties); + proxy.$val = proxy; + obj.$proxies[type.string] = proxy; + proxy.$proxies = obj.$proxies; + } + return proxy; +}; + +var $append = function(slice) { + return $internalAppend(slice, arguments, 1, arguments.length - 1); +}; + +var $appendSlice = function(slice, toAppend) { + if (toAppend.constructor === String) { + var bytes = $stringToBytes(toAppend); + return $internalAppend(slice, bytes, 0, bytes.length); + } + return $internalAppend(slice, toAppend.$array, toAppend.$offset, toAppend.$length); +}; + +var $internalAppend = function(slice, array, offset, length) { + if (length === 0) { + return slice; + } + + var newArray = slice.$array; + var newOffset = slice.$offset; + var newLength = slice.$length + length; + var newCapacity = slice.$capacity; + + if (newLength > newCapacity) { + newOffset = 0; + newCapacity = Math.max(newLength, slice.$capacity < 1024 ? slice.$capacity * 2 : Math.floor(slice.$capacity * 5 / 4)); + + if (slice.$array.constructor === Array) { + newArray = slice.$array.slice(slice.$offset, slice.$offset + slice.$length); + newArray.length = newCapacity; + var zero = slice.constructor.elem.zero; + for (var i = slice.$length; i < newCapacity; i++) { + newArray[i] = zero(); + } + } else { + newArray = new slice.$array.constructor(newCapacity); + newArray.set(slice.$array.subarray(slice.$offset, slice.$offset + slice.$length)); + } + } + + $copyArray(newArray, array, newOffset + slice.$length, offset, length, slice.constructor.elem); + + var newSlice = new slice.constructor(newArray); + newSlice.$offset = newOffset; + newSlice.$length = newLength; + newSlice.$capacity = newCapacity; + return newSlice; +}; + +var $equal = function(a, b, type) { + if (type === $jsObjectPtr) { + return a === b; + } + switch (type.kind) { + case $kindComplex64: + case $kindComplex128: + return a.$real === b.$real && a.$imag === b.$imag; + case $kindInt64: + case $kindUint64: + return a.$high === b.$high && a.$low === b.$low; + case $kindArray: + if (a.length !== b.length) { + return false; + } + for (var i = 0; i < a.length; i++) { + if (!$equal(a[i], b[i], type.elem)) { + return false; + } + } + return true; + case $kindStruct: + for (var i = 0; i < type.fields.length; i++) { + var f = type.fields[i]; + if (!$equal(a[f.prop], b[f.prop], f.typ)) { + return false; + } + } + return true; + case $kindInterface: + return $interfaceIsEqual(a, b); + default: + return a === b; + } +}; + +var $interfaceIsEqual = function(a, b) { + if (a === $ifaceNil || b === $ifaceNil) { + return a === b; + } + if (a.constructor !== b.constructor) { + return false; + } + if (a.constructor === $jsObjectPtr) { + return a.object === b.object; + } + if (!a.constructor.comparable) { + $throwRuntimeError("comparing uncomparable type " + a.constructor.string); + } + return $equal(a.$val, b.$val, a.constructor); +}; diff --git a/compiler/prelude/prelude_min.go b/compiler/prelude/prelude_min.go index ed6fb09ba..5a14f94da 100644 --- a/compiler/prelude/prelude_min.go +++ b/compiler/prelude/prelude_min.go @@ -1,4 +1,4 @@ -// Code generated by genmin; DO NOT EDIT. +// Code generated by genprelude; DO NOT EDIT. package prelude diff --git a/compiler/prelude/types.go b/compiler/prelude/types.js similarity index 99% rename from compiler/prelude/types.go rename to compiler/prelude/types.js index a8c29d575..e645ab3f5 100644 --- a/compiler/prelude/types.go +++ b/compiler/prelude/types.js @@ -1,6 +1,3 @@ -package prelude - -const types = ` var $kindBool = 1; var $kindInt = 2; var $kindInt8 = 3; @@ -740,4 +737,3 @@ var $assertType = function(value, type, returnTuple) { } return returnTuple ? [value, true] : value; }; -` From bae527eb3d3cd441c1ac9f7085e32f8d06450b9a Mon Sep 17 00:00:00 2001 From: Paul Jolly Date: Sun, 15 Apr 2018 12:19:45 +0100 Subject: [PATCH 2/2] compiler/prelude: format .js files using prettier This PR introduces automatic formatting of the prelude's now separate .js files. Using prettier has the same argument as using gofmt on .go source code. As part of this we make the go generate step for the prelude include a formatpreludejs.go step. The resulting prelude_min.go file is slightly different now, but post https://github.com/gopherjs/gopherjs/pull/791 we can see these differences are entirely and solely attributable to prettier's adjusting of the .js files. --- compiler/prelude/formatpreludejs.go | 56 ++ compiler/prelude/generate.go | 1 + compiler/prelude/goroutines.js | 130 ++-- compiler/prelude/jsmapping.js | 549 +++++++-------- compiler/prelude/numeric.js | 61 +- compiler/prelude/prelude.go | 2 +- compiler/prelude/prelude.js | 176 ++--- compiler/prelude/prettier_options.json | 4 + compiler/prelude/types.js | 887 ++++++++++++++----------- package-lock.json | 6 + package.json | 3 +- 11 files changed, 1066 insertions(+), 809 deletions(-) create mode 100644 compiler/prelude/formatpreludejs.go create mode 100644 compiler/prelude/prettier_options.json diff --git a/compiler/prelude/formatpreludejs.go b/compiler/prelude/formatpreludejs.go new file mode 100644 index 000000000..76b8484af --- /dev/null +++ b/compiler/prelude/formatpreludejs.go @@ -0,0 +1,56 @@ +// +build ignore + +package main + +import ( + "fmt" + "go/build" + "io/ioutil" + "log" + "os/exec" + "path/filepath" + "strings" +) + +func main() { + if err := run(); err != nil { + log.Fatalln(err) + } +} + +func run() error { + bpkg, err := build.Import("github.com/gopherjs/gopherjs", "", build.FindOnly) + if err != nil { + return fmt.Errorf("failed to locate path for github.com/gopherjs/gopherjs/compiler/prelude: %v", err) + } + + preludeDir := filepath.Join(bpkg.Dir, "compiler", "prelude") + + args := []string{ + filepath.Join(bpkg.Dir, "node_modules", ".bin", "prettier"), + "--config", + filepath.Join(preludeDir, "prettier_options.json"), + "--write", + } + + fis, err := ioutil.ReadDir(preludeDir) + if err != nil { + return fmt.Errorf("failed to list contents of %v: %v", preludeDir, err) + } + for _, fi := range fis { + fn := fi.Name() + if !strings.HasSuffix(fn, ".js") || strings.HasSuffix(fn, ".min.js") { + continue + } + args = append(args, fn) + } + + cmd := exec.Command(args[0], args[1:]...) + + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to run %v: %v\n%s", strings.Join(args, " "), err, string(out)) + } + + return nil +} diff --git a/compiler/prelude/generate.go b/compiler/prelude/generate.go index bc4b2cea7..d320fd3bf 100644 --- a/compiler/prelude/generate.go +++ b/compiler/prelude/generate.go @@ -1,3 +1,4 @@ package prelude +//go:generate go run formatpreludejs.go //go:generate go run genprelude.go diff --git a/compiler/prelude/goroutines.js b/compiler/prelude/goroutines.js index f1ae2d37e..06c51b8f6 100644 --- a/compiler/prelude/goroutines.js +++ b/compiler/prelude/goroutines.js @@ -7,7 +7,8 @@ var $getStackDepth = function() { return $stackDepthOffset + err.stack.split("\n").length; }; -var $panicStackDepth = null, $panicValue; +var $panicStackDepth = null, + $panicValue; var $callDeferred = function(deferred, jsErr, fromPanic) { if (!fromPanic && deferred !== null && deferred.index >= $curGoroutine.deferStack.length) { throw jsErr; @@ -106,10 +107,20 @@ var $recover = function() { $panicStackDepth = null; return $panicValue; }; -var $throw = function(err) { throw err; }; +var $throw = function(err) { + throw err; +}; -var $noGoroutine = { asleep: false, exit: false, deferStack: [], panicStack: [] }; -var $curGoroutine = $noGoroutine, $totalGoroutines = 0, $awakeGoroutines = 0, $checkForDeadlock = true; +var $noGoroutine = { + asleep: false, + exit: false, + deferStack: [], + panicStack: [], +}; +var $curGoroutine = $noGoroutine, + $totalGoroutines = 0, + $awakeGoroutines = 0, + $checkForDeadlock = true; var $mainFinished = false; var $go = function(fun, args) { $totalGoroutines++; @@ -119,7 +130,9 @@ var $go = function(fun, args) { $curGoroutine = $goroutine; var r = fun.apply(undefined, args); if (r && r.$blk !== undefined) { - fun = function() { return r.$blk(); }; + fun = function() { + return r.$blk(); + }; args = []; return; } @@ -130,7 +143,8 @@ var $go = function(fun, args) { } } finally { $curGoroutine = $noGoroutine; - if ($goroutine.exit) { /* also set by runtime.Goexit() */ + if ($goroutine.exit) { + /* also set by runtime.Goexit() */ $totalGoroutines--; $goroutine.asleep = true; } @@ -219,7 +233,7 @@ var $send = function(chan, value) { if (closedDuringSend) { $throwRuntimeError("send on closed channel"); } - } + }, }; }; var $recv = function(chan) { @@ -236,7 +250,11 @@ var $recv = function(chan) { } var thisGoroutine = $curGoroutine; - var f = { $blk: function() { return this.value; } }; + var f = { + $blk: function() { + return this.value; + }, + }; var queueEntry = function(v) { f.value = v; $schedule(thisGoroutine); @@ -272,22 +290,22 @@ var $select = function(comms) { var comm = comms[i]; var chan = comm[0]; switch (comm.length) { - case 0: /* default */ - selection = i; - break; - case 1: /* recv */ - if (chan.$sendQueue.length !== 0 || chan.$buffer.length !== 0 || chan.$closed) { - ready.push(i); - } - break; - case 2: /* send */ - if (chan.$closed) { - $throwRuntimeError("send on closed channel"); - } - if (chan.$recvQueue.length !== 0 || chan.$buffer.length < chan.$capacity) { - ready.push(i); - } - break; + case 0 /* default */: + selection = i; + break; + case 1 /* recv */: + if (chan.$sendQueue.length !== 0 || chan.$buffer.length !== 0 || chan.$closed) { + ready.push(i); + } + break; + case 2 /* send */: + if (chan.$closed) { + $throwRuntimeError("send on closed channel"); + } + if (chan.$recvQueue.length !== 0 || chan.$buffer.length < chan.$capacity) { + ready.push(i); + } + break; } } @@ -297,19 +315,23 @@ var $select = function(comms) { if (selection !== -1) { var comm = comms[selection]; switch (comm.length) { - case 0: /* default */ - return [selection]; - case 1: /* recv */ - return [selection, $recv(comm[0])]; - case 2: /* send */ - $send(comm[0], comm[1]); - return [selection]; + case 0 /* default */: + return [selection]; + case 1 /* recv */: + return [selection, $recv(comm[0])]; + case 2 /* send */: + $send(comm[0], comm[1]); + return [selection]; } } var entries = []; var thisGoroutine = $curGoroutine; - var f = { $blk: function() { return this.selection; } }; + var f = { + $blk: function() { + return this.selection; + }, + }; var removeFromQueues = function() { for (var i = 0; i < entries.length; i++) { var entry = entries[i]; @@ -324,28 +346,28 @@ var $select = function(comms) { (function(i) { var comm = comms[i]; switch (comm.length) { - case 1: /* recv */ - var queueEntry = function(value) { - f.selection = [i, value]; - removeFromQueues(); - $schedule(thisGoroutine); - }; - entries.push([comm[0].$recvQueue, queueEntry]); - comm[0].$recvQueue.push(queueEntry); - break; - case 2: /* send */ - var queueEntry = function() { - if (comm[0].$closed) { - $throwRuntimeError("send on closed channel"); - } - f.selection = [i]; - removeFromQueues(); - $schedule(thisGoroutine); - return comm[1]; - }; - entries.push([comm[0].$sendQueue, queueEntry]); - comm[0].$sendQueue.push(queueEntry); - break; + case 1 /* recv */: + var queueEntry = function(value) { + f.selection = [i, value]; + removeFromQueues(); + $schedule(thisGoroutine); + }; + entries.push([comm[0].$recvQueue, queueEntry]); + comm[0].$recvQueue.push(queueEntry); + break; + case 2 /* send */: + var queueEntry = function() { + if (comm[0].$closed) { + $throwRuntimeError("send on closed channel"); + } + f.selection = [i]; + removeFromQueues(); + $schedule(thisGoroutine); + return comm[1]; + }; + entries.push([comm[0].$sendQueue, queueEntry]); + comm[0].$sendQueue.push(queueEntry); + break; } })(i); } diff --git a/compiler/prelude/jsmapping.js b/compiler/prelude/jsmapping.js index 44a2a96a4..0a16a8250 100644 --- a/compiler/prelude/jsmapping.js +++ b/compiler/prelude/jsmapping.js @@ -25,113 +25,118 @@ var $externalize = function(v, t) { return v; } switch (t.kind) { - case $kindBool: - case $kindInt: - case $kindInt8: - case $kindInt16: - case $kindInt32: - case $kindUint: - case $kindUint8: - case $kindUint16: - case $kindUint32: - case $kindUintptr: - case $kindFloat32: - case $kindFloat64: - return v; - case $kindInt64: - case $kindUint64: - return $flatten64(v); - case $kindArray: - if ($needsExternalization(t.elem)) { - return $mapArray(v, function(e) { return $externalize(e, t.elem); }); - } - return v; - case $kindFunc: - return $externalizeFunction(v, t, false); - case $kindInterface: - if (v === $ifaceNil) { - return null; - } - if (v.constructor === $jsObjectPtr) { - return v.$val.object; - } - return $externalize(v.$val, v.constructor); - case $kindMap: - var m = {}; - var keys = $keys(v); - for (var i = 0; i < keys.length; i++) { - var entry = v[keys[i]]; - m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem); - } - return m; - case $kindPtr: - if (v === t.nil) { - return null; - } - return $externalize(v.$get(), t.elem); - case $kindSlice: - if ($needsExternalization(t.elem)) { - return $mapArray($sliceToArray(v), function(e) { return $externalize(e, t.elem); }); - } - return $sliceToArray(v); - case $kindString: - if ($isASCII(v)) { + case $kindBool: + case $kindInt: + case $kindInt8: + case $kindInt16: + case $kindInt32: + case $kindUint: + case $kindUint8: + case $kindUint16: + case $kindUint32: + case $kindUintptr: + case $kindFloat32: + case $kindFloat64: return v; - } - var s = "", r; - for (var i = 0; i < v.length; i += r[1]) { - r = $decodeRune(v, i); - var c = r[0]; - if (c > 0xFFFF) { - var h = Math.floor((c - 0x10000) / 0x400) + 0xD800; - var l = (c - 0x10000) % 0x400 + 0xDC00; - s += String.fromCharCode(h, l); - continue; + case $kindInt64: + case $kindUint64: + return $flatten64(v); + case $kindArray: + if ($needsExternalization(t.elem)) { + return $mapArray(v, function(e) { + return $externalize(e, t.elem); + }); } - s += String.fromCharCode(c); - } - return s; - case $kindStruct: - var timePkg = $packages["time"]; - if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) { - var milli = $div64(v.UnixNano(), new $Int64(0, 1000000)); - return new Date($flatten64(milli)); - } - - var noJsObject = {}; - var searchJsObject = function(v, t) { - if (t === $jsObjectPtr) { + return v; + case $kindFunc: + return $externalizeFunction(v, t, false); + case $kindInterface: + if (v === $ifaceNil) { + return null; + } + if (v.constructor === $jsObjectPtr) { + return v.$val.object; + } + return $externalize(v.$val, v.constructor); + case $kindMap: + var m = {}; + var keys = $keys(v); + for (var i = 0; i < keys.length; i++) { + var entry = v[keys[i]]; + m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem); + } + return m; + case $kindPtr: + if (v === t.nil) { + return null; + } + return $externalize(v.$get(), t.elem); + case $kindSlice: + if ($needsExternalization(t.elem)) { + return $mapArray($sliceToArray(v), function(e) { + return $externalize(e, t.elem); + }); + } + return $sliceToArray(v); + case $kindString: + if ($isASCII(v)) { return v; } - switch (t.kind) { - case $kindPtr: - if (v === t.nil) { - return noJsObject; + var s = "", + r; + for (var i = 0; i < v.length; i += r[1]) { + r = $decodeRune(v, i); + var c = r[0]; + if (c > 0xffff) { + var h = Math.floor((c - 0x10000) / 0x400) + 0xd800; + var l = (c - 0x10000) % 0x400 + 0xdc00; + s += String.fromCharCode(h, l); + continue; } - return searchJsObject(v.$get(), t.elem); - case $kindStruct: - var f = t.fields[0]; - return searchJsObject(v[f.prop], f.typ); - case $kindInterface: - return searchJsObject(v.$val, v.constructor); - default: - return noJsObject; + s += String.fromCharCode(c); + } + return s; + case $kindStruct: + var timePkg = $packages["time"]; + if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) { + var milli = $div64(v.UnixNano(), new $Int64(0, 1000000)); + return new Date($flatten64(milli)); } - }; - var o = searchJsObject(v, t); - if (o !== noJsObject) { - return o; - } - o = {}; - for (var i = 0; i < t.fields.length; i++) { - var f = t.fields[i]; - if (!f.exported) { - continue; + var noJsObject = {}; + var searchJsObject = function(v, t) { + if (t === $jsObjectPtr) { + return v; + } + switch (t.kind) { + case $kindPtr: + if (v === t.nil) { + return noJsObject; + } + return searchJsObject(v.$get(), t.elem); + case $kindStruct: + var f = t.fields[0]; + return searchJsObject(v[f.prop], f.typ); + case $kindInterface: + return searchJsObject(v.$val, v.constructor); + default: + return noJsObject; + } + }; + var o = searchJsObject(v, t); + if (o !== noJsObject) { + return o; } - o[f.name] = $externalize(v[f.prop], f.typ); - } - return o; + + o = {}; + for (var i = 0; i < t.fields.length; i++) { + var f = t.fields[i]; + if (!f.exported) { + continue; + } + o[f.name] = $externalize(v[f.prop], f.typ); + } + return o; } $throwRuntimeError("cannot externalize " + t.string); }; @@ -146,26 +151,27 @@ var $externalizeFunction = function(v, t, passThis) { var args = []; for (var i = 0; i < t.params.length; i++) { if (t.variadic && i === t.params.length - 1) { - var vt = t.params[i].elem, varargs = []; + var vt = t.params[i].elem, + varargs = []; for (var j = i; j < arguments.length; j++) { varargs.push($internalize(arguments[j], vt)); } - args.push(new (t.params[i])(varargs)); + args.push(new t.params[i](varargs)); break; } args.push($internalize(arguments[i], t.params[i])); } var result = v.apply(passThis ? this : undefined, args); switch (t.results.length) { - case 0: - return; - case 1: - return $externalize(result, t.results[0]); - default: - for (var i = 0; i < t.results.length; i++) { - result[i] = $externalize(result[i], t.results[i]); - } - return result; + case 0: + return; + case 1: + return $externalize(result, t.results[0]); + default: + for (var i = 0; i < t.results.length; i++) { + result[i] = $externalize(result[i], t.results[i]); + } + return result; } }; } @@ -190,176 +196,183 @@ var $internalize = function(v, t, recv) { return timePkg.Unix(new $Int64(0, 0), new $Int64(0, v.getTime() * 1000000)); } switch (t.kind) { - case $kindBool: - return !!v; - case $kindInt: - return parseInt(v); - case $kindInt8: - return parseInt(v) << 24 >> 24; - case $kindInt16: - return parseInt(v) << 16 >> 16; - case $kindInt32: - return parseInt(v) >> 0; - case $kindUint: - return parseInt(v); - case $kindUint8: - return parseInt(v) << 24 >>> 24; - case $kindUint16: - return parseInt(v) << 16 >>> 16; - case $kindUint32: - case $kindUintptr: - return parseInt(v) >>> 0; - case $kindInt64: - case $kindUint64: - return new t(0, v); - case $kindFloat32: - case $kindFloat64: - return parseFloat(v); - case $kindArray: - if (v.length !== t.len) { - $throwRuntimeError("got array with wrong size from JavaScript native"); - } - return $mapArray(v, function(e) { return $internalize(e, t.elem); }); - case $kindFunc: - return function() { - var args = []; - for (var i = 0; i < t.params.length; i++) { - if (t.variadic && i === t.params.length - 1) { - var vt = t.params[i].elem, varargs = arguments[i]; - for (var j = 0; j < varargs.$length; j++) { - args.push($externalize(varargs.$array[varargs.$offset + j], vt)); + case $kindBool: + return !!v; + case $kindInt: + return parseInt(v); + case $kindInt8: + return (parseInt(v) << 24) >> 24; + case $kindInt16: + return (parseInt(v) << 16) >> 16; + case $kindInt32: + return parseInt(v) >> 0; + case $kindUint: + return parseInt(v); + case $kindUint8: + return (parseInt(v) << 24) >>> 24; + case $kindUint16: + return (parseInt(v) << 16) >>> 16; + case $kindUint32: + case $kindUintptr: + return parseInt(v) >>> 0; + case $kindInt64: + case $kindUint64: + return new t(0, v); + case $kindFloat32: + case $kindFloat64: + return parseFloat(v); + case $kindArray: + if (v.length !== t.len) { + $throwRuntimeError("got array with wrong size from JavaScript native"); + } + return $mapArray(v, function(e) { + return $internalize(e, t.elem); + }); + case $kindFunc: + return function() { + var args = []; + for (var i = 0; i < t.params.length; i++) { + if (t.variadic && i === t.params.length - 1) { + var vt = t.params[i].elem, + varargs = arguments[i]; + for (var j = 0; j < varargs.$length; j++) { + args.push($externalize(varargs.$array[varargs.$offset + j], vt)); + } + break; } - break; + args.push($externalize(arguments[i], t.params[i])); } - args.push($externalize(arguments[i], t.params[i])); - } - var result = v.apply(recv, args); - switch (t.results.length) { - case 0: - return; - case 1: - return $internalize(result, t.results[0]); - default: - for (var i = 0; i < t.results.length; i++) { - result[i] = $internalize(result[i], t.results[i]); + var result = v.apply(recv, args); + switch (t.results.length) { + case 0: + return; + case 1: + return $internalize(result, t.results[0]); + default: + for (var i = 0; i < t.results.length; i++) { + result[i] = $internalize(result[i], t.results[i]); + } + return result; } - return result; + }; + case $kindInterface: + if (t.methods.length !== 0) { + $throwRuntimeError("cannot internalize " + t.string); } - }; - case $kindInterface: - if (t.methods.length !== 0) { - $throwRuntimeError("cannot internalize " + t.string); - } - if (v === null) { - return $ifaceNil; - } - if (v === undefined) { - return new $jsObjectPtr(undefined); - } - switch (v.constructor) { - case Int8Array: - return new ($sliceType($Int8))(v); - case Int16Array: - return new ($sliceType($Int16))(v); - case Int32Array: - return new ($sliceType($Int))(v); - case Uint8Array: - return new ($sliceType($Uint8))(v); - case Uint16Array: - return new ($sliceType($Uint16))(v); - case Uint32Array: - return new ($sliceType($Uint))(v); - case Float32Array: - return new ($sliceType($Float32))(v); - case Float64Array: - return new ($sliceType($Float64))(v); - case Array: - return $internalize(v, $sliceType($emptyInterface)); - case Boolean: - return new $Bool(!!v); - case Date: - if (timePkg === undefined) { - /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */ - return new $jsObjectPtr(v); + if (v === null) { + return $ifaceNil; } - return new timePkg.Time($internalize(v, timePkg.Time)); - case Function: - var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true); - return new funcType($internalize(v, funcType)); - case Number: - return new $Float64(parseFloat(v)); - case String: - return new $String($internalize(v, $String)); - default: - if ($global.Node && v instanceof $global.Node) { - return new $jsObjectPtr(v); + if (v === undefined) { + return new $jsObjectPtr(undefined); } - var mapType = $mapType($String, $emptyInterface); - return new mapType($internalize(v, mapType)); - } - case $kindMap: - var m = {}; - var keys = $keys(v); - for (var i = 0; i < keys.length; i++) { - var k = $internalize(keys[i], t.key); - m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) }; - } - return m; - case $kindPtr: - if (t.elem.kind === $kindStruct) { - return $internalize(v, t.elem); - } - case $kindSlice: - return new t($mapArray(v, function(e) { return $internalize(e, t.elem); })); - case $kindString: - v = String(v); - if ($isASCII(v)) { - return v; - } - var s = ""; - var i = 0; - while (i < v.length) { - var h = v.charCodeAt(i); - if (0xD800 <= h && h <= 0xDBFF) { - var l = v.charCodeAt(i + 1); - var c = (h - 0xD800) * 0x400 + l - 0xDC00 + 0x10000; - s += $encodeRune(c); - i += 2; - continue; + switch (v.constructor) { + case Int8Array: + return new ($sliceType($Int8))(v); + case Int16Array: + return new ($sliceType($Int16))(v); + case Int32Array: + return new ($sliceType($Int))(v); + case Uint8Array: + return new ($sliceType($Uint8))(v); + case Uint16Array: + return new ($sliceType($Uint16))(v); + case Uint32Array: + return new ($sliceType($Uint))(v); + case Float32Array: + return new ($sliceType($Float32))(v); + case Float64Array: + return new ($sliceType($Float64))(v); + case Array: + return $internalize(v, $sliceType($emptyInterface)); + case Boolean: + return new $Bool(!!v); + case Date: + if (timePkg === undefined) { + /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */ + return new $jsObjectPtr(v); + } + return new timePkg.Time($internalize(v, timePkg.Time)); + case Function: + var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true); + return new funcType($internalize(v, funcType)); + case Number: + return new $Float64(parseFloat(v)); + case String: + return new $String($internalize(v, $String)); + default: + if ($global.Node && v instanceof $global.Node) { + return new $jsObjectPtr(v); + } + var mapType = $mapType($String, $emptyInterface); + return new mapType($internalize(v, mapType)); } - s += $encodeRune(h); - i++; - } - return s; - case $kindStruct: - var noJsObject = {}; - var searchJsObject = function(t) { - if (t === $jsObjectPtr) { + case $kindMap: + var m = {}; + var keys = $keys(v); + for (var i = 0; i < keys.length; i++) { + var k = $internalize(keys[i], t.key); + m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) }; + } + return m; + case $kindPtr: + if (t.elem.kind === $kindStruct) { + return $internalize(v, t.elem); + } + case $kindSlice: + return new t( + $mapArray(v, function(e) { + return $internalize(e, t.elem); + }) + ); + case $kindString: + v = String(v); + if ($isASCII(v)) { return v; } - if (t === $jsObjectPtr.elem) { - $throwRuntimeError("cannot internalize js.Object, use *js.Object instead"); + var s = ""; + var i = 0; + while (i < v.length) { + var h = v.charCodeAt(i); + if (0xd800 <= h && h <= 0xdbff) { + var l = v.charCodeAt(i + 1); + var c = (h - 0xd800) * 0x400 + l - 0xdc00 + 0x10000; + s += $encodeRune(c); + i += 2; + continue; + } + s += $encodeRune(h); + i++; } - switch (t.kind) { - case $kindPtr: - return searchJsObject(t.elem); - case $kindStruct: - var f = t.fields[0]; - var o = searchJsObject(f.typ); - if (o !== noJsObject) { - var n = new t.ptr(); - n[f.prop] = o; - return n; + return s; + case $kindStruct: + var noJsObject = {}; + var searchJsObject = function(t) { + if (t === $jsObjectPtr) { + return v; } - return noJsObject; - default: - return noJsObject; + if (t === $jsObjectPtr.elem) { + $throwRuntimeError("cannot internalize js.Object, use *js.Object instead"); + } + switch (t.kind) { + case $kindPtr: + return searchJsObject(t.elem); + case $kindStruct: + var f = t.fields[0]; + var o = searchJsObject(f.typ); + if (o !== noJsObject) { + var n = new t.ptr(); + n[f.prop] = o; + return n; + } + return noJsObject; + default: + return noJsObject; + } + }; + var o = searchJsObject(t); + if (o !== noJsObject) { + return o; } - }; - var o = searchJsObject(t); - if (o !== noJsObject) { - return o; - } } $throwRuntimeError("cannot internalize " + t.string); }; diff --git a/compiler/prelude/numeric.js b/compiler/prelude/numeric.js index 3064e33ab..3d40deec0 100644 --- a/compiler/prelude/numeric.js +++ b/compiler/prelude/numeric.js @@ -1,5 +1,7 @@ var $min = Math.min; -var $mod = function(x, y) { return x % y; }; +var $mod = function(x, y) { + return x % y; +}; var $parseInt = parseInt; var $parseFloat = function(f) { if (f !== undefined && f !== null && f.constructor === Number) { @@ -9,18 +11,22 @@ var $parseFloat = function(f) { }; var $froundBuf = new Float32Array(1); -var $fround = Math.fround || function(f) { - $froundBuf[0] = f; - return $froundBuf[0]; -}; +var $fround = + Math.fround || + function(f) { + $froundBuf[0] = f; + return $froundBuf[0]; + }; -var $imul = Math.imul || function(a, b) { - var ah = (a >>> 16) & 0xffff; - var al = a & 0xffff; - var bh = (b >>> 16) & 0xffff; - var bl = b & 0xffff; - return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) >> 0); -}; +var $imul = + Math.imul || + function(a, b) { + var ah = (a >>> 16) & 0xffff; + var al = a & 0xffff; + var bh = (b >>> 16) & 0xffff; + var bl = b & 0xffff; + return (al * bl + (((ah * bl + al * bh) << 16) >>> 0)) >> 0; + }; var $floatKey = function(f) { if (f !== f) { @@ -39,7 +45,7 @@ var $shiftLeft64 = function(x, y) { return x; } if (y < 32) { - return new x.constructor(x.$high << y | x.$low >>> (32 - y), (x.$low << y) >>> 0); + return new x.constructor((x.$high << y) | (x.$low >>> (32 - y)), (x.$low << y) >>> 0); } if (y < 64) { return new x.constructor(x.$low << (y - 32), 0); @@ -52,7 +58,7 @@ var $shiftRightInt64 = function(x, y) { return x; } if (y < 32) { - return new x.constructor(x.$high >> y, (x.$low >>> y | x.$high << (32 - y)) >>> 0); + return new x.constructor(x.$high >> y, ((x.$low >>> y) | (x.$high << (32 - y))) >>> 0); } if (y < 64) { return new x.constructor(x.$high >> 31, (x.$high >> (y - 32)) >>> 0); @@ -68,7 +74,7 @@ var $shiftRightUint64 = function(x, y) { return x; } if (y < 32) { - return new x.constructor(x.$high >>> y, (x.$low >>> y | x.$high << (32 - y)) >>> 0); + return new x.constructor(x.$high >>> y, ((x.$low >>> y) | (x.$high << (32 - y))) >>> 0); } if (y < 64) { return new x.constructor(0, x.$high >>> (y - 32)); @@ -77,19 +83,20 @@ var $shiftRightUint64 = function(x, y) { }; var $mul64 = function(x, y) { - var high = 0, low = 0; + var high = 0, + low = 0; if ((y.$low & 1) !== 0) { high = x.$high; low = x.$low; } for (var i = 1; i < 32; i++) { - if ((y.$low & 1<>> (32 - i); + if ((y.$low & (1 << i)) !== 0) { + high += (x.$high << i) | (x.$low >>> (32 - i)); low += (x.$low << i) >>> 0; } } for (var i = 0; i < 32; i++) { - if ((y.$high & 1< yHigh) || (xHigh === yHigh && xLow > yLow))) { - yHigh = (yHigh << 1 | yLow >>> 31) >>> 0; + var high = 0, + low = 0, + n = 0; + while (yHigh < 2147483648 && (xHigh > yHigh || (xHigh === yHigh && xLow > yLow))) { + yHigh = ((yHigh << 1) | (yLow >>> 31)) >>> 0; yLow = (yLow << 1) >>> 0; n++; } for (var i = 0; i <= n; i++) { - high = high << 1 | low >>> 31; + high = (high << 1) | (low >>> 31); low = (low << 1) >>> 0; - if ((xHigh > yHigh) || (xHigh === yHigh && xLow >= yLow)) { + if (xHigh > yHigh || (xHigh === yHigh && xLow >= yLow)) { xHigh = xHigh - yHigh; xLow = xLow - yLow; if (xLow < 0) { @@ -149,7 +158,7 @@ var $div64 = function(x, y, returnRemainder) { low = 0; } } - yLow = (yLow >>> 1 | yHigh << (32 - 1)) >>> 0; + yLow = ((yLow >>> 1) | (yHigh << (32 - 1))) >>> 0; yHigh = yHigh >>> 1; } @@ -164,7 +173,7 @@ var $divComplex = function(n, d) { var dinf = d.$real === Infinity || d.$real === -Infinity || d.$imag === Infinity || d.$imag === -Infinity; var nnan = !ninf && (n.$real !== n.$real || n.$imag !== n.$imag); var dnan = !dinf && (d.$real !== d.$real || d.$imag !== d.$imag); - if(nnan || dnan) { + if (nnan || dnan) { return new n.constructor(NaN, NaN); } if (ninf && !dinf) { diff --git a/compiler/prelude/prelude.go b/compiler/prelude/prelude.go index caa1d2ade..f28837e7d 100644 --- a/compiler/prelude/prelude.go +++ b/compiler/prelude/prelude.go @@ -3,4 +3,4 @@ package prelude // Prelude is the GopherJS JavaScript interop layer. -const Prelude = "Error.stackTraceLimit = Infinity;\n\nvar $global, $module;\nif (typeof window !== \"undefined\") { /* web page */\n $global = window;\n} else if (typeof self !== \"undefined\") { /* web worker */\n $global = self;\n} else if (typeof global !== \"undefined\") { /* Node.js */\n $global = global;\n $global.require = require;\n} else { /* others (e.g. Nashorn) */\n $global = this;\n}\n\nif ($global === undefined || $global.Array === undefined) {\n throw new Error(\"no global object found\");\n}\nif (typeof module !== \"undefined\") {\n $module = module;\n}\n\nvar $packages = {}, $idCounter = 0;\nvar $keys = function(m) { return m ? Object.keys(m) : []; };\nvar $flushConsole = function() {};\nvar $throwRuntimeError; /* set by package \"runtime\" */\nvar $throwNilPointerError = function() { $throwRuntimeError(\"invalid memory address or nil pointer dereference\"); };\nvar $call = function(fn, rcvr, args) { return fn.apply(rcvr, args); };\nvar $makeFunc = function(fn) { return function() { return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface); }; };\nvar $unused = function(v) {};\n\nvar $mapArray = function(array, f) {\n var newArray = new array.constructor(array.length);\n for (var i = 0; i < array.length; i++) {\n newArray[i] = f(array[i]);\n }\n return newArray;\n};\n\nvar $methodVal = function(recv, name) {\n var vals = recv.$methodVals || {};\n recv.$methodVals = vals; /* noop for primitives */\n var f = vals[name];\n if (f !== undefined) {\n return f;\n }\n var method = recv[name];\n f = function() {\n $stackDepthOffset--;\n try {\n return method.apply(recv, arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n vals[name] = f;\n return f;\n};\n\nvar $methodExpr = function(typ, name) {\n var method = typ.prototype[name];\n if (method.$expr === undefined) {\n method.$expr = function() {\n $stackDepthOffset--;\n try {\n if (typ.wrapped) {\n arguments[0] = new typ(arguments[0]);\n }\n return Function.call.apply(method, arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n }\n return method.$expr;\n};\n\nvar $ifaceMethodExprs = {};\nvar $ifaceMethodExpr = function(name) {\n var expr = $ifaceMethodExprs[\"$\" + name];\n if (expr === undefined) {\n expr = $ifaceMethodExprs[\"$\" + name] = function() {\n $stackDepthOffset--;\n try {\n return Function.call.apply(arguments[0][name], arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n }\n return expr;\n};\n\nvar $subslice = function(slice, low, high, max) {\n if (high === undefined) {\n high = slice.$length;\n }\n if (max === undefined) {\n max = slice.$capacity;\n }\n if (low < 0 || high < low || max < high || high > slice.$capacity || max > slice.$capacity) {\n $throwRuntimeError(\"slice bounds out of range\");\n }\n var s = new slice.constructor(slice.$array);\n s.$offset = slice.$offset + low;\n s.$length = high - low;\n s.$capacity = max - low;\n return s;\n};\n\nvar $substring = function(str, low, high) {\n if (low < 0 || high < low || high > str.length) {\n $throwRuntimeError(\"slice bounds out of range\");\n }\n return str.substring(low, high);\n};\n\nvar $sliceToArray = function(slice) {\n if (slice.$array.constructor !== Array) {\n return slice.$array.subarray(slice.$offset, slice.$offset + slice.$length);\n }\n return slice.$array.slice(slice.$offset, slice.$offset + slice.$length);\n};\n\nvar $decodeRune = function(str, pos) {\n var c0 = str.charCodeAt(pos);\n\n if (c0 < 0x80) {\n return [c0, 1];\n }\n\n if (c0 !== c0 || c0 < 0xC0) {\n return [0xFFFD, 1];\n }\n\n var c1 = str.charCodeAt(pos + 1);\n if (c1 !== c1 || c1 < 0x80 || 0xC0 <= c1) {\n return [0xFFFD, 1];\n }\n\n if (c0 < 0xE0) {\n var r = (c0 & 0x1F) << 6 | (c1 & 0x3F);\n if (r <= 0x7F) {\n return [0xFFFD, 1];\n }\n return [r, 2];\n }\n\n var c2 = str.charCodeAt(pos + 2);\n if (c2 !== c2 || c2 < 0x80 || 0xC0 <= c2) {\n return [0xFFFD, 1];\n }\n\n if (c0 < 0xF0) {\n var r = (c0 & 0x0F) << 12 | (c1 & 0x3F) << 6 | (c2 & 0x3F);\n if (r <= 0x7FF) {\n return [0xFFFD, 1];\n }\n if (0xD800 <= r && r <= 0xDFFF) {\n return [0xFFFD, 1];\n }\n return [r, 3];\n }\n\n var c3 = str.charCodeAt(pos + 3);\n if (c3 !== c3 || c3 < 0x80 || 0xC0 <= c3) {\n return [0xFFFD, 1];\n }\n\n if (c0 < 0xF8) {\n var r = (c0 & 0x07) << 18 | (c1 & 0x3F) << 12 | (c2 & 0x3F) << 6 | (c3 & 0x3F);\n if (r <= 0xFFFF || 0x10FFFF < r) {\n return [0xFFFD, 1];\n }\n return [r, 4];\n }\n\n return [0xFFFD, 1];\n};\n\nvar $encodeRune = function(r) {\n if (r < 0 || r > 0x10FFFF || (0xD800 <= r && r <= 0xDFFF)) {\n r = 0xFFFD;\n }\n if (r <= 0x7F) {\n return String.fromCharCode(r);\n }\n if (r <= 0x7FF) {\n return String.fromCharCode(0xC0 | r >> 6, 0x80 | (r & 0x3F));\n }\n if (r <= 0xFFFF) {\n return String.fromCharCode(0xE0 | r >> 12, 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F));\n }\n return String.fromCharCode(0xF0 | r >> 18, 0x80 | (r >> 12 & 0x3F), 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F));\n};\n\nvar $stringToBytes = function(str) {\n var array = new Uint8Array(str.length);\n for (var i = 0; i < str.length; i++) {\n array[i] = str.charCodeAt(i);\n }\n return array;\n};\n\nvar $bytesToString = function(slice) {\n if (slice.$length === 0) {\n return \"\";\n }\n var str = \"\";\n for (var i = 0; i < slice.$length; i += 10000) {\n str += String.fromCharCode.apply(undefined, slice.$array.subarray(slice.$offset + i, slice.$offset + Math.min(slice.$length, i + 10000)));\n }\n return str;\n};\n\nvar $stringToRunes = function(str) {\n var array = new Int32Array(str.length);\n var rune, j = 0;\n for (var i = 0; i < str.length; i += rune[1], j++) {\n rune = $decodeRune(str, i);\n array[j] = rune[0];\n }\n return array.subarray(0, j);\n};\n\nvar $runesToString = function(slice) {\n if (slice.$length === 0) {\n return \"\";\n }\n var str = \"\";\n for (var i = 0; i < slice.$length; i++) {\n str += $encodeRune(slice.$array[slice.$offset + i]);\n }\n return str;\n};\n\nvar $copyString = function(dst, src) {\n var n = Math.min(src.length, dst.$length);\n for (var i = 0; i < n; i++) {\n dst.$array[dst.$offset + i] = src.charCodeAt(i);\n }\n return n;\n};\n\nvar $copySlice = function(dst, src) {\n var n = Math.min(src.$length, dst.$length);\n $copyArray(dst.$array, src.$array, dst.$offset, src.$offset, n, dst.constructor.elem);\n return n;\n};\n\nvar $copyArray = function(dst, src, dstOffset, srcOffset, n, elem) {\n if (n === 0 || (dst === src && dstOffset === srcOffset)) {\n return;\n }\n\n if (src.subarray) {\n dst.set(src.subarray(srcOffset, srcOffset + n), dstOffset);\n return;\n }\n\n switch (elem.kind) {\n case $kindArray:\n case $kindStruct:\n if (dst === src && dstOffset > srcOffset) {\n for (var i = n - 1; i >= 0; i--) {\n elem.copy(dst[dstOffset + i], src[srcOffset + i]);\n }\n return;\n }\n for (var i = 0; i < n; i++) {\n elem.copy(dst[dstOffset + i], src[srcOffset + i]);\n }\n return;\n }\n\n if (dst === src && dstOffset > srcOffset) {\n for (var i = n - 1; i >= 0; i--) {\n dst[dstOffset + i] = src[srcOffset + i];\n }\n return;\n }\n for (var i = 0; i < n; i++) {\n dst[dstOffset + i] = src[srcOffset + i];\n }\n};\n\nvar $clone = function(src, type) {\n var clone = type.zero();\n type.copy(clone, src);\n return clone;\n};\n\nvar $pointerOfStructConversion = function(obj, type) {\n if(obj.$proxies === undefined) {\n obj.$proxies = {};\n obj.$proxies[obj.constructor.string] = obj;\n }\n var proxy = obj.$proxies[type.string];\n if (proxy === undefined) {\n var properties = {};\n for (var i = 0; i < type.elem.fields.length; i++) {\n (function(fieldProp) {\n properties[fieldProp] = {\n get: function() { return obj[fieldProp]; },\n set: function(value) { obj[fieldProp] = value; }\n };\n })(type.elem.fields[i].prop);\n }\n proxy = Object.create(type.prototype, properties);\n proxy.$val = proxy;\n obj.$proxies[type.string] = proxy;\n proxy.$proxies = obj.$proxies;\n }\n return proxy;\n};\n\nvar $append = function(slice) {\n return $internalAppend(slice, arguments, 1, arguments.length - 1);\n};\n\nvar $appendSlice = function(slice, toAppend) {\n if (toAppend.constructor === String) {\n var bytes = $stringToBytes(toAppend);\n return $internalAppend(slice, bytes, 0, bytes.length);\n }\n return $internalAppend(slice, toAppend.$array, toAppend.$offset, toAppend.$length);\n};\n\nvar $internalAppend = function(slice, array, offset, length) {\n if (length === 0) {\n return slice;\n }\n\n var newArray = slice.$array;\n var newOffset = slice.$offset;\n var newLength = slice.$length + length;\n var newCapacity = slice.$capacity;\n\n if (newLength > newCapacity) {\n newOffset = 0;\n newCapacity = Math.max(newLength, slice.$capacity < 1024 ? slice.$capacity * 2 : Math.floor(slice.$capacity * 5 / 4));\n\n if (slice.$array.constructor === Array) {\n newArray = slice.$array.slice(slice.$offset, slice.$offset + slice.$length);\n newArray.length = newCapacity;\n var zero = slice.constructor.elem.zero;\n for (var i = slice.$length; i < newCapacity; i++) {\n newArray[i] = zero();\n }\n } else {\n newArray = new slice.$array.constructor(newCapacity);\n newArray.set(slice.$array.subarray(slice.$offset, slice.$offset + slice.$length));\n }\n }\n\n $copyArray(newArray, array, newOffset + slice.$length, offset, length, slice.constructor.elem);\n\n var newSlice = new slice.constructor(newArray);\n newSlice.$offset = newOffset;\n newSlice.$length = newLength;\n newSlice.$capacity = newCapacity;\n return newSlice;\n};\n\nvar $equal = function(a, b, type) {\n if (type === $jsObjectPtr) {\n return a === b;\n }\n switch (type.kind) {\n case $kindComplex64:\n case $kindComplex128:\n return a.$real === b.$real && a.$imag === b.$imag;\n case $kindInt64:\n case $kindUint64:\n return a.$high === b.$high && a.$low === b.$low;\n case $kindArray:\n if (a.length !== b.length) {\n return false;\n }\n for (var i = 0; i < a.length; i++) {\n if (!$equal(a[i], b[i], type.elem)) {\n return false;\n }\n }\n return true;\n case $kindStruct:\n for (var i = 0; i < type.fields.length; i++) {\n var f = type.fields[i];\n if (!$equal(a[f.prop], b[f.prop], f.typ)) {\n return false;\n }\n }\n return true;\n case $kindInterface:\n return $interfaceIsEqual(a, b);\n default:\n return a === b;\n }\n};\n\nvar $interfaceIsEqual = function(a, b) {\n if (a === $ifaceNil || b === $ifaceNil) {\n return a === b;\n }\n if (a.constructor !== b.constructor) {\n return false;\n }\n if (a.constructor === $jsObjectPtr) {\n return a.object === b.object;\n }\n if (!a.constructor.comparable) {\n $throwRuntimeError(\"comparing uncomparable type \" + a.constructor.string);\n }\n return $equal(a.$val, b.$val, a.constructor);\n};\nvar $min = Math.min;\nvar $mod = function(x, y) { return x % y; };\nvar $parseInt = parseInt;\nvar $parseFloat = function(f) {\n if (f !== undefined && f !== null && f.constructor === Number) {\n return f;\n }\n return parseFloat(f);\n};\n\nvar $froundBuf = new Float32Array(1);\nvar $fround = Math.fround || function(f) {\n $froundBuf[0] = f;\n return $froundBuf[0];\n};\n\nvar $imul = Math.imul || function(a, b) {\n var ah = (a >>> 16) & 0xffff;\n var al = a & 0xffff;\n var bh = (b >>> 16) & 0xffff;\n var bl = b & 0xffff;\n return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0) >> 0);\n};\n\nvar $floatKey = function(f) {\n if (f !== f) {\n $idCounter++;\n return \"NaN$\" + $idCounter;\n }\n return String(f);\n};\n\nvar $flatten64 = function(x) {\n return x.$high * 4294967296 + x.$low;\n};\n\nvar $shiftLeft64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high << y | x.$low >>> (32 - y), (x.$low << y) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(x.$low << (y - 32), 0);\n }\n return new x.constructor(0, 0);\n};\n\nvar $shiftRightInt64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high >> y, (x.$low >>> y | x.$high << (32 - y)) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(x.$high >> 31, (x.$high >> (y - 32)) >>> 0);\n }\n if (x.$high < 0) {\n return new x.constructor(-1, 4294967295);\n }\n return new x.constructor(0, 0);\n};\n\nvar $shiftRightUint64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high >>> y, (x.$low >>> y | x.$high << (32 - y)) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(0, x.$high >>> (y - 32));\n }\n return new x.constructor(0, 0);\n};\n\nvar $mul64 = function(x, y) {\n var high = 0, low = 0;\n if ((y.$low & 1) !== 0) {\n high = x.$high;\n low = x.$low;\n }\n for (var i = 1; i < 32; i++) {\n if ((y.$low & 1<>> (32 - i);\n low += (x.$low << i) >>> 0;\n }\n }\n for (var i = 0; i < 32; i++) {\n if ((y.$high & 1< yHigh) || (xHigh === yHigh && xLow > yLow))) {\n yHigh = (yHigh << 1 | yLow >>> 31) >>> 0;\n yLow = (yLow << 1) >>> 0;\n n++;\n }\n for (var i = 0; i <= n; i++) {\n high = high << 1 | low >>> 31;\n low = (low << 1) >>> 0;\n if ((xHigh > yHigh) || (xHigh === yHigh && xLow >= yLow)) {\n xHigh = xHigh - yHigh;\n xLow = xLow - yLow;\n if (xLow < 0) {\n xHigh--;\n xLow += 4294967296;\n }\n low++;\n if (low === 4294967296) {\n high++;\n low = 0;\n }\n }\n yLow = (yLow >>> 1 | yHigh << (32 - 1)) >>> 0;\n yHigh = yHigh >>> 1;\n }\n\n if (returnRemainder) {\n return new x.constructor(xHigh * rs, xLow * rs);\n }\n return new x.constructor(high * s, low * s);\n};\n\nvar $divComplex = function(n, d) {\n var ninf = n.$real === Infinity || n.$real === -Infinity || n.$imag === Infinity || n.$imag === -Infinity;\n var dinf = d.$real === Infinity || d.$real === -Infinity || d.$imag === Infinity || d.$imag === -Infinity;\n var nnan = !ninf && (n.$real !== n.$real || n.$imag !== n.$imag);\n var dnan = !dinf && (d.$real !== d.$real || d.$imag !== d.$imag);\n if(nnan || dnan) {\n return new n.constructor(NaN, NaN);\n }\n if (ninf && !dinf) {\n return new n.constructor(Infinity, Infinity);\n }\n if (!ninf && dinf) {\n return new n.constructor(0, 0);\n }\n if (d.$real === 0 && d.$imag === 0) {\n if (n.$real === 0 && n.$imag === 0) {\n return new n.constructor(NaN, NaN);\n }\n return new n.constructor(Infinity, Infinity);\n }\n var a = Math.abs(d.$real);\n var b = Math.abs(d.$imag);\n if (a <= b) {\n var ratio = d.$real / d.$imag;\n var denom = d.$real * ratio + d.$imag;\n return new n.constructor((n.$real * ratio + n.$imag) / denom, (n.$imag * ratio - n.$real) / denom);\n }\n var ratio = d.$imag / d.$real;\n var denom = d.$imag * ratio + d.$real;\n return new n.constructor((n.$imag * ratio + n.$real) / denom, (n.$imag - n.$real * ratio) / denom);\n};\nvar $kindBool = 1;\nvar $kindInt = 2;\nvar $kindInt8 = 3;\nvar $kindInt16 = 4;\nvar $kindInt32 = 5;\nvar $kindInt64 = 6;\nvar $kindUint = 7;\nvar $kindUint8 = 8;\nvar $kindUint16 = 9;\nvar $kindUint32 = 10;\nvar $kindUint64 = 11;\nvar $kindUintptr = 12;\nvar $kindFloat32 = 13;\nvar $kindFloat64 = 14;\nvar $kindComplex64 = 15;\nvar $kindComplex128 = 16;\nvar $kindArray = 17;\nvar $kindChan = 18;\nvar $kindFunc = 19;\nvar $kindInterface = 20;\nvar $kindMap = 21;\nvar $kindPtr = 22;\nvar $kindSlice = 23;\nvar $kindString = 24;\nvar $kindStruct = 25;\nvar $kindUnsafePointer = 26;\n\nvar $methodSynthesizers = [];\nvar $addMethodSynthesizer = function(f) {\n if ($methodSynthesizers === null) {\n f();\n return;\n }\n $methodSynthesizers.push(f);\n};\nvar $synthesizeMethods = function() {\n $methodSynthesizers.forEach(function(f) { f(); });\n $methodSynthesizers = null;\n};\n\nvar $ifaceKeyFor = function(x) {\n if (x === $ifaceNil) {\n return 'nil';\n }\n var c = x.constructor;\n return c.string + '$' + c.keyFor(x.$val);\n};\n\nvar $identity = function(x) { return x; };\n\nvar $typeIDCounter = 0;\n\nvar $idKey = function(x) {\n if (x.$id === undefined) {\n $idCounter++;\n x.$id = $idCounter;\n }\n return String(x.$id);\n};\n\nvar $newType = function(size, kind, string, named, pkg, exported, constructor) {\n var typ;\n switch(kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindUnsafePointer:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = $identity;\n break;\n\n case $kindString:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = function(x) { return \"$\" + x; };\n break;\n\n case $kindFloat32:\n case $kindFloat64:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = function(x) { return $floatKey(x); };\n break;\n\n case $kindInt64:\n typ = function(high, low) {\n this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >> 0;\n this.$low = low >>> 0;\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$high + \"$\" + x.$low; };\n break;\n\n case $kindUint64:\n typ = function(high, low) {\n this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >>> 0;\n this.$low = low >>> 0;\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$high + \"$\" + x.$low; };\n break;\n\n case $kindComplex64:\n typ = function(real, imag) {\n this.$real = $fround(real);\n this.$imag = $fround(imag);\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$real + \"$\" + x.$imag; };\n break;\n\n case $kindComplex128:\n typ = function(real, imag) {\n this.$real = real;\n this.$imag = imag;\n this.$val = this;\n };\n typ.keyFor = function(x) { return x.$real + \"$\" + x.$imag; };\n break;\n\n case $kindArray:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.ptr = $newType(4, $kindPtr, \"*\" + string, false, \"\", false, function(array) {\n this.$get = function() { return array; };\n this.$set = function(v) { typ.copy(this, v); };\n this.$val = array;\n });\n typ.init = function(elem, len) {\n typ.elem = elem;\n typ.len = len;\n typ.comparable = elem.comparable;\n typ.keyFor = function(x) {\n return Array.prototype.join.call($mapArray(x, function(e) {\n return String(elem.keyFor(e)).replace(/\\\\/g, \"\\\\\\\\\").replace(/\\$/g, \"\\\\$\");\n }), \"$\");\n };\n typ.copy = function(dst, src) {\n $copyArray(dst, src, 0, 0, src.length, elem);\n };\n typ.ptr.init(typ);\n Object.defineProperty(typ.ptr.nil, \"nilCheck\", { get: $throwNilPointerError });\n };\n break;\n\n case $kindChan:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.keyFor = $idKey;\n typ.init = function(elem, sendOnly, recvOnly) {\n typ.elem = elem;\n typ.sendOnly = sendOnly;\n typ.recvOnly = recvOnly;\n };\n break;\n\n case $kindFunc:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.init = function(params, results, variadic) {\n typ.params = params;\n typ.results = results;\n typ.variadic = variadic;\n typ.comparable = false;\n };\n break;\n\n case $kindInterface:\n typ = { implementedBy: {}, missingMethodFor: {} };\n typ.keyFor = $ifaceKeyFor;\n typ.init = function(methods) {\n typ.methods = methods;\n methods.forEach(function(m) {\n $ifaceNil[m.prop] = $throwNilPointerError;\n });\n };\n break;\n\n case $kindMap:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.init = function(key, elem) {\n typ.key = key;\n typ.elem = elem;\n typ.comparable = false;\n };\n break;\n\n case $kindPtr:\n typ = constructor || function(getter, setter, target) {\n this.$get = getter;\n this.$set = setter;\n this.$target = target;\n this.$val = this;\n };\n typ.keyFor = $idKey;\n typ.init = function(elem) {\n typ.elem = elem;\n typ.wrapped = (elem.kind === $kindArray);\n typ.nil = new typ($throwNilPointerError, $throwNilPointerError);\n };\n break;\n\n case $kindSlice:\n typ = function(array) {\n if (array.constructor !== typ.nativeArray) {\n array = new typ.nativeArray(array);\n }\n this.$array = array;\n this.$offset = 0;\n this.$length = array.length;\n this.$capacity = array.length;\n this.$val = this;\n };\n typ.init = function(elem) {\n typ.elem = elem;\n typ.comparable = false;\n typ.nativeArray = $nativeArray(elem.kind);\n typ.nil = new typ([]);\n };\n break;\n\n case $kindStruct:\n typ = function(v) { this.$val = v; };\n typ.wrapped = true;\n typ.ptr = $newType(4, $kindPtr, \"*\" + string, false, pkg, exported, constructor);\n typ.ptr.elem = typ;\n typ.ptr.prototype.$get = function() { return this; };\n typ.ptr.prototype.$set = function(v) { typ.copy(this, v); };\n typ.init = function(pkgPath, fields) {\n typ.pkgPath = pkgPath;\n typ.fields = fields;\n fields.forEach(function(f) {\n if (!f.typ.comparable) {\n typ.comparable = false;\n }\n });\n typ.keyFor = function(x) {\n var val = x.$val;\n return $mapArray(fields, function(f) {\n return String(f.typ.keyFor(val[f.prop])).replace(/\\\\/g, \"\\\\\\\\\").replace(/\\$/g, \"\\\\$\");\n }).join(\"$\");\n };\n typ.copy = function(dst, src) {\n for (var i = 0; i < fields.length; i++) {\n var f = fields[i];\n switch (f.typ.kind) {\n case $kindArray:\n case $kindStruct:\n f.typ.copy(dst[f.prop], src[f.prop]);\n continue;\n default:\n dst[f.prop] = src[f.prop];\n continue;\n }\n }\n };\n /* nil value */\n var properties = {};\n fields.forEach(function(f) {\n properties[f.prop] = { get: $throwNilPointerError, set: $throwNilPointerError };\n });\n typ.ptr.nil = Object.create(constructor.prototype, properties);\n typ.ptr.nil.$val = typ.ptr.nil;\n /* methods for embedded fields */\n $addMethodSynthesizer(function() {\n var synthesizeMethod = function(target, m, f) {\n if (target.prototype[m.prop] !== undefined) { return; }\n target.prototype[m.prop] = function() {\n var v = this.$val[f.prop];\n if (f.typ === $jsObjectPtr) {\n v = new $jsObjectPtr(v);\n }\n if (v.$val === undefined) {\n v = new f.typ(v);\n }\n return v[m.prop].apply(v, arguments);\n };\n };\n fields.forEach(function(f) {\n if (f.anonymous) {\n $methodSet(f.typ).forEach(function(m) {\n synthesizeMethod(typ, m, f);\n synthesizeMethod(typ.ptr, m, f);\n });\n $methodSet($ptrType(f.typ)).forEach(function(m) {\n synthesizeMethod(typ.ptr, m, f);\n });\n }\n });\n });\n };\n break;\n\n default:\n $panic(new $String(\"invalid kind: \" + kind));\n }\n\n switch (kind) {\n case $kindBool:\n case $kindMap:\n typ.zero = function() { return false; };\n break;\n\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8 :\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindUnsafePointer:\n case $kindFloat32:\n case $kindFloat64:\n typ.zero = function() { return 0; };\n break;\n\n case $kindString:\n typ.zero = function() { return \"\"; };\n break;\n\n case $kindInt64:\n case $kindUint64:\n case $kindComplex64:\n case $kindComplex128:\n var zero = new typ(0, 0);\n typ.zero = function() { return zero; };\n break;\n\n case $kindPtr:\n case $kindSlice:\n typ.zero = function() { return typ.nil; };\n break;\n\n case $kindChan:\n typ.zero = function() { return $chanNil; };\n break;\n\n case $kindFunc:\n typ.zero = function() { return $throwNilPointerError; };\n break;\n\n case $kindInterface:\n typ.zero = function() { return $ifaceNil; };\n break;\n\n case $kindArray:\n typ.zero = function() {\n var arrayClass = $nativeArray(typ.elem.kind);\n if (arrayClass !== Array) {\n return new arrayClass(typ.len);\n }\n var array = new Array(typ.len);\n for (var i = 0; i < typ.len; i++) {\n array[i] = typ.elem.zero();\n }\n return array;\n };\n break;\n\n case $kindStruct:\n typ.zero = function() { return new typ.ptr(); };\n break;\n\n default:\n $panic(new $String(\"invalid kind: \" + kind));\n }\n\n typ.id = $typeIDCounter;\n $typeIDCounter++;\n typ.size = size;\n typ.kind = kind;\n typ.string = string;\n typ.named = named;\n typ.pkg = pkg;\n typ.exported = exported;\n typ.methods = [];\n typ.methodSetCache = null;\n typ.comparable = true;\n return typ;\n};\n\nvar $methodSet = function(typ) {\n if (typ.methodSetCache !== null) {\n return typ.methodSetCache;\n }\n var base = {};\n\n var isPtr = (typ.kind === $kindPtr);\n if (isPtr && typ.elem.kind === $kindInterface) {\n typ.methodSetCache = [];\n return [];\n }\n\n var current = [{typ: isPtr ? typ.elem : typ, indirect: isPtr}];\n\n var seen = {};\n\n while (current.length > 0) {\n var next = [];\n var mset = [];\n\n current.forEach(function(e) {\n if (seen[e.typ.string]) {\n return;\n }\n seen[e.typ.string] = true;\n\n if (e.typ.named) {\n mset = mset.concat(e.typ.methods);\n if (e.indirect) {\n mset = mset.concat($ptrType(e.typ).methods);\n }\n }\n\n switch (e.typ.kind) {\n case $kindStruct:\n e.typ.fields.forEach(function(f) {\n if (f.anonymous) {\n var fTyp = f.typ;\n var fIsPtr = (fTyp.kind === $kindPtr);\n next.push({typ: fIsPtr ? fTyp.elem : fTyp, indirect: e.indirect || fIsPtr});\n }\n });\n break;\n\n case $kindInterface:\n mset = mset.concat(e.typ.methods);\n break;\n }\n });\n\n mset.forEach(function(m) {\n if (base[m.name] === undefined) {\n base[m.name] = m;\n }\n });\n\n current = next;\n }\n\n typ.methodSetCache = [];\n Object.keys(base).sort().forEach(function(name) {\n typ.methodSetCache.push(base[name]);\n });\n return typ.methodSetCache;\n};\n\nvar $Bool = $newType( 1, $kindBool, \"bool\", true, \"\", false, null);\nvar $Int = $newType( 4, $kindInt, \"int\", true, \"\", false, null);\nvar $Int8 = $newType( 1, $kindInt8, \"int8\", true, \"\", false, null);\nvar $Int16 = $newType( 2, $kindInt16, \"int16\", true, \"\", false, null);\nvar $Int32 = $newType( 4, $kindInt32, \"int32\", true, \"\", false, null);\nvar $Int64 = $newType( 8, $kindInt64, \"int64\", true, \"\", false, null);\nvar $Uint = $newType( 4, $kindUint, \"uint\", true, \"\", false, null);\nvar $Uint8 = $newType( 1, $kindUint8, \"uint8\", true, \"\", false, null);\nvar $Uint16 = $newType( 2, $kindUint16, \"uint16\", true, \"\", false, null);\nvar $Uint32 = $newType( 4, $kindUint32, \"uint32\", true, \"\", false, null);\nvar $Uint64 = $newType( 8, $kindUint64, \"uint64\", true, \"\", false, null);\nvar $Uintptr = $newType( 4, $kindUintptr, \"uintptr\", true, \"\", false, null);\nvar $Float32 = $newType( 4, $kindFloat32, \"float32\", true, \"\", false, null);\nvar $Float64 = $newType( 8, $kindFloat64, \"float64\", true, \"\", false, null);\nvar $Complex64 = $newType( 8, $kindComplex64, \"complex64\", true, \"\", false, null);\nvar $Complex128 = $newType(16, $kindComplex128, \"complex128\", true, \"\", false, null);\nvar $String = $newType( 8, $kindString, \"string\", true, \"\", false, null);\nvar $UnsafePointer = $newType( 4, $kindUnsafePointer, \"unsafe.Pointer\", true, \"\", false, null);\n\nvar $nativeArray = function(elemKind) {\n switch (elemKind) {\n case $kindInt:\n return Int32Array;\n case $kindInt8:\n return Int8Array;\n case $kindInt16:\n return Int16Array;\n case $kindInt32:\n return Int32Array;\n case $kindUint:\n return Uint32Array;\n case $kindUint8:\n return Uint8Array;\n case $kindUint16:\n return Uint16Array;\n case $kindUint32:\n return Uint32Array;\n case $kindUintptr:\n return Uint32Array;\n case $kindFloat32:\n return Float32Array;\n case $kindFloat64:\n return Float64Array;\n default:\n return Array;\n }\n};\nvar $toNativeArray = function(elemKind, array) {\n var nativeArray = $nativeArray(elemKind);\n if (nativeArray === Array) {\n return array;\n }\n return new nativeArray(array);\n};\nvar $arrayTypes = {};\nvar $arrayType = function(elem, len) {\n var typeKey = elem.id + \"$\" + len;\n var typ = $arrayTypes[typeKey];\n if (typ === undefined) {\n typ = $newType(12, $kindArray, \"[\" + len + \"]\" + elem.string, false, \"\", false, null);\n $arrayTypes[typeKey] = typ;\n typ.init(elem, len);\n }\n return typ;\n};\n\nvar $chanType = function(elem, sendOnly, recvOnly) {\n var string = (recvOnly ? \"<-\" : \"\") + \"chan\" + (sendOnly ? \"<- \" : \" \") + elem.string;\n var field = sendOnly ? \"SendChan\" : (recvOnly ? \"RecvChan\" : \"Chan\");\n var typ = elem[field];\n if (typ === undefined) {\n typ = $newType(4, $kindChan, string, false, \"\", false, null);\n elem[field] = typ;\n typ.init(elem, sendOnly, recvOnly);\n }\n return typ;\n};\nvar $Chan = function(elem, capacity) {\n if (capacity < 0 || capacity > 2147483647) {\n $throwRuntimeError(\"makechan: size out of range\");\n }\n this.$elem = elem;\n this.$capacity = capacity;\n this.$buffer = [];\n this.$sendQueue = [];\n this.$recvQueue = [];\n this.$closed = false;\n};\nvar $chanNil = new $Chan(null, 0);\n$chanNil.$sendQueue = $chanNil.$recvQueue = { length: 0, push: function() {}, shift: function() { return undefined; }, indexOf: function() { return -1; } };\n\nvar $funcTypes = {};\nvar $funcType = function(params, results, variadic) {\n var typeKey = $mapArray(params, function(p) { return p.id; }).join(\",\") + \"$\" + $mapArray(results, function(r) { return r.id; }).join(\",\") + \"$\" + variadic;\n var typ = $funcTypes[typeKey];\n if (typ === undefined) {\n var paramTypes = $mapArray(params, function(p) { return p.string; });\n if (variadic) {\n paramTypes[paramTypes.length - 1] = \"...\" + paramTypes[paramTypes.length - 1].substr(2);\n }\n var string = \"func(\" + paramTypes.join(\", \") + \")\";\n if (results.length === 1) {\n string += \" \" + results[0].string;\n } else if (results.length > 1) {\n string += \" (\" + $mapArray(results, function(r) { return r.string; }).join(\", \") + \")\";\n }\n typ = $newType(4, $kindFunc, string, false, \"\", false, null);\n $funcTypes[typeKey] = typ;\n typ.init(params, results, variadic);\n }\n return typ;\n};\n\nvar $interfaceTypes = {};\nvar $interfaceType = function(methods) {\n var typeKey = $mapArray(methods, function(m) { return m.pkg + \",\" + m.name + \",\" + m.typ.id; }).join(\"$\");\n var typ = $interfaceTypes[typeKey];\n if (typ === undefined) {\n var string = \"interface {}\";\n if (methods.length !== 0) {\n string = \"interface { \" + $mapArray(methods, function(m) {\n return (m.pkg !== \"\" ? m.pkg + \".\" : \"\") + m.name + m.typ.string.substr(4);\n }).join(\"; \") + \" }\";\n }\n typ = $newType(8, $kindInterface, string, false, \"\", false, null);\n $interfaceTypes[typeKey] = typ;\n typ.init(methods);\n }\n return typ;\n};\nvar $emptyInterface = $interfaceType([]);\nvar $ifaceNil = {};\nvar $error = $newType(8, $kindInterface, \"error\", true, \"\", false, null);\n$error.init([{prop: \"Error\", name: \"Error\", pkg: \"\", typ: $funcType([], [$String], false)}]);\n\nvar $mapTypes = {};\nvar $mapType = function(key, elem) {\n var typeKey = key.id + \"$\" + elem.id;\n var typ = $mapTypes[typeKey];\n if (typ === undefined) {\n typ = $newType(4, $kindMap, \"map[\" + key.string + \"]\" + elem.string, false, \"\", false, null);\n $mapTypes[typeKey] = typ;\n typ.init(key, elem);\n }\n return typ;\n};\nvar $makeMap = function(keyForFunc, entries) {\n var m = {};\n for (var i = 0; i < entries.length; i++) {\n var e = entries[i];\n m[keyForFunc(e.k)] = e;\n }\n return m;\n};\n\nvar $ptrType = function(elem) {\n var typ = elem.ptr;\n if (typ === undefined) {\n typ = $newType(4, $kindPtr, \"*\" + elem.string, false, \"\", elem.exported, null);\n elem.ptr = typ;\n typ.init(elem);\n }\n return typ;\n};\n\nvar $newDataPointer = function(data, constructor) {\n if (constructor.elem.kind === $kindStruct) {\n return data;\n }\n return new constructor(function() { return data; }, function(v) { data = v; });\n};\n\nvar $indexPtr = function(array, index, constructor) {\n array.$ptr = array.$ptr || {};\n return array.$ptr[index] || (array.$ptr[index] = new constructor(function() { return array[index]; }, function(v) { array[index] = v; }));\n};\n\nvar $sliceType = function(elem) {\n var typ = elem.slice;\n if (typ === undefined) {\n typ = $newType(12, $kindSlice, \"[]\" + elem.string, false, \"\", false, null);\n elem.slice = typ;\n typ.init(elem);\n }\n return typ;\n};\nvar $makeSlice = function(typ, length, capacity) {\n capacity = capacity || length;\n if (length < 0 || length > 2147483647) {\n $throwRuntimeError(\"makeslice: len out of range\");\n }\n if (capacity < 0 || capacity < length || capacity > 2147483647) {\n $throwRuntimeError(\"makeslice: cap out of range\");\n }\n var array = new typ.nativeArray(capacity);\n if (typ.nativeArray === Array) {\n for (var i = 0; i < capacity; i++) {\n array[i] = typ.elem.zero();\n }\n }\n var slice = new typ(array);\n slice.$length = length;\n return slice;\n};\n\nvar $structTypes = {};\nvar $structType = function(pkgPath, fields) {\n var typeKey = $mapArray(fields, function(f) { return f.name + \",\" + f.typ.id + \",\" + f.tag; }).join(\"$\");\n var typ = $structTypes[typeKey];\n if (typ === undefined) {\n var string = \"struct { \" + $mapArray(fields, function(f) {\n return f.name + \" \" + f.typ.string + (f.tag !== \"\" ? (\" \\\"\" + f.tag.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, \"\\\\\\\"\") + \"\\\"\") : \"\");\n }).join(\"; \") + \" }\";\n if (fields.length === 0) {\n string = \"struct {}\";\n }\n typ = $newType(0, $kindStruct, string, false, \"\", false, function() {\n this.$val = this;\n for (var i = 0; i < fields.length; i++) {\n var f = fields[i];\n var arg = arguments[i];\n this[f.prop] = arg !== undefined ? arg : f.typ.zero();\n }\n });\n $structTypes[typeKey] = typ;\n typ.init(pkgPath, fields);\n }\n return typ;\n};\n\nvar $assertType = function(value, type, returnTuple) {\n var isInterface = (type.kind === $kindInterface), ok, missingMethod = \"\";\n if (value === $ifaceNil) {\n ok = false;\n } else if (!isInterface) {\n ok = value.constructor === type;\n } else {\n var valueTypeString = value.constructor.string;\n ok = type.implementedBy[valueTypeString];\n if (ok === undefined) {\n ok = true;\n var valueMethodSet = $methodSet(value.constructor);\n var interfaceMethods = type.methods;\n for (var i = 0; i < interfaceMethods.length; i++) {\n var tm = interfaceMethods[i];\n var found = false;\n for (var j = 0; j < valueMethodSet.length; j++) {\n var vm = valueMethodSet[j];\n if (vm.name === tm.name && vm.pkg === tm.pkg && vm.typ === tm.typ) {\n found = true;\n break;\n }\n }\n if (!found) {\n ok = false;\n type.missingMethodFor[valueTypeString] = tm.name;\n break;\n }\n }\n type.implementedBy[valueTypeString] = ok;\n }\n if (!ok) {\n missingMethod = type.missingMethodFor[valueTypeString];\n }\n }\n\n if (!ok) {\n if (returnTuple) {\n return [type.zero(), false];\n }\n $panic(new $packages[\"runtime\"].TypeAssertionError.ptr(\"\", (value === $ifaceNil ? \"\" : value.constructor.string), type.string, missingMethod));\n }\n\n if (!isInterface) {\n value = value.$val;\n }\n if (type === $jsObjectPtr) {\n value = value.object;\n }\n return returnTuple ? [value, true] : value;\n};\nvar $stackDepthOffset = 0;\nvar $getStackDepth = function() {\n var err = new Error();\n if (err.stack === undefined) {\n return undefined;\n }\n return $stackDepthOffset + err.stack.split(\"\\n\").length;\n};\n\nvar $panicStackDepth = null, $panicValue;\nvar $callDeferred = function(deferred, jsErr, fromPanic) {\n if (!fromPanic && deferred !== null && deferred.index >= $curGoroutine.deferStack.length) {\n throw jsErr;\n }\n if (jsErr !== null) {\n var newErr = null;\n try {\n $curGoroutine.deferStack.push(deferred);\n $panic(new $jsErrorPtr(jsErr));\n } catch (err) {\n newErr = err;\n }\n $curGoroutine.deferStack.pop();\n $callDeferred(deferred, newErr);\n return;\n }\n if ($curGoroutine.asleep) {\n return;\n }\n\n $stackDepthOffset--;\n var outerPanicStackDepth = $panicStackDepth;\n var outerPanicValue = $panicValue;\n\n var localPanicValue = $curGoroutine.panicStack.pop();\n if (localPanicValue !== undefined) {\n $panicStackDepth = $getStackDepth();\n $panicValue = localPanicValue;\n }\n\n try {\n while (true) {\n if (deferred === null) {\n deferred = $curGoroutine.deferStack[$curGoroutine.deferStack.length - 1];\n if (deferred === undefined) {\n /* The panic reached the top of the stack. Clear it and throw it as a JavaScript error. */\n $panicStackDepth = null;\n if (localPanicValue.Object instanceof Error) {\n throw localPanicValue.Object;\n }\n var msg;\n if (localPanicValue.constructor === $String) {\n msg = localPanicValue.$val;\n } else if (localPanicValue.Error !== undefined) {\n msg = localPanicValue.Error();\n } else if (localPanicValue.String !== undefined) {\n msg = localPanicValue.String();\n } else {\n msg = localPanicValue;\n }\n throw new Error(msg);\n }\n }\n var call = deferred.pop();\n if (call === undefined) {\n $curGoroutine.deferStack.pop();\n if (localPanicValue !== undefined) {\n deferred = null;\n continue;\n }\n return;\n }\n var r = call[0].apply(call[2], call[1]);\n if (r && r.$blk !== undefined) {\n deferred.push([r.$blk, [], r]);\n if (fromPanic) {\n throw null;\n }\n return;\n }\n\n if (localPanicValue !== undefined && $panicStackDepth === null) {\n throw null; /* error was recovered */\n }\n }\n } finally {\n if (localPanicValue !== undefined) {\n if ($panicStackDepth !== null) {\n $curGoroutine.panicStack.push(localPanicValue);\n }\n $panicStackDepth = outerPanicStackDepth;\n $panicValue = outerPanicValue;\n }\n $stackDepthOffset++;\n }\n};\n\nvar $panic = function(value) {\n $curGoroutine.panicStack.push(value);\n $callDeferred(null, null, true);\n};\nvar $recover = function() {\n if ($panicStackDepth === null || ($panicStackDepth !== undefined && $panicStackDepth !== $getStackDepth() - 2)) {\n return $ifaceNil;\n }\n $panicStackDepth = null;\n return $panicValue;\n};\nvar $throw = function(err) { throw err; };\n\nvar $noGoroutine = { asleep: false, exit: false, deferStack: [], panicStack: [] };\nvar $curGoroutine = $noGoroutine, $totalGoroutines = 0, $awakeGoroutines = 0, $checkForDeadlock = true;\nvar $mainFinished = false;\nvar $go = function(fun, args) {\n $totalGoroutines++;\n $awakeGoroutines++;\n var $goroutine = function() {\n try {\n $curGoroutine = $goroutine;\n var r = fun.apply(undefined, args);\n if (r && r.$blk !== undefined) {\n fun = function() { return r.$blk(); };\n args = [];\n return;\n }\n $goroutine.exit = true;\n } catch (err) {\n if (!$goroutine.exit) {\n throw err;\n }\n } finally {\n $curGoroutine = $noGoroutine;\n if ($goroutine.exit) { /* also set by runtime.Goexit() */\n $totalGoroutines--;\n $goroutine.asleep = true;\n }\n if ($goroutine.asleep) {\n $awakeGoroutines--;\n if (!$mainFinished && $awakeGoroutines === 0 && $checkForDeadlock) {\n console.error(\"fatal error: all goroutines are asleep - deadlock!\");\n if ($global.process !== undefined) {\n $global.process.exit(2);\n }\n }\n }\n }\n };\n $goroutine.asleep = false;\n $goroutine.exit = false;\n $goroutine.deferStack = [];\n $goroutine.panicStack = [];\n $schedule($goroutine);\n};\n\nvar $scheduled = [];\nvar $runScheduled = function() {\n try {\n var r;\n while ((r = $scheduled.shift()) !== undefined) {\n r();\n }\n } finally {\n if ($scheduled.length > 0) {\n setTimeout($runScheduled, 0);\n }\n }\n};\n\nvar $schedule = function(goroutine) {\n if (goroutine.asleep) {\n goroutine.asleep = false;\n $awakeGoroutines++;\n }\n $scheduled.push(goroutine);\n if ($curGoroutine === $noGoroutine) {\n $runScheduled();\n }\n};\n\nvar $setTimeout = function(f, t) {\n $awakeGoroutines++;\n return setTimeout(function() {\n $awakeGoroutines--;\n f();\n }, t);\n};\n\nvar $block = function() {\n if ($curGoroutine === $noGoroutine) {\n $throwRuntimeError(\"cannot block in JavaScript callback, fix by wrapping code in goroutine\");\n }\n $curGoroutine.asleep = true;\n};\n\nvar $send = function(chan, value) {\n if (chan.$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n var queuedRecv = chan.$recvQueue.shift();\n if (queuedRecv !== undefined) {\n queuedRecv([value, true]);\n return;\n }\n if (chan.$buffer.length < chan.$capacity) {\n chan.$buffer.push(value);\n return;\n }\n\n var thisGoroutine = $curGoroutine;\n var closedDuringSend;\n chan.$sendQueue.push(function(closed) {\n closedDuringSend = closed;\n $schedule(thisGoroutine);\n return value;\n });\n $block();\n return {\n $blk: function() {\n if (closedDuringSend) {\n $throwRuntimeError(\"send on closed channel\");\n }\n }\n };\n};\nvar $recv = function(chan) {\n var queuedSend = chan.$sendQueue.shift();\n if (queuedSend !== undefined) {\n chan.$buffer.push(queuedSend(false));\n }\n var bufferedValue = chan.$buffer.shift();\n if (bufferedValue !== undefined) {\n return [bufferedValue, true];\n }\n if (chan.$closed) {\n return [chan.$elem.zero(), false];\n }\n\n var thisGoroutine = $curGoroutine;\n var f = { $blk: function() { return this.value; } };\n var queueEntry = function(v) {\n f.value = v;\n $schedule(thisGoroutine);\n };\n chan.$recvQueue.push(queueEntry);\n $block();\n return f;\n};\nvar $close = function(chan) {\n if (chan.$closed) {\n $throwRuntimeError(\"close of closed channel\");\n }\n chan.$closed = true;\n while (true) {\n var queuedSend = chan.$sendQueue.shift();\n if (queuedSend === undefined) {\n break;\n }\n queuedSend(true); /* will panic */\n }\n while (true) {\n var queuedRecv = chan.$recvQueue.shift();\n if (queuedRecv === undefined) {\n break;\n }\n queuedRecv([chan.$elem.zero(), false]);\n }\n};\nvar $select = function(comms) {\n var ready = [];\n var selection = -1;\n for (var i = 0; i < comms.length; i++) {\n var comm = comms[i];\n var chan = comm[0];\n switch (comm.length) {\n case 0: /* default */\n selection = i;\n break;\n case 1: /* recv */\n if (chan.$sendQueue.length !== 0 || chan.$buffer.length !== 0 || chan.$closed) {\n ready.push(i);\n }\n break;\n case 2: /* send */\n if (chan.$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n if (chan.$recvQueue.length !== 0 || chan.$buffer.length < chan.$capacity) {\n ready.push(i);\n }\n break;\n }\n }\n\n if (ready.length !== 0) {\n selection = ready[Math.floor(Math.random() * ready.length)];\n }\n if (selection !== -1) {\n var comm = comms[selection];\n switch (comm.length) {\n case 0: /* default */\n return [selection];\n case 1: /* recv */\n return [selection, $recv(comm[0])];\n case 2: /* send */\n $send(comm[0], comm[1]);\n return [selection];\n }\n }\n\n var entries = [];\n var thisGoroutine = $curGoroutine;\n var f = { $blk: function() { return this.selection; } };\n var removeFromQueues = function() {\n for (var i = 0; i < entries.length; i++) {\n var entry = entries[i];\n var queue = entry[0];\n var index = queue.indexOf(entry[1]);\n if (index !== -1) {\n queue.splice(index, 1);\n }\n }\n };\n for (var i = 0; i < comms.length; i++) {\n (function(i) {\n var comm = comms[i];\n switch (comm.length) {\n case 1: /* recv */\n var queueEntry = function(value) {\n f.selection = [i, value];\n removeFromQueues();\n $schedule(thisGoroutine);\n };\n entries.push([comm[0].$recvQueue, queueEntry]);\n comm[0].$recvQueue.push(queueEntry);\n break;\n case 2: /* send */\n var queueEntry = function() {\n if (comm[0].$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n f.selection = [i];\n removeFromQueues();\n $schedule(thisGoroutine);\n return comm[1];\n };\n entries.push([comm[0].$sendQueue, queueEntry]);\n comm[0].$sendQueue.push(queueEntry);\n break;\n }\n })(i);\n }\n $block();\n return f;\n};\nvar $jsObjectPtr, $jsErrorPtr;\n\nvar $needsExternalization = function(t) {\n switch (t.kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindFloat32:\n case $kindFloat64:\n return false;\n default:\n return t !== $jsObjectPtr;\n }\n};\n\nvar $externalize = function(v, t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n switch (t.kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindFloat32:\n case $kindFloat64:\n return v;\n case $kindInt64:\n case $kindUint64:\n return $flatten64(v);\n case $kindArray:\n if ($needsExternalization(t.elem)) {\n return $mapArray(v, function(e) { return $externalize(e, t.elem); });\n }\n return v;\n case $kindFunc:\n return $externalizeFunction(v, t, false);\n case $kindInterface:\n if (v === $ifaceNil) {\n return null;\n }\n if (v.constructor === $jsObjectPtr) {\n return v.$val.object;\n }\n return $externalize(v.$val, v.constructor);\n case $kindMap:\n var m = {};\n var keys = $keys(v);\n for (var i = 0; i < keys.length; i++) {\n var entry = v[keys[i]];\n m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem);\n }\n return m;\n case $kindPtr:\n if (v === t.nil) {\n return null;\n }\n return $externalize(v.$get(), t.elem);\n case $kindSlice:\n if ($needsExternalization(t.elem)) {\n return $mapArray($sliceToArray(v), function(e) { return $externalize(e, t.elem); });\n }\n return $sliceToArray(v);\n case $kindString:\n if ($isASCII(v)) {\n return v;\n }\n var s = \"\", r;\n for (var i = 0; i < v.length; i += r[1]) {\n r = $decodeRune(v, i);\n var c = r[0];\n if (c > 0xFFFF) {\n var h = Math.floor((c - 0x10000) / 0x400) + 0xD800;\n var l = (c - 0x10000) % 0x400 + 0xDC00;\n s += String.fromCharCode(h, l);\n continue;\n }\n s += String.fromCharCode(c);\n }\n return s;\n case $kindStruct:\n var timePkg = $packages[\"time\"];\n if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) {\n var milli = $div64(v.UnixNano(), new $Int64(0, 1000000));\n return new Date($flatten64(milli));\n }\n\n var noJsObject = {};\n var searchJsObject = function(v, t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n switch (t.kind) {\n case $kindPtr:\n if (v === t.nil) {\n return noJsObject;\n }\n return searchJsObject(v.$get(), t.elem);\n case $kindStruct:\n var f = t.fields[0];\n return searchJsObject(v[f.prop], f.typ);\n case $kindInterface:\n return searchJsObject(v.$val, v.constructor);\n default:\n return noJsObject;\n }\n };\n var o = searchJsObject(v, t);\n if (o !== noJsObject) {\n return o;\n }\n\n o = {};\n for (var i = 0; i < t.fields.length; i++) {\n var f = t.fields[i];\n if (!f.exported) {\n continue;\n }\n o[f.name] = $externalize(v[f.prop], f.typ);\n }\n return o;\n }\n $throwRuntimeError(\"cannot externalize \" + t.string);\n};\n\nvar $externalizeFunction = function(v, t, passThis) {\n if (v === $throwNilPointerError) {\n return null;\n }\n if (v.$externalizeWrapper === undefined) {\n $checkForDeadlock = false;\n v.$externalizeWrapper = function() {\n var args = [];\n for (var i = 0; i < t.params.length; i++) {\n if (t.variadic && i === t.params.length - 1) {\n var vt = t.params[i].elem, varargs = [];\n for (var j = i; j < arguments.length; j++) {\n varargs.push($internalize(arguments[j], vt));\n }\n args.push(new (t.params[i])(varargs));\n break;\n }\n args.push($internalize(arguments[i], t.params[i]));\n }\n var result = v.apply(passThis ? this : undefined, args);\n switch (t.results.length) {\n case 0:\n return;\n case 1:\n return $externalize(result, t.results[0]);\n default:\n for (var i = 0; i < t.results.length; i++) {\n result[i] = $externalize(result[i], t.results[i]);\n }\n return result;\n }\n };\n }\n return v.$externalizeWrapper;\n};\n\nvar $internalize = function(v, t, recv) {\n if (t === $jsObjectPtr) {\n return v;\n }\n if (t === $jsObjectPtr.elem) {\n $throwRuntimeError(\"cannot internalize js.Object, use *js.Object instead\");\n }\n if (v && v.__internal_object__ !== undefined) {\n return $assertType(v.__internal_object__, t, false);\n }\n var timePkg = $packages[\"time\"];\n if (timePkg !== undefined && t === timePkg.Time) {\n if (!(v !== null && v !== undefined && v.constructor === Date)) {\n $throwRuntimeError(\"cannot internalize time.Time from \" + typeof v + \", must be Date\");\n }\n return timePkg.Unix(new $Int64(0, 0), new $Int64(0, v.getTime() * 1000000));\n }\n switch (t.kind) {\n case $kindBool:\n return !!v;\n case $kindInt:\n return parseInt(v);\n case $kindInt8:\n return parseInt(v) << 24 >> 24;\n case $kindInt16:\n return parseInt(v) << 16 >> 16;\n case $kindInt32:\n return parseInt(v) >> 0;\n case $kindUint:\n return parseInt(v);\n case $kindUint8:\n return parseInt(v) << 24 >>> 24;\n case $kindUint16:\n return parseInt(v) << 16 >>> 16;\n case $kindUint32:\n case $kindUintptr:\n return parseInt(v) >>> 0;\n case $kindInt64:\n case $kindUint64:\n return new t(0, v);\n case $kindFloat32:\n case $kindFloat64:\n return parseFloat(v);\n case $kindArray:\n if (v.length !== t.len) {\n $throwRuntimeError(\"got array with wrong size from JavaScript native\");\n }\n return $mapArray(v, function(e) { return $internalize(e, t.elem); });\n case $kindFunc:\n return function() {\n var args = [];\n for (var i = 0; i < t.params.length; i++) {\n if (t.variadic && i === t.params.length - 1) {\n var vt = t.params[i].elem, varargs = arguments[i];\n for (var j = 0; j < varargs.$length; j++) {\n args.push($externalize(varargs.$array[varargs.$offset + j], vt));\n }\n break;\n }\n args.push($externalize(arguments[i], t.params[i]));\n }\n var result = v.apply(recv, args);\n switch (t.results.length) {\n case 0:\n return;\n case 1:\n return $internalize(result, t.results[0]);\n default:\n for (var i = 0; i < t.results.length; i++) {\n result[i] = $internalize(result[i], t.results[i]);\n }\n return result;\n }\n };\n case $kindInterface:\n if (t.methods.length !== 0) {\n $throwRuntimeError(\"cannot internalize \" + t.string);\n }\n if (v === null) {\n return $ifaceNil;\n }\n if (v === undefined) {\n return new $jsObjectPtr(undefined);\n }\n switch (v.constructor) {\n case Int8Array:\n return new ($sliceType($Int8))(v);\n case Int16Array:\n return new ($sliceType($Int16))(v);\n case Int32Array:\n return new ($sliceType($Int))(v);\n case Uint8Array:\n return new ($sliceType($Uint8))(v);\n case Uint16Array:\n return new ($sliceType($Uint16))(v);\n case Uint32Array:\n return new ($sliceType($Uint))(v);\n case Float32Array:\n return new ($sliceType($Float32))(v);\n case Float64Array:\n return new ($sliceType($Float64))(v);\n case Array:\n return $internalize(v, $sliceType($emptyInterface));\n case Boolean:\n return new $Bool(!!v);\n case Date:\n if (timePkg === undefined) {\n /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */\n return new $jsObjectPtr(v);\n }\n return new timePkg.Time($internalize(v, timePkg.Time));\n case Function:\n var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true);\n return new funcType($internalize(v, funcType));\n case Number:\n return new $Float64(parseFloat(v));\n case String:\n return new $String($internalize(v, $String));\n default:\n if ($global.Node && v instanceof $global.Node) {\n return new $jsObjectPtr(v);\n }\n var mapType = $mapType($String, $emptyInterface);\n return new mapType($internalize(v, mapType));\n }\n case $kindMap:\n var m = {};\n var keys = $keys(v);\n for (var i = 0; i < keys.length; i++) {\n var k = $internalize(keys[i], t.key);\n m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) };\n }\n return m;\n case $kindPtr:\n if (t.elem.kind === $kindStruct) {\n return $internalize(v, t.elem);\n }\n case $kindSlice:\n return new t($mapArray(v, function(e) { return $internalize(e, t.elem); }));\n case $kindString:\n v = String(v);\n if ($isASCII(v)) {\n return v;\n }\n var s = \"\";\n var i = 0;\n while (i < v.length) {\n var h = v.charCodeAt(i);\n if (0xD800 <= h && h <= 0xDBFF) {\n var l = v.charCodeAt(i + 1);\n var c = (h - 0xD800) * 0x400 + l - 0xDC00 + 0x10000;\n s += $encodeRune(c);\n i += 2;\n continue;\n }\n s += $encodeRune(h);\n i++;\n }\n return s;\n case $kindStruct:\n var noJsObject = {};\n var searchJsObject = function(t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n if (t === $jsObjectPtr.elem) {\n $throwRuntimeError(\"cannot internalize js.Object, use *js.Object instead\");\n }\n switch (t.kind) {\n case $kindPtr:\n return searchJsObject(t.elem);\n case $kindStruct:\n var f = t.fields[0];\n var o = searchJsObject(f.typ);\n if (o !== noJsObject) {\n var n = new t.ptr();\n n[f.prop] = o;\n return n;\n }\n return noJsObject;\n default:\n return noJsObject;\n }\n };\n var o = searchJsObject(t);\n if (o !== noJsObject) {\n return o;\n }\n }\n $throwRuntimeError(\"cannot internalize \" + t.string);\n};\n\n/* $isASCII reports whether string s contains only ASCII characters. */\nvar $isASCII = function(s) {\n for (var i = 0; i < s.length; i++) {\n if (s.charCodeAt(i) >= 128) {\n return false;\n }\n }\n return true;\n};\n" +const Prelude = "Error.stackTraceLimit = Infinity;\n\nvar $global, $module;\nif (typeof window !== \"undefined\") {\n /* web page */\n $global = window;\n} else if (typeof self !== \"undefined\") {\n /* web worker */\n $global = self;\n} else if (typeof global !== \"undefined\") {\n /* Node.js */\n $global = global;\n $global.require = require;\n} else {\n /* others (e.g. Nashorn) */\n $global = this;\n}\n\nif ($global === undefined || $global.Array === undefined) {\n throw new Error(\"no global object found\");\n}\nif (typeof module !== \"undefined\") {\n $module = module;\n}\n\nvar $packages = {},\n $idCounter = 0;\nvar $keys = function(m) {\n return m ? Object.keys(m) : [];\n};\nvar $flushConsole = function() {};\nvar $throwRuntimeError; /* set by package \"runtime\" */\nvar $throwNilPointerError = function() {\n $throwRuntimeError(\"invalid memory address or nil pointer dereference\");\n};\nvar $call = function(fn, rcvr, args) {\n return fn.apply(rcvr, args);\n};\nvar $makeFunc = function(fn) {\n return function() {\n return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface);\n };\n};\nvar $unused = function(v) {};\n\nvar $mapArray = function(array, f) {\n var newArray = new array.constructor(array.length);\n for (var i = 0; i < array.length; i++) {\n newArray[i] = f(array[i]);\n }\n return newArray;\n};\n\nvar $methodVal = function(recv, name) {\n var vals = recv.$methodVals || {};\n recv.$methodVals = vals; /* noop for primitives */\n var f = vals[name];\n if (f !== undefined) {\n return f;\n }\n var method = recv[name];\n f = function() {\n $stackDepthOffset--;\n try {\n return method.apply(recv, arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n vals[name] = f;\n return f;\n};\n\nvar $methodExpr = function(typ, name) {\n var method = typ.prototype[name];\n if (method.$expr === undefined) {\n method.$expr = function() {\n $stackDepthOffset--;\n try {\n if (typ.wrapped) {\n arguments[0] = new typ(arguments[0]);\n }\n return Function.call.apply(method, arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n }\n return method.$expr;\n};\n\nvar $ifaceMethodExprs = {};\nvar $ifaceMethodExpr = function(name) {\n var expr = $ifaceMethodExprs[\"$\" + name];\n if (expr === undefined) {\n expr = $ifaceMethodExprs[\"$\" + name] = function() {\n $stackDepthOffset--;\n try {\n return Function.call.apply(arguments[0][name], arguments);\n } finally {\n $stackDepthOffset++;\n }\n };\n }\n return expr;\n};\n\nvar $subslice = function(slice, low, high, max) {\n if (high === undefined) {\n high = slice.$length;\n }\n if (max === undefined) {\n max = slice.$capacity;\n }\n if (low < 0 || high < low || max < high || high > slice.$capacity || max > slice.$capacity) {\n $throwRuntimeError(\"slice bounds out of range\");\n }\n var s = new slice.constructor(slice.$array);\n s.$offset = slice.$offset + low;\n s.$length = high - low;\n s.$capacity = max - low;\n return s;\n};\n\nvar $substring = function(str, low, high) {\n if (low < 0 || high < low || high > str.length) {\n $throwRuntimeError(\"slice bounds out of range\");\n }\n return str.substring(low, high);\n};\n\nvar $sliceToArray = function(slice) {\n if (slice.$array.constructor !== Array) {\n return slice.$array.subarray(slice.$offset, slice.$offset + slice.$length);\n }\n return slice.$array.slice(slice.$offset, slice.$offset + slice.$length);\n};\n\nvar $decodeRune = function(str, pos) {\n var c0 = str.charCodeAt(pos);\n\n if (c0 < 0x80) {\n return [c0, 1];\n }\n\n if (c0 !== c0 || c0 < 0xc0) {\n return [0xfffd, 1];\n }\n\n var c1 = str.charCodeAt(pos + 1);\n if (c1 !== c1 || c1 < 0x80 || 0xc0 <= c1) {\n return [0xfffd, 1];\n }\n\n if (c0 < 0xe0) {\n var r = ((c0 & 0x1f) << 6) | (c1 & 0x3f);\n if (r <= 0x7f) {\n return [0xfffd, 1];\n }\n return [r, 2];\n }\n\n var c2 = str.charCodeAt(pos + 2);\n if (c2 !== c2 || c2 < 0x80 || 0xc0 <= c2) {\n return [0xfffd, 1];\n }\n\n if (c0 < 0xf0) {\n var r = ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f);\n if (r <= 0x7ff) {\n return [0xfffd, 1];\n }\n if (0xd800 <= r && r <= 0xdfff) {\n return [0xfffd, 1];\n }\n return [r, 3];\n }\n\n var c3 = str.charCodeAt(pos + 3);\n if (c3 !== c3 || c3 < 0x80 || 0xc0 <= c3) {\n return [0xfffd, 1];\n }\n\n if (c0 < 0xf8) {\n var r = ((c0 & 0x07) << 18) | ((c1 & 0x3f) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f);\n if (r <= 0xffff || 0x10ffff < r) {\n return [0xfffd, 1];\n }\n return [r, 4];\n }\n\n return [0xfffd, 1];\n};\n\nvar $encodeRune = function(r) {\n if (r < 0 || r > 0x10ffff || (0xd800 <= r && r <= 0xdfff)) {\n r = 0xfffd;\n }\n if (r <= 0x7f) {\n return String.fromCharCode(r);\n }\n if (r <= 0x7ff) {\n return String.fromCharCode(0xc0 | (r >> 6), 0x80 | (r & 0x3f));\n }\n if (r <= 0xffff) {\n return String.fromCharCode(0xe0 | (r >> 12), 0x80 | ((r >> 6) & 0x3f), 0x80 | (r & 0x3f));\n }\n return String.fromCharCode(0xf0 | (r >> 18), 0x80 | ((r >> 12) & 0x3f), 0x80 | ((r >> 6) & 0x3f), 0x80 | (r & 0x3f));\n};\n\nvar $stringToBytes = function(str) {\n var array = new Uint8Array(str.length);\n for (var i = 0; i < str.length; i++) {\n array[i] = str.charCodeAt(i);\n }\n return array;\n};\n\nvar $bytesToString = function(slice) {\n if (slice.$length === 0) {\n return \"\";\n }\n var str = \"\";\n for (var i = 0; i < slice.$length; i += 10000) {\n str += String.fromCharCode.apply(undefined, slice.$array.subarray(slice.$offset + i, slice.$offset + Math.min(slice.$length, i + 10000)));\n }\n return str;\n};\n\nvar $stringToRunes = function(str) {\n var array = new Int32Array(str.length);\n var rune,\n j = 0;\n for (var i = 0; i < str.length; i += rune[1], j++) {\n rune = $decodeRune(str, i);\n array[j] = rune[0];\n }\n return array.subarray(0, j);\n};\n\nvar $runesToString = function(slice) {\n if (slice.$length === 0) {\n return \"\";\n }\n var str = \"\";\n for (var i = 0; i < slice.$length; i++) {\n str += $encodeRune(slice.$array[slice.$offset + i]);\n }\n return str;\n};\n\nvar $copyString = function(dst, src) {\n var n = Math.min(src.length, dst.$length);\n for (var i = 0; i < n; i++) {\n dst.$array[dst.$offset + i] = src.charCodeAt(i);\n }\n return n;\n};\n\nvar $copySlice = function(dst, src) {\n var n = Math.min(src.$length, dst.$length);\n $copyArray(dst.$array, src.$array, dst.$offset, src.$offset, n, dst.constructor.elem);\n return n;\n};\n\nvar $copyArray = function(dst, src, dstOffset, srcOffset, n, elem) {\n if (n === 0 || (dst === src && dstOffset === srcOffset)) {\n return;\n }\n\n if (src.subarray) {\n dst.set(src.subarray(srcOffset, srcOffset + n), dstOffset);\n return;\n }\n\n switch (elem.kind) {\n case $kindArray:\n case $kindStruct:\n if (dst === src && dstOffset > srcOffset) {\n for (var i = n - 1; i >= 0; i--) {\n elem.copy(dst[dstOffset + i], src[srcOffset + i]);\n }\n return;\n }\n for (var i = 0; i < n; i++) {\n elem.copy(dst[dstOffset + i], src[srcOffset + i]);\n }\n return;\n }\n\n if (dst === src && dstOffset > srcOffset) {\n for (var i = n - 1; i >= 0; i--) {\n dst[dstOffset + i] = src[srcOffset + i];\n }\n return;\n }\n for (var i = 0; i < n; i++) {\n dst[dstOffset + i] = src[srcOffset + i];\n }\n};\n\nvar $clone = function(src, type) {\n var clone = type.zero();\n type.copy(clone, src);\n return clone;\n};\n\nvar $pointerOfStructConversion = function(obj, type) {\n if (obj.$proxies === undefined) {\n obj.$proxies = {};\n obj.$proxies[obj.constructor.string] = obj;\n }\n var proxy = obj.$proxies[type.string];\n if (proxy === undefined) {\n var properties = {};\n for (var i = 0; i < type.elem.fields.length; i++) {\n (function(fieldProp) {\n properties[fieldProp] = {\n get: function() {\n return obj[fieldProp];\n },\n set: function(value) {\n obj[fieldProp] = value;\n },\n };\n })(type.elem.fields[i].prop);\n }\n proxy = Object.create(type.prototype, properties);\n proxy.$val = proxy;\n obj.$proxies[type.string] = proxy;\n proxy.$proxies = obj.$proxies;\n }\n return proxy;\n};\n\nvar $append = function(slice) {\n return $internalAppend(slice, arguments, 1, arguments.length - 1);\n};\n\nvar $appendSlice = function(slice, toAppend) {\n if (toAppend.constructor === String) {\n var bytes = $stringToBytes(toAppend);\n return $internalAppend(slice, bytes, 0, bytes.length);\n }\n return $internalAppend(slice, toAppend.$array, toAppend.$offset, toAppend.$length);\n};\n\nvar $internalAppend = function(slice, array, offset, length) {\n if (length === 0) {\n return slice;\n }\n\n var newArray = slice.$array;\n var newOffset = slice.$offset;\n var newLength = slice.$length + length;\n var newCapacity = slice.$capacity;\n\n if (newLength > newCapacity) {\n newOffset = 0;\n newCapacity = Math.max(newLength, slice.$capacity < 1024 ? slice.$capacity * 2 : Math.floor(slice.$capacity * 5 / 4));\n\n if (slice.$array.constructor === Array) {\n newArray = slice.$array.slice(slice.$offset, slice.$offset + slice.$length);\n newArray.length = newCapacity;\n var zero = slice.constructor.elem.zero;\n for (var i = slice.$length; i < newCapacity; i++) {\n newArray[i] = zero();\n }\n } else {\n newArray = new slice.$array.constructor(newCapacity);\n newArray.set(slice.$array.subarray(slice.$offset, slice.$offset + slice.$length));\n }\n }\n\n $copyArray(newArray, array, newOffset + slice.$length, offset, length, slice.constructor.elem);\n\n var newSlice = new slice.constructor(newArray);\n newSlice.$offset = newOffset;\n newSlice.$length = newLength;\n newSlice.$capacity = newCapacity;\n return newSlice;\n};\n\nvar $equal = function(a, b, type) {\n if (type === $jsObjectPtr) {\n return a === b;\n }\n switch (type.kind) {\n case $kindComplex64:\n case $kindComplex128:\n return a.$real === b.$real && a.$imag === b.$imag;\n case $kindInt64:\n case $kindUint64:\n return a.$high === b.$high && a.$low === b.$low;\n case $kindArray:\n if (a.length !== b.length) {\n return false;\n }\n for (var i = 0; i < a.length; i++) {\n if (!$equal(a[i], b[i], type.elem)) {\n return false;\n }\n }\n return true;\n case $kindStruct:\n for (var i = 0; i < type.fields.length; i++) {\n var f = type.fields[i];\n if (!$equal(a[f.prop], b[f.prop], f.typ)) {\n return false;\n }\n }\n return true;\n case $kindInterface:\n return $interfaceIsEqual(a, b);\n default:\n return a === b;\n }\n};\n\nvar $interfaceIsEqual = function(a, b) {\n if (a === $ifaceNil || b === $ifaceNil) {\n return a === b;\n }\n if (a.constructor !== b.constructor) {\n return false;\n }\n if (a.constructor === $jsObjectPtr) {\n return a.object === b.object;\n }\n if (!a.constructor.comparable) {\n $throwRuntimeError(\"comparing uncomparable type \" + a.constructor.string);\n }\n return $equal(a.$val, b.$val, a.constructor);\n};\nvar $min = Math.min;\nvar $mod = function(x, y) {\n return x % y;\n};\nvar $parseInt = parseInt;\nvar $parseFloat = function(f) {\n if (f !== undefined && f !== null && f.constructor === Number) {\n return f;\n }\n return parseFloat(f);\n};\n\nvar $froundBuf = new Float32Array(1);\nvar $fround =\n Math.fround ||\n function(f) {\n $froundBuf[0] = f;\n return $froundBuf[0];\n };\n\nvar $imul =\n Math.imul ||\n function(a, b) {\n var ah = (a >>> 16) & 0xffff;\n var al = a & 0xffff;\n var bh = (b >>> 16) & 0xffff;\n var bl = b & 0xffff;\n return (al * bl + (((ah * bl + al * bh) << 16) >>> 0)) >> 0;\n };\n\nvar $floatKey = function(f) {\n if (f !== f) {\n $idCounter++;\n return \"NaN$\" + $idCounter;\n }\n return String(f);\n};\n\nvar $flatten64 = function(x) {\n return x.$high * 4294967296 + x.$low;\n};\n\nvar $shiftLeft64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor((x.$high << y) | (x.$low >>> (32 - y)), (x.$low << y) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(x.$low << (y - 32), 0);\n }\n return new x.constructor(0, 0);\n};\n\nvar $shiftRightInt64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high >> y, ((x.$low >>> y) | (x.$high << (32 - y))) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(x.$high >> 31, (x.$high >> (y - 32)) >>> 0);\n }\n if (x.$high < 0) {\n return new x.constructor(-1, 4294967295);\n }\n return new x.constructor(0, 0);\n};\n\nvar $shiftRightUint64 = function(x, y) {\n if (y === 0) {\n return x;\n }\n if (y < 32) {\n return new x.constructor(x.$high >>> y, ((x.$low >>> y) | (x.$high << (32 - y))) >>> 0);\n }\n if (y < 64) {\n return new x.constructor(0, x.$high >>> (y - 32));\n }\n return new x.constructor(0, 0);\n};\n\nvar $mul64 = function(x, y) {\n var high = 0,\n low = 0;\n if ((y.$low & 1) !== 0) {\n high = x.$high;\n low = x.$low;\n }\n for (var i = 1; i < 32; i++) {\n if ((y.$low & (1 << i)) !== 0) {\n high += (x.$high << i) | (x.$low >>> (32 - i));\n low += (x.$low << i) >>> 0;\n }\n }\n for (var i = 0; i < 32; i++) {\n if ((y.$high & (1 << i)) !== 0) {\n high += x.$low << i;\n }\n }\n return new x.constructor(high, low);\n};\n\nvar $div64 = function(x, y, returnRemainder) {\n if (y.$high === 0 && y.$low === 0) {\n $throwRuntimeError(\"integer divide by zero\");\n }\n\n var s = 1;\n var rs = 1;\n\n var xHigh = x.$high;\n var xLow = x.$low;\n if (xHigh < 0) {\n s = -1;\n rs = -1;\n xHigh = -xHigh;\n if (xLow !== 0) {\n xHigh--;\n xLow = 4294967296 - xLow;\n }\n }\n\n var yHigh = y.$high;\n var yLow = y.$low;\n if (y.$high < 0) {\n s *= -1;\n yHigh = -yHigh;\n if (yLow !== 0) {\n yHigh--;\n yLow = 4294967296 - yLow;\n }\n }\n\n var high = 0,\n low = 0,\n n = 0;\n while (yHigh < 2147483648 && (xHigh > yHigh || (xHigh === yHigh && xLow > yLow))) {\n yHigh = ((yHigh << 1) | (yLow >>> 31)) >>> 0;\n yLow = (yLow << 1) >>> 0;\n n++;\n }\n for (var i = 0; i <= n; i++) {\n high = (high << 1) | (low >>> 31);\n low = (low << 1) >>> 0;\n if (xHigh > yHigh || (xHigh === yHigh && xLow >= yLow)) {\n xHigh = xHigh - yHigh;\n xLow = xLow - yLow;\n if (xLow < 0) {\n xHigh--;\n xLow += 4294967296;\n }\n low++;\n if (low === 4294967296) {\n high++;\n low = 0;\n }\n }\n yLow = ((yLow >>> 1) | (yHigh << (32 - 1))) >>> 0;\n yHigh = yHigh >>> 1;\n }\n\n if (returnRemainder) {\n return new x.constructor(xHigh * rs, xLow * rs);\n }\n return new x.constructor(high * s, low * s);\n};\n\nvar $divComplex = function(n, d) {\n var ninf = n.$real === Infinity || n.$real === -Infinity || n.$imag === Infinity || n.$imag === -Infinity;\n var dinf = d.$real === Infinity || d.$real === -Infinity || d.$imag === Infinity || d.$imag === -Infinity;\n var nnan = !ninf && (n.$real !== n.$real || n.$imag !== n.$imag);\n var dnan = !dinf && (d.$real !== d.$real || d.$imag !== d.$imag);\n if (nnan || dnan) {\n return new n.constructor(NaN, NaN);\n }\n if (ninf && !dinf) {\n return new n.constructor(Infinity, Infinity);\n }\n if (!ninf && dinf) {\n return new n.constructor(0, 0);\n }\n if (d.$real === 0 && d.$imag === 0) {\n if (n.$real === 0 && n.$imag === 0) {\n return new n.constructor(NaN, NaN);\n }\n return new n.constructor(Infinity, Infinity);\n }\n var a = Math.abs(d.$real);\n var b = Math.abs(d.$imag);\n if (a <= b) {\n var ratio = d.$real / d.$imag;\n var denom = d.$real * ratio + d.$imag;\n return new n.constructor((n.$real * ratio + n.$imag) / denom, (n.$imag * ratio - n.$real) / denom);\n }\n var ratio = d.$imag / d.$real;\n var denom = d.$imag * ratio + d.$real;\n return new n.constructor((n.$imag * ratio + n.$real) / denom, (n.$imag - n.$real * ratio) / denom);\n};\nvar $kindBool = 1;\nvar $kindInt = 2;\nvar $kindInt8 = 3;\nvar $kindInt16 = 4;\nvar $kindInt32 = 5;\nvar $kindInt64 = 6;\nvar $kindUint = 7;\nvar $kindUint8 = 8;\nvar $kindUint16 = 9;\nvar $kindUint32 = 10;\nvar $kindUint64 = 11;\nvar $kindUintptr = 12;\nvar $kindFloat32 = 13;\nvar $kindFloat64 = 14;\nvar $kindComplex64 = 15;\nvar $kindComplex128 = 16;\nvar $kindArray = 17;\nvar $kindChan = 18;\nvar $kindFunc = 19;\nvar $kindInterface = 20;\nvar $kindMap = 21;\nvar $kindPtr = 22;\nvar $kindSlice = 23;\nvar $kindString = 24;\nvar $kindStruct = 25;\nvar $kindUnsafePointer = 26;\n\nvar $methodSynthesizers = [];\nvar $addMethodSynthesizer = function(f) {\n if ($methodSynthesizers === null) {\n f();\n return;\n }\n $methodSynthesizers.push(f);\n};\nvar $synthesizeMethods = function() {\n $methodSynthesizers.forEach(function(f) {\n f();\n });\n $methodSynthesizers = null;\n};\n\nvar $ifaceKeyFor = function(x) {\n if (x === $ifaceNil) {\n return \"nil\";\n }\n var c = x.constructor;\n return c.string + \"$\" + c.keyFor(x.$val);\n};\n\nvar $identity = function(x) {\n return x;\n};\n\nvar $typeIDCounter = 0;\n\nvar $idKey = function(x) {\n if (x.$id === undefined) {\n $idCounter++;\n x.$id = $idCounter;\n }\n return String(x.$id);\n};\n\nvar $newType = function(size, kind, string, named, pkg, exported, constructor) {\n var typ;\n switch (kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindUnsafePointer:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.keyFor = $identity;\n break;\n\n case $kindString:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.keyFor = function(x) {\n return \"$\" + x;\n };\n break;\n\n case $kindFloat32:\n case $kindFloat64:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.keyFor = function(x) {\n return $floatKey(x);\n };\n break;\n\n case $kindInt64:\n typ = function(high, low) {\n this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >> 0;\n this.$low = low >>> 0;\n this.$val = this;\n };\n typ.keyFor = function(x) {\n return x.$high + \"$\" + x.$low;\n };\n break;\n\n case $kindUint64:\n typ = function(high, low) {\n this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >>> 0;\n this.$low = low >>> 0;\n this.$val = this;\n };\n typ.keyFor = function(x) {\n return x.$high + \"$\" + x.$low;\n };\n break;\n\n case $kindComplex64:\n typ = function(real, imag) {\n this.$real = $fround(real);\n this.$imag = $fround(imag);\n this.$val = this;\n };\n typ.keyFor = function(x) {\n return x.$real + \"$\" + x.$imag;\n };\n break;\n\n case $kindComplex128:\n typ = function(real, imag) {\n this.$real = real;\n this.$imag = imag;\n this.$val = this;\n };\n typ.keyFor = function(x) {\n return x.$real + \"$\" + x.$imag;\n };\n break;\n\n case $kindArray:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.ptr = $newType(4, $kindPtr, \"*\" + string, false, \"\", false, function(array) {\n this.$get = function() {\n return array;\n };\n this.$set = function(v) {\n typ.copy(this, v);\n };\n this.$val = array;\n });\n typ.init = function(elem, len) {\n typ.elem = elem;\n typ.len = len;\n typ.comparable = elem.comparable;\n typ.keyFor = function(x) {\n return Array.prototype.join.call(\n $mapArray(x, function(e) {\n return String(elem.keyFor(e))\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\$/g, \"\\\\$\");\n }),\n \"$\"\n );\n };\n typ.copy = function(dst, src) {\n $copyArray(dst, src, 0, 0, src.length, elem);\n };\n typ.ptr.init(typ);\n Object.defineProperty(typ.ptr.nil, \"nilCheck\", { get: $throwNilPointerError });\n };\n break;\n\n case $kindChan:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.keyFor = $idKey;\n typ.init = function(elem, sendOnly, recvOnly) {\n typ.elem = elem;\n typ.sendOnly = sendOnly;\n typ.recvOnly = recvOnly;\n };\n break;\n\n case $kindFunc:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.init = function(params, results, variadic) {\n typ.params = params;\n typ.results = results;\n typ.variadic = variadic;\n typ.comparable = false;\n };\n break;\n\n case $kindInterface:\n typ = { implementedBy: {}, missingMethodFor: {} };\n typ.keyFor = $ifaceKeyFor;\n typ.init = function(methods) {\n typ.methods = methods;\n methods.forEach(function(m) {\n $ifaceNil[m.prop] = $throwNilPointerError;\n });\n };\n break;\n\n case $kindMap:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.init = function(key, elem) {\n typ.key = key;\n typ.elem = elem;\n typ.comparable = false;\n };\n break;\n\n case $kindPtr:\n typ =\n constructor ||\n function(getter, setter, target) {\n this.$get = getter;\n this.$set = setter;\n this.$target = target;\n this.$val = this;\n };\n typ.keyFor = $idKey;\n typ.init = function(elem) {\n typ.elem = elem;\n typ.wrapped = elem.kind === $kindArray;\n typ.nil = new typ($throwNilPointerError, $throwNilPointerError);\n };\n break;\n\n case $kindSlice:\n typ = function(array) {\n if (array.constructor !== typ.nativeArray) {\n array = new typ.nativeArray(array);\n }\n this.$array = array;\n this.$offset = 0;\n this.$length = array.length;\n this.$capacity = array.length;\n this.$val = this;\n };\n typ.init = function(elem) {\n typ.elem = elem;\n typ.comparable = false;\n typ.nativeArray = $nativeArray(elem.kind);\n typ.nil = new typ([]);\n };\n break;\n\n case $kindStruct:\n typ = function(v) {\n this.$val = v;\n };\n typ.wrapped = true;\n typ.ptr = $newType(4, $kindPtr, \"*\" + string, false, pkg, exported, constructor);\n typ.ptr.elem = typ;\n typ.ptr.prototype.$get = function() {\n return this;\n };\n typ.ptr.prototype.$set = function(v) {\n typ.copy(this, v);\n };\n typ.init = function(pkgPath, fields) {\n typ.pkgPath = pkgPath;\n typ.fields = fields;\n fields.forEach(function(f) {\n if (!f.typ.comparable) {\n typ.comparable = false;\n }\n });\n typ.keyFor = function(x) {\n var val = x.$val;\n return $mapArray(fields, function(f) {\n return String(f.typ.keyFor(val[f.prop]))\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\\$/g, \"\\\\$\");\n }).join(\"$\");\n };\n typ.copy = function(dst, src) {\n for (var i = 0; i < fields.length; i++) {\n var f = fields[i];\n switch (f.typ.kind) {\n case $kindArray:\n case $kindStruct:\n f.typ.copy(dst[f.prop], src[f.prop]);\n continue;\n default:\n dst[f.prop] = src[f.prop];\n continue;\n }\n }\n };\n /* nil value */\n var properties = {};\n fields.forEach(function(f) {\n properties[f.prop] = { get: $throwNilPointerError, set: $throwNilPointerError };\n });\n typ.ptr.nil = Object.create(constructor.prototype, properties);\n typ.ptr.nil.$val = typ.ptr.nil;\n /* methods for embedded fields */\n $addMethodSynthesizer(function() {\n var synthesizeMethod = function(target, m, f) {\n if (target.prototype[m.prop] !== undefined) {\n return;\n }\n target.prototype[m.prop] = function() {\n var v = this.$val[f.prop];\n if (f.typ === $jsObjectPtr) {\n v = new $jsObjectPtr(v);\n }\n if (v.$val === undefined) {\n v = new f.typ(v);\n }\n return v[m.prop].apply(v, arguments);\n };\n };\n fields.forEach(function(f) {\n if (f.anonymous) {\n $methodSet(f.typ).forEach(function(m) {\n synthesizeMethod(typ, m, f);\n synthesizeMethod(typ.ptr, m, f);\n });\n $methodSet($ptrType(f.typ)).forEach(function(m) {\n synthesizeMethod(typ.ptr, m, f);\n });\n }\n });\n });\n };\n break;\n\n default:\n $panic(new $String(\"invalid kind: \" + kind));\n }\n\n switch (kind) {\n case $kindBool:\n case $kindMap:\n typ.zero = function() {\n return false;\n };\n break;\n\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindUnsafePointer:\n case $kindFloat32:\n case $kindFloat64:\n typ.zero = function() {\n return 0;\n };\n break;\n\n case $kindString:\n typ.zero = function() {\n return \"\";\n };\n break;\n\n case $kindInt64:\n case $kindUint64:\n case $kindComplex64:\n case $kindComplex128:\n var zero = new typ(0, 0);\n typ.zero = function() {\n return zero;\n };\n break;\n\n case $kindPtr:\n case $kindSlice:\n typ.zero = function() {\n return typ.nil;\n };\n break;\n\n case $kindChan:\n typ.zero = function() {\n return $chanNil;\n };\n break;\n\n case $kindFunc:\n typ.zero = function() {\n return $throwNilPointerError;\n };\n break;\n\n case $kindInterface:\n typ.zero = function() {\n return $ifaceNil;\n };\n break;\n\n case $kindArray:\n typ.zero = function() {\n var arrayClass = $nativeArray(typ.elem.kind);\n if (arrayClass !== Array) {\n return new arrayClass(typ.len);\n }\n var array = new Array(typ.len);\n for (var i = 0; i < typ.len; i++) {\n array[i] = typ.elem.zero();\n }\n return array;\n };\n break;\n\n case $kindStruct:\n typ.zero = function() {\n return new typ.ptr();\n };\n break;\n\n default:\n $panic(new $String(\"invalid kind: \" + kind));\n }\n\n typ.id = $typeIDCounter;\n $typeIDCounter++;\n typ.size = size;\n typ.kind = kind;\n typ.string = string;\n typ.named = named;\n typ.pkg = pkg;\n typ.exported = exported;\n typ.methods = [];\n typ.methodSetCache = null;\n typ.comparable = true;\n return typ;\n};\n\nvar $methodSet = function(typ) {\n if (typ.methodSetCache !== null) {\n return typ.methodSetCache;\n }\n var base = {};\n\n var isPtr = typ.kind === $kindPtr;\n if (isPtr && typ.elem.kind === $kindInterface) {\n typ.methodSetCache = [];\n return [];\n }\n\n var current = [{ typ: isPtr ? typ.elem : typ, indirect: isPtr }];\n\n var seen = {};\n\n while (current.length > 0) {\n var next = [];\n var mset = [];\n\n current.forEach(function(e) {\n if (seen[e.typ.string]) {\n return;\n }\n seen[e.typ.string] = true;\n\n if (e.typ.named) {\n mset = mset.concat(e.typ.methods);\n if (e.indirect) {\n mset = mset.concat($ptrType(e.typ).methods);\n }\n }\n\n switch (e.typ.kind) {\n case $kindStruct:\n e.typ.fields.forEach(function(f) {\n if (f.anonymous) {\n var fTyp = f.typ;\n var fIsPtr = fTyp.kind === $kindPtr;\n next.push({ typ: fIsPtr ? fTyp.elem : fTyp, indirect: e.indirect || fIsPtr });\n }\n });\n break;\n\n case $kindInterface:\n mset = mset.concat(e.typ.methods);\n break;\n }\n });\n\n mset.forEach(function(m) {\n if (base[m.name] === undefined) {\n base[m.name] = m;\n }\n });\n\n current = next;\n }\n\n typ.methodSetCache = [];\n Object.keys(base)\n .sort()\n .forEach(function(name) {\n typ.methodSetCache.push(base[name]);\n });\n return typ.methodSetCache;\n};\n\nvar $Bool = $newType(1, $kindBool, \"bool\", true, \"\", false, null);\nvar $Int = $newType(4, $kindInt, \"int\", true, \"\", false, null);\nvar $Int8 = $newType(1, $kindInt8, \"int8\", true, \"\", false, null);\nvar $Int16 = $newType(2, $kindInt16, \"int16\", true, \"\", false, null);\nvar $Int32 = $newType(4, $kindInt32, \"int32\", true, \"\", false, null);\nvar $Int64 = $newType(8, $kindInt64, \"int64\", true, \"\", false, null);\nvar $Uint = $newType(4, $kindUint, \"uint\", true, \"\", false, null);\nvar $Uint8 = $newType(1, $kindUint8, \"uint8\", true, \"\", false, null);\nvar $Uint16 = $newType(2, $kindUint16, \"uint16\", true, \"\", false, null);\nvar $Uint32 = $newType(4, $kindUint32, \"uint32\", true, \"\", false, null);\nvar $Uint64 = $newType(8, $kindUint64, \"uint64\", true, \"\", false, null);\nvar $Uintptr = $newType(4, $kindUintptr, \"uintptr\", true, \"\", false, null);\nvar $Float32 = $newType(4, $kindFloat32, \"float32\", true, \"\", false, null);\nvar $Float64 = $newType(8, $kindFloat64, \"float64\", true, \"\", false, null);\nvar $Complex64 = $newType(8, $kindComplex64, \"complex64\", true, \"\", false, null);\nvar $Complex128 = $newType(16, $kindComplex128, \"complex128\", true, \"\", false, null);\nvar $String = $newType(8, $kindString, \"string\", true, \"\", false, null);\nvar $UnsafePointer = $newType(4, $kindUnsafePointer, \"unsafe.Pointer\", true, \"\", false, null);\n\nvar $nativeArray = function(elemKind) {\n switch (elemKind) {\n case $kindInt:\n return Int32Array;\n case $kindInt8:\n return Int8Array;\n case $kindInt16:\n return Int16Array;\n case $kindInt32:\n return Int32Array;\n case $kindUint:\n return Uint32Array;\n case $kindUint8:\n return Uint8Array;\n case $kindUint16:\n return Uint16Array;\n case $kindUint32:\n return Uint32Array;\n case $kindUintptr:\n return Uint32Array;\n case $kindFloat32:\n return Float32Array;\n case $kindFloat64:\n return Float64Array;\n default:\n return Array;\n }\n};\nvar $toNativeArray = function(elemKind, array) {\n var nativeArray = $nativeArray(elemKind);\n if (nativeArray === Array) {\n return array;\n }\n return new nativeArray(array);\n};\nvar $arrayTypes = {};\nvar $arrayType = function(elem, len) {\n var typeKey = elem.id + \"$\" + len;\n var typ = $arrayTypes[typeKey];\n if (typ === undefined) {\n typ = $newType(12, $kindArray, \"[\" + len + \"]\" + elem.string, false, \"\", false, null);\n $arrayTypes[typeKey] = typ;\n typ.init(elem, len);\n }\n return typ;\n};\n\nvar $chanType = function(elem, sendOnly, recvOnly) {\n var string = (recvOnly ? \"<-\" : \"\") + \"chan\" + (sendOnly ? \"<- \" : \" \") + elem.string;\n var field = sendOnly ? \"SendChan\" : recvOnly ? \"RecvChan\" : \"Chan\";\n var typ = elem[field];\n if (typ === undefined) {\n typ = $newType(4, $kindChan, string, false, \"\", false, null);\n elem[field] = typ;\n typ.init(elem, sendOnly, recvOnly);\n }\n return typ;\n};\nvar $Chan = function(elem, capacity) {\n if (capacity < 0 || capacity > 2147483647) {\n $throwRuntimeError(\"makechan: size out of range\");\n }\n this.$elem = elem;\n this.$capacity = capacity;\n this.$buffer = [];\n this.$sendQueue = [];\n this.$recvQueue = [];\n this.$closed = false;\n};\nvar $chanNil = new $Chan(null, 0);\n$chanNil.$sendQueue = $chanNil.$recvQueue = {\n length: 0,\n push: function() {},\n shift: function() {\n return undefined;\n },\n indexOf: function() {\n return -1;\n },\n};\n\nvar $funcTypes = {};\nvar $funcType = function(params, results, variadic) {\n var typeKey =\n $mapArray(params, function(p) {\n return p.id;\n }).join(\",\") +\n \"$\" +\n $mapArray(results, function(r) {\n return r.id;\n }).join(\",\") +\n \"$\" +\n variadic;\n var typ = $funcTypes[typeKey];\n if (typ === undefined) {\n var paramTypes = $mapArray(params, function(p) {\n return p.string;\n });\n if (variadic) {\n paramTypes[paramTypes.length - 1] = \"...\" + paramTypes[paramTypes.length - 1].substr(2);\n }\n var string = \"func(\" + paramTypes.join(\", \") + \")\";\n if (results.length === 1) {\n string += \" \" + results[0].string;\n } else if (results.length > 1) {\n string +=\n \" (\" +\n $mapArray(results, function(r) {\n return r.string;\n }).join(\", \") +\n \")\";\n }\n typ = $newType(4, $kindFunc, string, false, \"\", false, null);\n $funcTypes[typeKey] = typ;\n typ.init(params, results, variadic);\n }\n return typ;\n};\n\nvar $interfaceTypes = {};\nvar $interfaceType = function(methods) {\n var typeKey = $mapArray(methods, function(m) {\n return m.pkg + \",\" + m.name + \",\" + m.typ.id;\n }).join(\"$\");\n var typ = $interfaceTypes[typeKey];\n if (typ === undefined) {\n var string = \"interface {}\";\n if (methods.length !== 0) {\n string =\n \"interface { \" +\n $mapArray(methods, function(m) {\n return (m.pkg !== \"\" ? m.pkg + \".\" : \"\") + m.name + m.typ.string.substr(4);\n }).join(\"; \") +\n \" }\";\n }\n typ = $newType(8, $kindInterface, string, false, \"\", false, null);\n $interfaceTypes[typeKey] = typ;\n typ.init(methods);\n }\n return typ;\n};\nvar $emptyInterface = $interfaceType([]);\nvar $ifaceNil = {};\nvar $error = $newType(8, $kindInterface, \"error\", true, \"\", false, null);\n$error.init([{ prop: \"Error\", name: \"Error\", pkg: \"\", typ: $funcType([], [$String], false) }]);\n\nvar $mapTypes = {};\nvar $mapType = function(key, elem) {\n var typeKey = key.id + \"$\" + elem.id;\n var typ = $mapTypes[typeKey];\n if (typ === undefined) {\n typ = $newType(4, $kindMap, \"map[\" + key.string + \"]\" + elem.string, false, \"\", false, null);\n $mapTypes[typeKey] = typ;\n typ.init(key, elem);\n }\n return typ;\n};\nvar $makeMap = function(keyForFunc, entries) {\n var m = {};\n for (var i = 0; i < entries.length; i++) {\n var e = entries[i];\n m[keyForFunc(e.k)] = e;\n }\n return m;\n};\n\nvar $ptrType = function(elem) {\n var typ = elem.ptr;\n if (typ === undefined) {\n typ = $newType(4, $kindPtr, \"*\" + elem.string, false, \"\", elem.exported, null);\n elem.ptr = typ;\n typ.init(elem);\n }\n return typ;\n};\n\nvar $newDataPointer = function(data, constructor) {\n if (constructor.elem.kind === $kindStruct) {\n return data;\n }\n return new constructor(\n function() {\n return data;\n },\n function(v) {\n data = v;\n }\n );\n};\n\nvar $indexPtr = function(array, index, constructor) {\n array.$ptr = array.$ptr || {};\n return (\n array.$ptr[index] ||\n (array.$ptr[index] = new constructor(\n function() {\n return array[index];\n },\n function(v) {\n array[index] = v;\n }\n ))\n );\n};\n\nvar $sliceType = function(elem) {\n var typ = elem.slice;\n if (typ === undefined) {\n typ = $newType(12, $kindSlice, \"[]\" + elem.string, false, \"\", false, null);\n elem.slice = typ;\n typ.init(elem);\n }\n return typ;\n};\nvar $makeSlice = function(typ, length, capacity) {\n capacity = capacity || length;\n if (length < 0 || length > 2147483647) {\n $throwRuntimeError(\"makeslice: len out of range\");\n }\n if (capacity < 0 || capacity < length || capacity > 2147483647) {\n $throwRuntimeError(\"makeslice: cap out of range\");\n }\n var array = new typ.nativeArray(capacity);\n if (typ.nativeArray === Array) {\n for (var i = 0; i < capacity; i++) {\n array[i] = typ.elem.zero();\n }\n }\n var slice = new typ(array);\n slice.$length = length;\n return slice;\n};\n\nvar $structTypes = {};\nvar $structType = function(pkgPath, fields) {\n var typeKey = $mapArray(fields, function(f) {\n return f.name + \",\" + f.typ.id + \",\" + f.tag;\n }).join(\"$\");\n var typ = $structTypes[typeKey];\n if (typ === undefined) {\n var string =\n \"struct { \" +\n $mapArray(fields, function(f) {\n return f.name + \" \" + f.typ.string + (f.tag !== \"\" ? ' \"' + f.tag.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"') + '\"' : \"\");\n }).join(\"; \") +\n \" }\";\n if (fields.length === 0) {\n string = \"struct {}\";\n }\n typ = $newType(0, $kindStruct, string, false, \"\", false, function() {\n this.$val = this;\n for (var i = 0; i < fields.length; i++) {\n var f = fields[i];\n var arg = arguments[i];\n this[f.prop] = arg !== undefined ? arg : f.typ.zero();\n }\n });\n $structTypes[typeKey] = typ;\n typ.init(pkgPath, fields);\n }\n return typ;\n};\n\nvar $assertType = function(value, type, returnTuple) {\n var isInterface = type.kind === $kindInterface,\n ok,\n missingMethod = \"\";\n if (value === $ifaceNil) {\n ok = false;\n } else if (!isInterface) {\n ok = value.constructor === type;\n } else {\n var valueTypeString = value.constructor.string;\n ok = type.implementedBy[valueTypeString];\n if (ok === undefined) {\n ok = true;\n var valueMethodSet = $methodSet(value.constructor);\n var interfaceMethods = type.methods;\n for (var i = 0; i < interfaceMethods.length; i++) {\n var tm = interfaceMethods[i];\n var found = false;\n for (var j = 0; j < valueMethodSet.length; j++) {\n var vm = valueMethodSet[j];\n if (vm.name === tm.name && vm.pkg === tm.pkg && vm.typ === tm.typ) {\n found = true;\n break;\n }\n }\n if (!found) {\n ok = false;\n type.missingMethodFor[valueTypeString] = tm.name;\n break;\n }\n }\n type.implementedBy[valueTypeString] = ok;\n }\n if (!ok) {\n missingMethod = type.missingMethodFor[valueTypeString];\n }\n }\n\n if (!ok) {\n if (returnTuple) {\n return [type.zero(), false];\n }\n $panic(new $packages[\"runtime\"].TypeAssertionError.ptr(\"\", value === $ifaceNil ? \"\" : value.constructor.string, type.string, missingMethod));\n }\n\n if (!isInterface) {\n value = value.$val;\n }\n if (type === $jsObjectPtr) {\n value = value.object;\n }\n return returnTuple ? [value, true] : value;\n};\nvar $stackDepthOffset = 0;\nvar $getStackDepth = function() {\n var err = new Error();\n if (err.stack === undefined) {\n return undefined;\n }\n return $stackDepthOffset + err.stack.split(\"\\n\").length;\n};\n\nvar $panicStackDepth = null,\n $panicValue;\nvar $callDeferred = function(deferred, jsErr, fromPanic) {\n if (!fromPanic && deferred !== null && deferred.index >= $curGoroutine.deferStack.length) {\n throw jsErr;\n }\n if (jsErr !== null) {\n var newErr = null;\n try {\n $curGoroutine.deferStack.push(deferred);\n $panic(new $jsErrorPtr(jsErr));\n } catch (err) {\n newErr = err;\n }\n $curGoroutine.deferStack.pop();\n $callDeferred(deferred, newErr);\n return;\n }\n if ($curGoroutine.asleep) {\n return;\n }\n\n $stackDepthOffset--;\n var outerPanicStackDepth = $panicStackDepth;\n var outerPanicValue = $panicValue;\n\n var localPanicValue = $curGoroutine.panicStack.pop();\n if (localPanicValue !== undefined) {\n $panicStackDepth = $getStackDepth();\n $panicValue = localPanicValue;\n }\n\n try {\n while (true) {\n if (deferred === null) {\n deferred = $curGoroutine.deferStack[$curGoroutine.deferStack.length - 1];\n if (deferred === undefined) {\n /* The panic reached the top of the stack. Clear it and throw it as a JavaScript error. */\n $panicStackDepth = null;\n if (localPanicValue.Object instanceof Error) {\n throw localPanicValue.Object;\n }\n var msg;\n if (localPanicValue.constructor === $String) {\n msg = localPanicValue.$val;\n } else if (localPanicValue.Error !== undefined) {\n msg = localPanicValue.Error();\n } else if (localPanicValue.String !== undefined) {\n msg = localPanicValue.String();\n } else {\n msg = localPanicValue;\n }\n throw new Error(msg);\n }\n }\n var call = deferred.pop();\n if (call === undefined) {\n $curGoroutine.deferStack.pop();\n if (localPanicValue !== undefined) {\n deferred = null;\n continue;\n }\n return;\n }\n var r = call[0].apply(call[2], call[1]);\n if (r && r.$blk !== undefined) {\n deferred.push([r.$blk, [], r]);\n if (fromPanic) {\n throw null;\n }\n return;\n }\n\n if (localPanicValue !== undefined && $panicStackDepth === null) {\n throw null; /* error was recovered */\n }\n }\n } finally {\n if (localPanicValue !== undefined) {\n if ($panicStackDepth !== null) {\n $curGoroutine.panicStack.push(localPanicValue);\n }\n $panicStackDepth = outerPanicStackDepth;\n $panicValue = outerPanicValue;\n }\n $stackDepthOffset++;\n }\n};\n\nvar $panic = function(value) {\n $curGoroutine.panicStack.push(value);\n $callDeferred(null, null, true);\n};\nvar $recover = function() {\n if ($panicStackDepth === null || ($panicStackDepth !== undefined && $panicStackDepth !== $getStackDepth() - 2)) {\n return $ifaceNil;\n }\n $panicStackDepth = null;\n return $panicValue;\n};\nvar $throw = function(err) {\n throw err;\n};\n\nvar $noGoroutine = {\n asleep: false,\n exit: false,\n deferStack: [],\n panicStack: [],\n};\nvar $curGoroutine = $noGoroutine,\n $totalGoroutines = 0,\n $awakeGoroutines = 0,\n $checkForDeadlock = true;\nvar $mainFinished = false;\nvar $go = function(fun, args) {\n $totalGoroutines++;\n $awakeGoroutines++;\n var $goroutine = function() {\n try {\n $curGoroutine = $goroutine;\n var r = fun.apply(undefined, args);\n if (r && r.$blk !== undefined) {\n fun = function() {\n return r.$blk();\n };\n args = [];\n return;\n }\n $goroutine.exit = true;\n } catch (err) {\n if (!$goroutine.exit) {\n throw err;\n }\n } finally {\n $curGoroutine = $noGoroutine;\n if ($goroutine.exit) {\n /* also set by runtime.Goexit() */\n $totalGoroutines--;\n $goroutine.asleep = true;\n }\n if ($goroutine.asleep) {\n $awakeGoroutines--;\n if (!$mainFinished && $awakeGoroutines === 0 && $checkForDeadlock) {\n console.error(\"fatal error: all goroutines are asleep - deadlock!\");\n if ($global.process !== undefined) {\n $global.process.exit(2);\n }\n }\n }\n }\n };\n $goroutine.asleep = false;\n $goroutine.exit = false;\n $goroutine.deferStack = [];\n $goroutine.panicStack = [];\n $schedule($goroutine);\n};\n\nvar $scheduled = [];\nvar $runScheduled = function() {\n try {\n var r;\n while ((r = $scheduled.shift()) !== undefined) {\n r();\n }\n } finally {\n if ($scheduled.length > 0) {\n setTimeout($runScheduled, 0);\n }\n }\n};\n\nvar $schedule = function(goroutine) {\n if (goroutine.asleep) {\n goroutine.asleep = false;\n $awakeGoroutines++;\n }\n $scheduled.push(goroutine);\n if ($curGoroutine === $noGoroutine) {\n $runScheduled();\n }\n};\n\nvar $setTimeout = function(f, t) {\n $awakeGoroutines++;\n return setTimeout(function() {\n $awakeGoroutines--;\n f();\n }, t);\n};\n\nvar $block = function() {\n if ($curGoroutine === $noGoroutine) {\n $throwRuntimeError(\"cannot block in JavaScript callback, fix by wrapping code in goroutine\");\n }\n $curGoroutine.asleep = true;\n};\n\nvar $send = function(chan, value) {\n if (chan.$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n var queuedRecv = chan.$recvQueue.shift();\n if (queuedRecv !== undefined) {\n queuedRecv([value, true]);\n return;\n }\n if (chan.$buffer.length < chan.$capacity) {\n chan.$buffer.push(value);\n return;\n }\n\n var thisGoroutine = $curGoroutine;\n var closedDuringSend;\n chan.$sendQueue.push(function(closed) {\n closedDuringSend = closed;\n $schedule(thisGoroutine);\n return value;\n });\n $block();\n return {\n $blk: function() {\n if (closedDuringSend) {\n $throwRuntimeError(\"send on closed channel\");\n }\n },\n };\n};\nvar $recv = function(chan) {\n var queuedSend = chan.$sendQueue.shift();\n if (queuedSend !== undefined) {\n chan.$buffer.push(queuedSend(false));\n }\n var bufferedValue = chan.$buffer.shift();\n if (bufferedValue !== undefined) {\n return [bufferedValue, true];\n }\n if (chan.$closed) {\n return [chan.$elem.zero(), false];\n }\n\n var thisGoroutine = $curGoroutine;\n var f = {\n $blk: function() {\n return this.value;\n },\n };\n var queueEntry = function(v) {\n f.value = v;\n $schedule(thisGoroutine);\n };\n chan.$recvQueue.push(queueEntry);\n $block();\n return f;\n};\nvar $close = function(chan) {\n if (chan.$closed) {\n $throwRuntimeError(\"close of closed channel\");\n }\n chan.$closed = true;\n while (true) {\n var queuedSend = chan.$sendQueue.shift();\n if (queuedSend === undefined) {\n break;\n }\n queuedSend(true); /* will panic */\n }\n while (true) {\n var queuedRecv = chan.$recvQueue.shift();\n if (queuedRecv === undefined) {\n break;\n }\n queuedRecv([chan.$elem.zero(), false]);\n }\n};\nvar $select = function(comms) {\n var ready = [];\n var selection = -1;\n for (var i = 0; i < comms.length; i++) {\n var comm = comms[i];\n var chan = comm[0];\n switch (comm.length) {\n case 0 /* default */:\n selection = i;\n break;\n case 1 /* recv */:\n if (chan.$sendQueue.length !== 0 || chan.$buffer.length !== 0 || chan.$closed) {\n ready.push(i);\n }\n break;\n case 2 /* send */:\n if (chan.$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n if (chan.$recvQueue.length !== 0 || chan.$buffer.length < chan.$capacity) {\n ready.push(i);\n }\n break;\n }\n }\n\n if (ready.length !== 0) {\n selection = ready[Math.floor(Math.random() * ready.length)];\n }\n if (selection !== -1) {\n var comm = comms[selection];\n switch (comm.length) {\n case 0 /* default */:\n return [selection];\n case 1 /* recv */:\n return [selection, $recv(comm[0])];\n case 2 /* send */:\n $send(comm[0], comm[1]);\n return [selection];\n }\n }\n\n var entries = [];\n var thisGoroutine = $curGoroutine;\n var f = {\n $blk: function() {\n return this.selection;\n },\n };\n var removeFromQueues = function() {\n for (var i = 0; i < entries.length; i++) {\n var entry = entries[i];\n var queue = entry[0];\n var index = queue.indexOf(entry[1]);\n if (index !== -1) {\n queue.splice(index, 1);\n }\n }\n };\n for (var i = 0; i < comms.length; i++) {\n (function(i) {\n var comm = comms[i];\n switch (comm.length) {\n case 1 /* recv */:\n var queueEntry = function(value) {\n f.selection = [i, value];\n removeFromQueues();\n $schedule(thisGoroutine);\n };\n entries.push([comm[0].$recvQueue, queueEntry]);\n comm[0].$recvQueue.push(queueEntry);\n break;\n case 2 /* send */:\n var queueEntry = function() {\n if (comm[0].$closed) {\n $throwRuntimeError(\"send on closed channel\");\n }\n f.selection = [i];\n removeFromQueues();\n $schedule(thisGoroutine);\n return comm[1];\n };\n entries.push([comm[0].$sendQueue, queueEntry]);\n comm[0].$sendQueue.push(queueEntry);\n break;\n }\n })(i);\n }\n $block();\n return f;\n};\nvar $jsObjectPtr, $jsErrorPtr;\n\nvar $needsExternalization = function(t) {\n switch (t.kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindFloat32:\n case $kindFloat64:\n return false;\n default:\n return t !== $jsObjectPtr;\n }\n};\n\nvar $externalize = function(v, t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n switch (t.kind) {\n case $kindBool:\n case $kindInt:\n case $kindInt8:\n case $kindInt16:\n case $kindInt32:\n case $kindUint:\n case $kindUint8:\n case $kindUint16:\n case $kindUint32:\n case $kindUintptr:\n case $kindFloat32:\n case $kindFloat64:\n return v;\n case $kindInt64:\n case $kindUint64:\n return $flatten64(v);\n case $kindArray:\n if ($needsExternalization(t.elem)) {\n return $mapArray(v, function(e) {\n return $externalize(e, t.elem);\n });\n }\n return v;\n case $kindFunc:\n return $externalizeFunction(v, t, false);\n case $kindInterface:\n if (v === $ifaceNil) {\n return null;\n }\n if (v.constructor === $jsObjectPtr) {\n return v.$val.object;\n }\n return $externalize(v.$val, v.constructor);\n case $kindMap:\n var m = {};\n var keys = $keys(v);\n for (var i = 0; i < keys.length; i++) {\n var entry = v[keys[i]];\n m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem);\n }\n return m;\n case $kindPtr:\n if (v === t.nil) {\n return null;\n }\n return $externalize(v.$get(), t.elem);\n case $kindSlice:\n if ($needsExternalization(t.elem)) {\n return $mapArray($sliceToArray(v), function(e) {\n return $externalize(e, t.elem);\n });\n }\n return $sliceToArray(v);\n case $kindString:\n if ($isASCII(v)) {\n return v;\n }\n var s = \"\",\n r;\n for (var i = 0; i < v.length; i += r[1]) {\n r = $decodeRune(v, i);\n var c = r[0];\n if (c > 0xffff) {\n var h = Math.floor((c - 0x10000) / 0x400) + 0xd800;\n var l = (c - 0x10000) % 0x400 + 0xdc00;\n s += String.fromCharCode(h, l);\n continue;\n }\n s += String.fromCharCode(c);\n }\n return s;\n case $kindStruct:\n var timePkg = $packages[\"time\"];\n if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) {\n var milli = $div64(v.UnixNano(), new $Int64(0, 1000000));\n return new Date($flatten64(milli));\n }\n\n var noJsObject = {};\n var searchJsObject = function(v, t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n switch (t.kind) {\n case $kindPtr:\n if (v === t.nil) {\n return noJsObject;\n }\n return searchJsObject(v.$get(), t.elem);\n case $kindStruct:\n var f = t.fields[0];\n return searchJsObject(v[f.prop], f.typ);\n case $kindInterface:\n return searchJsObject(v.$val, v.constructor);\n default:\n return noJsObject;\n }\n };\n var o = searchJsObject(v, t);\n if (o !== noJsObject) {\n return o;\n }\n\n o = {};\n for (var i = 0; i < t.fields.length; i++) {\n var f = t.fields[i];\n if (!f.exported) {\n continue;\n }\n o[f.name] = $externalize(v[f.prop], f.typ);\n }\n return o;\n }\n $throwRuntimeError(\"cannot externalize \" + t.string);\n};\n\nvar $externalizeFunction = function(v, t, passThis) {\n if (v === $throwNilPointerError) {\n return null;\n }\n if (v.$externalizeWrapper === undefined) {\n $checkForDeadlock = false;\n v.$externalizeWrapper = function() {\n var args = [];\n for (var i = 0; i < t.params.length; i++) {\n if (t.variadic && i === t.params.length - 1) {\n var vt = t.params[i].elem,\n varargs = [];\n for (var j = i; j < arguments.length; j++) {\n varargs.push($internalize(arguments[j], vt));\n }\n args.push(new t.params[i](varargs));\n break;\n }\n args.push($internalize(arguments[i], t.params[i]));\n }\n var result = v.apply(passThis ? this : undefined, args);\n switch (t.results.length) {\n case 0:\n return;\n case 1:\n return $externalize(result, t.results[0]);\n default:\n for (var i = 0; i < t.results.length; i++) {\n result[i] = $externalize(result[i], t.results[i]);\n }\n return result;\n }\n };\n }\n return v.$externalizeWrapper;\n};\n\nvar $internalize = function(v, t, recv) {\n if (t === $jsObjectPtr) {\n return v;\n }\n if (t === $jsObjectPtr.elem) {\n $throwRuntimeError(\"cannot internalize js.Object, use *js.Object instead\");\n }\n if (v && v.__internal_object__ !== undefined) {\n return $assertType(v.__internal_object__, t, false);\n }\n var timePkg = $packages[\"time\"];\n if (timePkg !== undefined && t === timePkg.Time) {\n if (!(v !== null && v !== undefined && v.constructor === Date)) {\n $throwRuntimeError(\"cannot internalize time.Time from \" + typeof v + \", must be Date\");\n }\n return timePkg.Unix(new $Int64(0, 0), new $Int64(0, v.getTime() * 1000000));\n }\n switch (t.kind) {\n case $kindBool:\n return !!v;\n case $kindInt:\n return parseInt(v);\n case $kindInt8:\n return (parseInt(v) << 24) >> 24;\n case $kindInt16:\n return (parseInt(v) << 16) >> 16;\n case $kindInt32:\n return parseInt(v) >> 0;\n case $kindUint:\n return parseInt(v);\n case $kindUint8:\n return (parseInt(v) << 24) >>> 24;\n case $kindUint16:\n return (parseInt(v) << 16) >>> 16;\n case $kindUint32:\n case $kindUintptr:\n return parseInt(v) >>> 0;\n case $kindInt64:\n case $kindUint64:\n return new t(0, v);\n case $kindFloat32:\n case $kindFloat64:\n return parseFloat(v);\n case $kindArray:\n if (v.length !== t.len) {\n $throwRuntimeError(\"got array with wrong size from JavaScript native\");\n }\n return $mapArray(v, function(e) {\n return $internalize(e, t.elem);\n });\n case $kindFunc:\n return function() {\n var args = [];\n for (var i = 0; i < t.params.length; i++) {\n if (t.variadic && i === t.params.length - 1) {\n var vt = t.params[i].elem,\n varargs = arguments[i];\n for (var j = 0; j < varargs.$length; j++) {\n args.push($externalize(varargs.$array[varargs.$offset + j], vt));\n }\n break;\n }\n args.push($externalize(arguments[i], t.params[i]));\n }\n var result = v.apply(recv, args);\n switch (t.results.length) {\n case 0:\n return;\n case 1:\n return $internalize(result, t.results[0]);\n default:\n for (var i = 0; i < t.results.length; i++) {\n result[i] = $internalize(result[i], t.results[i]);\n }\n return result;\n }\n };\n case $kindInterface:\n if (t.methods.length !== 0) {\n $throwRuntimeError(\"cannot internalize \" + t.string);\n }\n if (v === null) {\n return $ifaceNil;\n }\n if (v === undefined) {\n return new $jsObjectPtr(undefined);\n }\n switch (v.constructor) {\n case Int8Array:\n return new ($sliceType($Int8))(v);\n case Int16Array:\n return new ($sliceType($Int16))(v);\n case Int32Array:\n return new ($sliceType($Int))(v);\n case Uint8Array:\n return new ($sliceType($Uint8))(v);\n case Uint16Array:\n return new ($sliceType($Uint16))(v);\n case Uint32Array:\n return new ($sliceType($Uint))(v);\n case Float32Array:\n return new ($sliceType($Float32))(v);\n case Float64Array:\n return new ($sliceType($Float64))(v);\n case Array:\n return $internalize(v, $sliceType($emptyInterface));\n case Boolean:\n return new $Bool(!!v);\n case Date:\n if (timePkg === undefined) {\n /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */\n return new $jsObjectPtr(v);\n }\n return new timePkg.Time($internalize(v, timePkg.Time));\n case Function:\n var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true);\n return new funcType($internalize(v, funcType));\n case Number:\n return new $Float64(parseFloat(v));\n case String:\n return new $String($internalize(v, $String));\n default:\n if ($global.Node && v instanceof $global.Node) {\n return new $jsObjectPtr(v);\n }\n var mapType = $mapType($String, $emptyInterface);\n return new mapType($internalize(v, mapType));\n }\n case $kindMap:\n var m = {};\n var keys = $keys(v);\n for (var i = 0; i < keys.length; i++) {\n var k = $internalize(keys[i], t.key);\n m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) };\n }\n return m;\n case $kindPtr:\n if (t.elem.kind === $kindStruct) {\n return $internalize(v, t.elem);\n }\n case $kindSlice:\n return new t(\n $mapArray(v, function(e) {\n return $internalize(e, t.elem);\n })\n );\n case $kindString:\n v = String(v);\n if ($isASCII(v)) {\n return v;\n }\n var s = \"\";\n var i = 0;\n while (i < v.length) {\n var h = v.charCodeAt(i);\n if (0xd800 <= h && h <= 0xdbff) {\n var l = v.charCodeAt(i + 1);\n var c = (h - 0xd800) * 0x400 + l - 0xdc00 + 0x10000;\n s += $encodeRune(c);\n i += 2;\n continue;\n }\n s += $encodeRune(h);\n i++;\n }\n return s;\n case $kindStruct:\n var noJsObject = {};\n var searchJsObject = function(t) {\n if (t === $jsObjectPtr) {\n return v;\n }\n if (t === $jsObjectPtr.elem) {\n $throwRuntimeError(\"cannot internalize js.Object, use *js.Object instead\");\n }\n switch (t.kind) {\n case $kindPtr:\n return searchJsObject(t.elem);\n case $kindStruct:\n var f = t.fields[0];\n var o = searchJsObject(f.typ);\n if (o !== noJsObject) {\n var n = new t.ptr();\n n[f.prop] = o;\n return n;\n }\n return noJsObject;\n default:\n return noJsObject;\n }\n };\n var o = searchJsObject(t);\n if (o !== noJsObject) {\n return o;\n }\n }\n $throwRuntimeError(\"cannot internalize \" + t.string);\n};\n\n/* $isASCII reports whether string s contains only ASCII characters. */\nvar $isASCII = function(s) {\n for (var i = 0; i < s.length; i++) {\n if (s.charCodeAt(i) >= 128) {\n return false;\n }\n }\n return true;\n};\n" diff --git a/compiler/prelude/prelude.js b/compiler/prelude/prelude.js index 58ad4e0d3..586161e2c 100644 --- a/compiler/prelude/prelude.js +++ b/compiler/prelude/prelude.js @@ -1,14 +1,18 @@ Error.stackTraceLimit = Infinity; var $global, $module; -if (typeof window !== "undefined") { /* web page */ +if (typeof window !== "undefined") { + /* web page */ $global = window; -} else if (typeof self !== "undefined") { /* web worker */ +} else if (typeof self !== "undefined") { + /* web worker */ $global = self; -} else if (typeof global !== "undefined") { /* Node.js */ +} else if (typeof global !== "undefined") { + /* Node.js */ $global = global; $global.require = require; -} else { /* others (e.g. Nashorn) */ +} else { + /* others (e.g. Nashorn) */ $global = this; } @@ -19,13 +23,24 @@ if (typeof module !== "undefined") { $module = module; } -var $packages = {}, $idCounter = 0; -var $keys = function(m) { return m ? Object.keys(m) : []; }; +var $packages = {}, + $idCounter = 0; +var $keys = function(m) { + return m ? Object.keys(m) : []; +}; var $flushConsole = function() {}; var $throwRuntimeError; /* set by package "runtime" */ -var $throwNilPointerError = function() { $throwRuntimeError("invalid memory address or nil pointer dereference"); }; -var $call = function(fn, rcvr, args) { return fn.apply(rcvr, args); }; -var $makeFunc = function(fn) { return function() { return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface); }; }; +var $throwNilPointerError = function() { + $throwRuntimeError("invalid memory address or nil pointer dereference"); +}; +var $call = function(fn, rcvr, args) { + return fn.apply(rcvr, args); +}; +var $makeFunc = function(fn) { + return function() { + return $externalize(fn(this, new ($sliceType($jsObjectPtr))($global.Array.prototype.slice.call(arguments, []))), $emptyInterface); + }; +}; var $unused = function(v) {}; var $mapArray = function(array, f) { @@ -128,69 +143,69 @@ var $decodeRune = function(str, pos) { return [c0, 1]; } - if (c0 !== c0 || c0 < 0xC0) { - return [0xFFFD, 1]; + if (c0 !== c0 || c0 < 0xc0) { + return [0xfffd, 1]; } var c1 = str.charCodeAt(pos + 1); - if (c1 !== c1 || c1 < 0x80 || 0xC0 <= c1) { - return [0xFFFD, 1]; + if (c1 !== c1 || c1 < 0x80 || 0xc0 <= c1) { + return [0xfffd, 1]; } - if (c0 < 0xE0) { - var r = (c0 & 0x1F) << 6 | (c1 & 0x3F); - if (r <= 0x7F) { - return [0xFFFD, 1]; + if (c0 < 0xe0) { + var r = ((c0 & 0x1f) << 6) | (c1 & 0x3f); + if (r <= 0x7f) { + return [0xfffd, 1]; } return [r, 2]; } var c2 = str.charCodeAt(pos + 2); - if (c2 !== c2 || c2 < 0x80 || 0xC0 <= c2) { - return [0xFFFD, 1]; + if (c2 !== c2 || c2 < 0x80 || 0xc0 <= c2) { + return [0xfffd, 1]; } - if (c0 < 0xF0) { - var r = (c0 & 0x0F) << 12 | (c1 & 0x3F) << 6 | (c2 & 0x3F); - if (r <= 0x7FF) { - return [0xFFFD, 1]; + if (c0 < 0xf0) { + var r = ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f); + if (r <= 0x7ff) { + return [0xfffd, 1]; } - if (0xD800 <= r && r <= 0xDFFF) { - return [0xFFFD, 1]; + if (0xd800 <= r && r <= 0xdfff) { + return [0xfffd, 1]; } return [r, 3]; } var c3 = str.charCodeAt(pos + 3); - if (c3 !== c3 || c3 < 0x80 || 0xC0 <= c3) { - return [0xFFFD, 1]; + if (c3 !== c3 || c3 < 0x80 || 0xc0 <= c3) { + return [0xfffd, 1]; } - if (c0 < 0xF8) { - var r = (c0 & 0x07) << 18 | (c1 & 0x3F) << 12 | (c2 & 0x3F) << 6 | (c3 & 0x3F); - if (r <= 0xFFFF || 0x10FFFF < r) { - return [0xFFFD, 1]; + if (c0 < 0xf8) { + var r = ((c0 & 0x07) << 18) | ((c1 & 0x3f) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f); + if (r <= 0xffff || 0x10ffff < r) { + return [0xfffd, 1]; } return [r, 4]; } - return [0xFFFD, 1]; + return [0xfffd, 1]; }; var $encodeRune = function(r) { - if (r < 0 || r > 0x10FFFF || (0xD800 <= r && r <= 0xDFFF)) { - r = 0xFFFD; + if (r < 0 || r > 0x10ffff || (0xd800 <= r && r <= 0xdfff)) { + r = 0xfffd; } - if (r <= 0x7F) { + if (r <= 0x7f) { return String.fromCharCode(r); } - if (r <= 0x7FF) { - return String.fromCharCode(0xC0 | r >> 6, 0x80 | (r & 0x3F)); + if (r <= 0x7ff) { + return String.fromCharCode(0xc0 | (r >> 6), 0x80 | (r & 0x3f)); } - if (r <= 0xFFFF) { - return String.fromCharCode(0xE0 | r >> 12, 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F)); + if (r <= 0xffff) { + return String.fromCharCode(0xe0 | (r >> 12), 0x80 | ((r >> 6) & 0x3f), 0x80 | (r & 0x3f)); } - return String.fromCharCode(0xF0 | r >> 18, 0x80 | (r >> 12 & 0x3F), 0x80 | (r >> 6 & 0x3F), 0x80 | (r & 0x3F)); + return String.fromCharCode(0xf0 | (r >> 18), 0x80 | ((r >> 12) & 0x3f), 0x80 | ((r >> 6) & 0x3f), 0x80 | (r & 0x3f)); }; var $stringToBytes = function(str) { @@ -214,7 +229,8 @@ var $bytesToString = function(slice) { var $stringToRunes = function(str) { var array = new Int32Array(str.length); - var rune, j = 0; + var rune, + j = 0; for (var i = 0; i < str.length; i += rune[1], j++) { rune = $decodeRune(str, i); array[j] = rune[0]; @@ -258,18 +274,18 @@ var $copyArray = function(dst, src, dstOffset, srcOffset, n, elem) { } switch (elem.kind) { - case $kindArray: - case $kindStruct: - if (dst === src && dstOffset > srcOffset) { - for (var i = n - 1; i >= 0; i--) { + case $kindArray: + case $kindStruct: + if (dst === src && dstOffset > srcOffset) { + for (var i = n - 1; i >= 0; i--) { + elem.copy(dst[dstOffset + i], src[srcOffset + i]); + } + return; + } + for (var i = 0; i < n; i++) { elem.copy(dst[dstOffset + i], src[srcOffset + i]); } return; - } - for (var i = 0; i < n; i++) { - elem.copy(dst[dstOffset + i], src[srcOffset + i]); - } - return; } if (dst === src && dstOffset > srcOffset) { @@ -290,7 +306,7 @@ var $clone = function(src, type) { }; var $pointerOfStructConversion = function(obj, type) { - if(obj.$proxies === undefined) { + if (obj.$proxies === undefined) { obj.$proxies = {}; obj.$proxies[obj.constructor.string] = obj; } @@ -300,8 +316,12 @@ var $pointerOfStructConversion = function(obj, type) { for (var i = 0; i < type.elem.fields.length; i++) { (function(fieldProp) { properties[fieldProp] = { - get: function() { return obj[fieldProp]; }, - set: function(value) { obj[fieldProp] = value; } + get: function() { + return obj[fieldProp]; + }, + set: function(value) { + obj[fieldProp] = value; + }, }; })(type.elem.fields[i].prop); } @@ -366,34 +386,34 @@ var $equal = function(a, b, type) { return a === b; } switch (type.kind) { - case $kindComplex64: - case $kindComplex128: - return a.$real === b.$real && a.$imag === b.$imag; - case $kindInt64: - case $kindUint64: - return a.$high === b.$high && a.$low === b.$low; - case $kindArray: - if (a.length !== b.length) { - return false; - } - for (var i = 0; i < a.length; i++) { - if (!$equal(a[i], b[i], type.elem)) { + case $kindComplex64: + case $kindComplex128: + return a.$real === b.$real && a.$imag === b.$imag; + case $kindInt64: + case $kindUint64: + return a.$high === b.$high && a.$low === b.$low; + case $kindArray: + if (a.length !== b.length) { return false; } - } - return true; - case $kindStruct: - for (var i = 0; i < type.fields.length; i++) { - var f = type.fields[i]; - if (!$equal(a[f.prop], b[f.prop], f.typ)) { - return false; + for (var i = 0; i < a.length; i++) { + if (!$equal(a[i], b[i], type.elem)) { + return false; + } } - } - return true; - case $kindInterface: - return $interfaceIsEqual(a, b); - default: - return a === b; + return true; + case $kindStruct: + for (var i = 0; i < type.fields.length; i++) { + var f = type.fields[i]; + if (!$equal(a[f.prop], b[f.prop], f.typ)) { + return false; + } + } + return true; + case $kindInterface: + return $interfaceIsEqual(a, b); + default: + return a === b; } }; diff --git a/compiler/prelude/prettier_options.json b/compiler/prelude/prettier_options.json new file mode 100644 index 000000000..4db654bda --- /dev/null +++ b/compiler/prelude/prettier_options.json @@ -0,0 +1,4 @@ +{ + "printWidth": 1000000, + "trailingComma": "es5" +} diff --git a/compiler/prelude/types.js b/compiler/prelude/types.js index e645ab3f5..aef54a2ba 100644 --- a/compiler/prelude/types.js +++ b/compiler/prelude/types.js @@ -34,19 +34,23 @@ var $addMethodSynthesizer = function(f) { $methodSynthesizers.push(f); }; var $synthesizeMethods = function() { - $methodSynthesizers.forEach(function(f) { f(); }); + $methodSynthesizers.forEach(function(f) { + f(); + }); $methodSynthesizers = null; }; var $ifaceKeyFor = function(x) { if (x === $ifaceNil) { - return 'nil'; + return "nil"; } var c = x.constructor; - return c.string + '$' + c.keyFor(x.$val); + return c.string + "$" + c.keyFor(x.$val); }; -var $identity = function(x) { return x; }; +var $identity = function(x) { + return x; +}; var $typeIDCounter = 0; @@ -60,320 +64,385 @@ var $idKey = function(x) { var $newType = function(size, kind, string, named, pkg, exported, constructor) { var typ; - switch(kind) { - case $kindBool: - case $kindInt: - case $kindInt8: - case $kindInt16: - case $kindInt32: - case $kindUint: - case $kindUint8: - case $kindUint16: - case $kindUint32: - case $kindUintptr: - case $kindUnsafePointer: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.keyFor = $identity; - break; - - case $kindString: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.keyFor = function(x) { return "$" + x; }; - break; - - case $kindFloat32: - case $kindFloat64: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.keyFor = function(x) { return $floatKey(x); }; - break; - - case $kindInt64: - typ = function(high, low) { - this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >> 0; - this.$low = low >>> 0; - this.$val = this; - }; - typ.keyFor = function(x) { return x.$high + "$" + x.$low; }; - break; - - case $kindUint64: - typ = function(high, low) { - this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >>> 0; - this.$low = low >>> 0; - this.$val = this; - }; - typ.keyFor = function(x) { return x.$high + "$" + x.$low; }; - break; - - case $kindComplex64: - typ = function(real, imag) { - this.$real = $fround(real); - this.$imag = $fround(imag); - this.$val = this; - }; - typ.keyFor = function(x) { return x.$real + "$" + x.$imag; }; - break; - - case $kindComplex128: - typ = function(real, imag) { - this.$real = real; - this.$imag = imag; - this.$val = this; - }; - typ.keyFor = function(x) { return x.$real + "$" + x.$imag; }; - break; - - case $kindArray: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.ptr = $newType(4, $kindPtr, "*" + string, false, "", false, function(array) { - this.$get = function() { return array; }; - this.$set = function(v) { typ.copy(this, v); }; - this.$val = array; - }); - typ.init = function(elem, len) { - typ.elem = elem; - typ.len = len; - typ.comparable = elem.comparable; + switch (kind) { + case $kindBool: + case $kindInt: + case $kindInt8: + case $kindInt16: + case $kindInt32: + case $kindUint: + case $kindUint8: + case $kindUint16: + case $kindUint32: + case $kindUintptr: + case $kindUnsafePointer: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; + typ.keyFor = $identity; + break; + + case $kindString: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; typ.keyFor = function(x) { - return Array.prototype.join.call($mapArray(x, function(e) { - return String(elem.keyFor(e)).replace(/\\/g, "\\\\").replace(/\$/g, "\\$"); - }), "$"); - }; - typ.copy = function(dst, src) { - $copyArray(dst, src, 0, 0, src.length, elem); - }; - typ.ptr.init(typ); - Object.defineProperty(typ.ptr.nil, "nilCheck", { get: $throwNilPointerError }); - }; - break; - - case $kindChan: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.keyFor = $idKey; - typ.init = function(elem, sendOnly, recvOnly) { - typ.elem = elem; - typ.sendOnly = sendOnly; - typ.recvOnly = recvOnly; - }; - break; - - case $kindFunc: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.init = function(params, results, variadic) { - typ.params = params; - typ.results = results; - typ.variadic = variadic; - typ.comparable = false; - }; - break; - - case $kindInterface: - typ = { implementedBy: {}, missingMethodFor: {} }; - typ.keyFor = $ifaceKeyFor; - typ.init = function(methods) { - typ.methods = methods; - methods.forEach(function(m) { - $ifaceNil[m.prop] = $throwNilPointerError; - }); - }; - break; - - case $kindMap: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.init = function(key, elem) { - typ.key = key; - typ.elem = elem; - typ.comparable = false; - }; - break; - - case $kindPtr: - typ = constructor || function(getter, setter, target) { - this.$get = getter; - this.$set = setter; - this.$target = target; - this.$val = this; - }; - typ.keyFor = $idKey; - typ.init = function(elem) { - typ.elem = elem; - typ.wrapped = (elem.kind === $kindArray); - typ.nil = new typ($throwNilPointerError, $throwNilPointerError); - }; - break; - - case $kindSlice: - typ = function(array) { - if (array.constructor !== typ.nativeArray) { - array = new typ.nativeArray(array); - } - this.$array = array; - this.$offset = 0; - this.$length = array.length; - this.$capacity = array.length; - this.$val = this; - }; - typ.init = function(elem) { - typ.elem = elem; - typ.comparable = false; - typ.nativeArray = $nativeArray(elem.kind); - typ.nil = new typ([]); - }; - break; - - case $kindStruct: - typ = function(v) { this.$val = v; }; - typ.wrapped = true; - typ.ptr = $newType(4, $kindPtr, "*" + string, false, pkg, exported, constructor); - typ.ptr.elem = typ; - typ.ptr.prototype.$get = function() { return this; }; - typ.ptr.prototype.$set = function(v) { typ.copy(this, v); }; - typ.init = function(pkgPath, fields) { - typ.pkgPath = pkgPath; - typ.fields = fields; - fields.forEach(function(f) { - if (!f.typ.comparable) { - typ.comparable = false; - } - }); + return "$" + x; + }; + break; + + case $kindFloat32: + case $kindFloat64: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; typ.keyFor = function(x) { - var val = x.$val; - return $mapArray(fields, function(f) { - return String(f.typ.keyFor(val[f.prop])).replace(/\\/g, "\\\\").replace(/\$/g, "\\$"); - }).join("$"); - }; - typ.copy = function(dst, src) { - for (var i = 0; i < fields.length; i++) { - var f = fields[i]; - switch (f.typ.kind) { - case $kindArray: - case $kindStruct: - f.typ.copy(dst[f.prop], src[f.prop]); - continue; - default: - dst[f.prop] = src[f.prop]; - continue; - } - } + return $floatKey(x); + }; + break; + + case $kindInt64: + typ = function(high, low) { + this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >> 0; + this.$low = low >>> 0; + this.$val = this; + }; + typ.keyFor = function(x) { + return x.$high + "$" + x.$low; + }; + break; + + case $kindUint64: + typ = function(high, low) { + this.$high = (high + Math.floor(Math.ceil(low) / 4294967296)) >>> 0; + this.$low = low >>> 0; + this.$val = this; }; - /* nil value */ - var properties = {}; - fields.forEach(function(f) { - properties[f.prop] = { get: $throwNilPointerError, set: $throwNilPointerError }; + typ.keyFor = function(x) { + return x.$high + "$" + x.$low; + }; + break; + + case $kindComplex64: + typ = function(real, imag) { + this.$real = $fround(real); + this.$imag = $fround(imag); + this.$val = this; + }; + typ.keyFor = function(x) { + return x.$real + "$" + x.$imag; + }; + break; + + case $kindComplex128: + typ = function(real, imag) { + this.$real = real; + this.$imag = imag; + this.$val = this; + }; + typ.keyFor = function(x) { + return x.$real + "$" + x.$imag; + }; + break; + + case $kindArray: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; + typ.ptr = $newType(4, $kindPtr, "*" + string, false, "", false, function(array) { + this.$get = function() { + return array; + }; + this.$set = function(v) { + typ.copy(this, v); + }; + this.$val = array; }); - typ.ptr.nil = Object.create(constructor.prototype, properties); - typ.ptr.nil.$val = typ.ptr.nil; - /* methods for embedded fields */ - $addMethodSynthesizer(function() { - var synthesizeMethod = function(target, m, f) { - if (target.prototype[m.prop] !== undefined) { return; } - target.prototype[m.prop] = function() { - var v = this.$val[f.prop]; - if (f.typ === $jsObjectPtr) { - v = new $jsObjectPtr(v); - } - if (v.$val === undefined) { - v = new f.typ(v); - } - return v[m.prop].apply(v, arguments); - }; + typ.init = function(elem, len) { + typ.elem = elem; + typ.len = len; + typ.comparable = elem.comparable; + typ.keyFor = function(x) { + return Array.prototype.join.call( + $mapArray(x, function(e) { + return String(elem.keyFor(e)) + .replace(/\\/g, "\\\\") + .replace(/\$/g, "\\$"); + }), + "$" + ); + }; + typ.copy = function(dst, src) { + $copyArray(dst, src, 0, 0, src.length, elem); }; + typ.ptr.init(typ); + Object.defineProperty(typ.ptr.nil, "nilCheck", { get: $throwNilPointerError }); + }; + break; + + case $kindChan: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; + typ.keyFor = $idKey; + typ.init = function(elem, sendOnly, recvOnly) { + typ.elem = elem; + typ.sendOnly = sendOnly; + typ.recvOnly = recvOnly; + }; + break; + + case $kindFunc: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; + typ.init = function(params, results, variadic) { + typ.params = params; + typ.results = results; + typ.variadic = variadic; + typ.comparable = false; + }; + break; + + case $kindInterface: + typ = { implementedBy: {}, missingMethodFor: {} }; + typ.keyFor = $ifaceKeyFor; + typ.init = function(methods) { + typ.methods = methods; + methods.forEach(function(m) { + $ifaceNil[m.prop] = $throwNilPointerError; + }); + }; + break; + + case $kindMap: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; + typ.init = function(key, elem) { + typ.key = key; + typ.elem = elem; + typ.comparable = false; + }; + break; + + case $kindPtr: + typ = + constructor || + function(getter, setter, target) { + this.$get = getter; + this.$set = setter; + this.$target = target; + this.$val = this; + }; + typ.keyFor = $idKey; + typ.init = function(elem) { + typ.elem = elem; + typ.wrapped = elem.kind === $kindArray; + typ.nil = new typ($throwNilPointerError, $throwNilPointerError); + }; + break; + + case $kindSlice: + typ = function(array) { + if (array.constructor !== typ.nativeArray) { + array = new typ.nativeArray(array); + } + this.$array = array; + this.$offset = 0; + this.$length = array.length; + this.$capacity = array.length; + this.$val = this; + }; + typ.init = function(elem) { + typ.elem = elem; + typ.comparable = false; + typ.nativeArray = $nativeArray(elem.kind); + typ.nil = new typ([]); + }; + break; + + case $kindStruct: + typ = function(v) { + this.$val = v; + }; + typ.wrapped = true; + typ.ptr = $newType(4, $kindPtr, "*" + string, false, pkg, exported, constructor); + typ.ptr.elem = typ; + typ.ptr.prototype.$get = function() { + return this; + }; + typ.ptr.prototype.$set = function(v) { + typ.copy(this, v); + }; + typ.init = function(pkgPath, fields) { + typ.pkgPath = pkgPath; + typ.fields = fields; fields.forEach(function(f) { - if (f.anonymous) { - $methodSet(f.typ).forEach(function(m) { - synthesizeMethod(typ, m, f); - synthesizeMethod(typ.ptr, m, f); - }); - $methodSet($ptrType(f.typ)).forEach(function(m) { - synthesizeMethod(typ.ptr, m, f); - }); + if (!f.typ.comparable) { + typ.comparable = false; } }); - }); - }; - break; + typ.keyFor = function(x) { + var val = x.$val; + return $mapArray(fields, function(f) { + return String(f.typ.keyFor(val[f.prop])) + .replace(/\\/g, "\\\\") + .replace(/\$/g, "\\$"); + }).join("$"); + }; + typ.copy = function(dst, src) { + for (var i = 0; i < fields.length; i++) { + var f = fields[i]; + switch (f.typ.kind) { + case $kindArray: + case $kindStruct: + f.typ.copy(dst[f.prop], src[f.prop]); + continue; + default: + dst[f.prop] = src[f.prop]; + continue; + } + } + }; + /* nil value */ + var properties = {}; + fields.forEach(function(f) { + properties[f.prop] = { get: $throwNilPointerError, set: $throwNilPointerError }; + }); + typ.ptr.nil = Object.create(constructor.prototype, properties); + typ.ptr.nil.$val = typ.ptr.nil; + /* methods for embedded fields */ + $addMethodSynthesizer(function() { + var synthesizeMethod = function(target, m, f) { + if (target.prototype[m.prop] !== undefined) { + return; + } + target.prototype[m.prop] = function() { + var v = this.$val[f.prop]; + if (f.typ === $jsObjectPtr) { + v = new $jsObjectPtr(v); + } + if (v.$val === undefined) { + v = new f.typ(v); + } + return v[m.prop].apply(v, arguments); + }; + }; + fields.forEach(function(f) { + if (f.anonymous) { + $methodSet(f.typ).forEach(function(m) { + synthesizeMethod(typ, m, f); + synthesizeMethod(typ.ptr, m, f); + }); + $methodSet($ptrType(f.typ)).forEach(function(m) { + synthesizeMethod(typ.ptr, m, f); + }); + } + }); + }); + }; + break; - default: - $panic(new $String("invalid kind: " + kind)); + default: + $panic(new $String("invalid kind: " + kind)); } switch (kind) { - case $kindBool: - case $kindMap: - typ.zero = function() { return false; }; - break; - - case $kindInt: - case $kindInt8: - case $kindInt16: - case $kindInt32: - case $kindUint: - case $kindUint8 : - case $kindUint16: - case $kindUint32: - case $kindUintptr: - case $kindUnsafePointer: - case $kindFloat32: - case $kindFloat64: - typ.zero = function() { return 0; }; - break; - - case $kindString: - typ.zero = function() { return ""; }; - break; - - case $kindInt64: - case $kindUint64: - case $kindComplex64: - case $kindComplex128: - var zero = new typ(0, 0); - typ.zero = function() { return zero; }; - break; - - case $kindPtr: - case $kindSlice: - typ.zero = function() { return typ.nil; }; - break; - - case $kindChan: - typ.zero = function() { return $chanNil; }; - break; - - case $kindFunc: - typ.zero = function() { return $throwNilPointerError; }; - break; - - case $kindInterface: - typ.zero = function() { return $ifaceNil; }; - break; - - case $kindArray: - typ.zero = function() { - var arrayClass = $nativeArray(typ.elem.kind); - if (arrayClass !== Array) { - return new arrayClass(typ.len); - } - var array = new Array(typ.len); - for (var i = 0; i < typ.len; i++) { - array[i] = typ.elem.zero(); - } - return array; - }; - break; + case $kindBool: + case $kindMap: + typ.zero = function() { + return false; + }; + break; + + case $kindInt: + case $kindInt8: + case $kindInt16: + case $kindInt32: + case $kindUint: + case $kindUint8: + case $kindUint16: + case $kindUint32: + case $kindUintptr: + case $kindUnsafePointer: + case $kindFloat32: + case $kindFloat64: + typ.zero = function() { + return 0; + }; + break; - case $kindStruct: - typ.zero = function() { return new typ.ptr(); }; - break; + case $kindString: + typ.zero = function() { + return ""; + }; + break; + + case $kindInt64: + case $kindUint64: + case $kindComplex64: + case $kindComplex128: + var zero = new typ(0, 0); + typ.zero = function() { + return zero; + }; + break; + + case $kindPtr: + case $kindSlice: + typ.zero = function() { + return typ.nil; + }; + break; + + case $kindChan: + typ.zero = function() { + return $chanNil; + }; + break; + + case $kindFunc: + typ.zero = function() { + return $throwNilPointerError; + }; + break; + + case $kindInterface: + typ.zero = function() { + return $ifaceNil; + }; + break; + + case $kindArray: + typ.zero = function() { + var arrayClass = $nativeArray(typ.elem.kind); + if (arrayClass !== Array) { + return new arrayClass(typ.len); + } + var array = new Array(typ.len); + for (var i = 0; i < typ.len; i++) { + array[i] = typ.elem.zero(); + } + return array; + }; + break; - default: - $panic(new $String("invalid kind: " + kind)); + case $kindStruct: + typ.zero = function() { + return new typ.ptr(); + }; + break; + + default: + $panic(new $String("invalid kind: " + kind)); } typ.id = $typeIDCounter; @@ -396,13 +465,13 @@ var $methodSet = function(typ) { } var base = {}; - var isPtr = (typ.kind === $kindPtr); + var isPtr = typ.kind === $kindPtr; if (isPtr && typ.elem.kind === $kindInterface) { typ.methodSetCache = []; return []; } - var current = [{typ: isPtr ? typ.elem : typ, indirect: isPtr}]; + var current = [{ typ: isPtr ? typ.elem : typ, indirect: isPtr }]; var seen = {}; @@ -424,19 +493,19 @@ var $methodSet = function(typ) { } switch (e.typ.kind) { - case $kindStruct: - e.typ.fields.forEach(function(f) { - if (f.anonymous) { - var fTyp = f.typ; - var fIsPtr = (fTyp.kind === $kindPtr); - next.push({typ: fIsPtr ? fTyp.elem : fTyp, indirect: e.indirect || fIsPtr}); - } - }); - break; + case $kindStruct: + e.typ.fields.forEach(function(f) { + if (f.anonymous) { + var fTyp = f.typ; + var fIsPtr = fTyp.kind === $kindPtr; + next.push({ typ: fIsPtr ? fTyp.elem : fTyp, indirect: e.indirect || fIsPtr }); + } + }); + break; - case $kindInterface: - mset = mset.concat(e.typ.methods); - break; + case $kindInterface: + mset = mset.concat(e.typ.methods); + break; } }); @@ -450,57 +519,59 @@ var $methodSet = function(typ) { } typ.methodSetCache = []; - Object.keys(base).sort().forEach(function(name) { - typ.methodSetCache.push(base[name]); - }); + Object.keys(base) + .sort() + .forEach(function(name) { + typ.methodSetCache.push(base[name]); + }); return typ.methodSetCache; }; -var $Bool = $newType( 1, $kindBool, "bool", true, "", false, null); -var $Int = $newType( 4, $kindInt, "int", true, "", false, null); -var $Int8 = $newType( 1, $kindInt8, "int8", true, "", false, null); -var $Int16 = $newType( 2, $kindInt16, "int16", true, "", false, null); -var $Int32 = $newType( 4, $kindInt32, "int32", true, "", false, null); -var $Int64 = $newType( 8, $kindInt64, "int64", true, "", false, null); -var $Uint = $newType( 4, $kindUint, "uint", true, "", false, null); -var $Uint8 = $newType( 1, $kindUint8, "uint8", true, "", false, null); -var $Uint16 = $newType( 2, $kindUint16, "uint16", true, "", false, null); -var $Uint32 = $newType( 4, $kindUint32, "uint32", true, "", false, null); -var $Uint64 = $newType( 8, $kindUint64, "uint64", true, "", false, null); -var $Uintptr = $newType( 4, $kindUintptr, "uintptr", true, "", false, null); -var $Float32 = $newType( 4, $kindFloat32, "float32", true, "", false, null); -var $Float64 = $newType( 8, $kindFloat64, "float64", true, "", false, null); -var $Complex64 = $newType( 8, $kindComplex64, "complex64", true, "", false, null); -var $Complex128 = $newType(16, $kindComplex128, "complex128", true, "", false, null); -var $String = $newType( 8, $kindString, "string", true, "", false, null); -var $UnsafePointer = $newType( 4, $kindUnsafePointer, "unsafe.Pointer", true, "", false, null); +var $Bool = $newType(1, $kindBool, "bool", true, "", false, null); +var $Int = $newType(4, $kindInt, "int", true, "", false, null); +var $Int8 = $newType(1, $kindInt8, "int8", true, "", false, null); +var $Int16 = $newType(2, $kindInt16, "int16", true, "", false, null); +var $Int32 = $newType(4, $kindInt32, "int32", true, "", false, null); +var $Int64 = $newType(8, $kindInt64, "int64", true, "", false, null); +var $Uint = $newType(4, $kindUint, "uint", true, "", false, null); +var $Uint8 = $newType(1, $kindUint8, "uint8", true, "", false, null); +var $Uint16 = $newType(2, $kindUint16, "uint16", true, "", false, null); +var $Uint32 = $newType(4, $kindUint32, "uint32", true, "", false, null); +var $Uint64 = $newType(8, $kindUint64, "uint64", true, "", false, null); +var $Uintptr = $newType(4, $kindUintptr, "uintptr", true, "", false, null); +var $Float32 = $newType(4, $kindFloat32, "float32", true, "", false, null); +var $Float64 = $newType(8, $kindFloat64, "float64", true, "", false, null); +var $Complex64 = $newType(8, $kindComplex64, "complex64", true, "", false, null); +var $Complex128 = $newType(16, $kindComplex128, "complex128", true, "", false, null); +var $String = $newType(8, $kindString, "string", true, "", false, null); +var $UnsafePointer = $newType(4, $kindUnsafePointer, "unsafe.Pointer", true, "", false, null); var $nativeArray = function(elemKind) { switch (elemKind) { - case $kindInt: - return Int32Array; - case $kindInt8: - return Int8Array; - case $kindInt16: - return Int16Array; - case $kindInt32: - return Int32Array; - case $kindUint: - return Uint32Array; - case $kindUint8: - return Uint8Array; - case $kindUint16: - return Uint16Array; - case $kindUint32: - return Uint32Array; - case $kindUintptr: - return Uint32Array; - case $kindFloat32: - return Float32Array; - case $kindFloat64: - return Float64Array; - default: - return Array; + case $kindInt: + return Int32Array; + case $kindInt8: + return Int8Array; + case $kindInt16: + return Int16Array; + case $kindInt32: + return Int32Array; + case $kindUint: + return Uint32Array; + case $kindUint8: + return Uint8Array; + case $kindUint16: + return Uint16Array; + case $kindUint32: + return Uint32Array; + case $kindUintptr: + return Uint32Array; + case $kindFloat32: + return Float32Array; + case $kindFloat64: + return Float64Array; + default: + return Array; } }; var $toNativeArray = function(elemKind, array) { @@ -524,7 +595,7 @@ var $arrayType = function(elem, len) { var $chanType = function(elem, sendOnly, recvOnly) { var string = (recvOnly ? "<-" : "") + "chan" + (sendOnly ? "<- " : " ") + elem.string; - var field = sendOnly ? "SendChan" : (recvOnly ? "RecvChan" : "Chan"); + var field = sendOnly ? "SendChan" : recvOnly ? "RecvChan" : "Chan"; var typ = elem[field]; if (typ === undefined) { typ = $newType(4, $kindChan, string, false, "", false, null); @@ -545,14 +616,34 @@ var $Chan = function(elem, capacity) { this.$closed = false; }; var $chanNil = new $Chan(null, 0); -$chanNil.$sendQueue = $chanNil.$recvQueue = { length: 0, push: function() {}, shift: function() { return undefined; }, indexOf: function() { return -1; } }; +$chanNil.$sendQueue = $chanNil.$recvQueue = { + length: 0, + push: function() {}, + shift: function() { + return undefined; + }, + indexOf: function() { + return -1; + }, +}; var $funcTypes = {}; var $funcType = function(params, results, variadic) { - var typeKey = $mapArray(params, function(p) { return p.id; }).join(",") + "$" + $mapArray(results, function(r) { return r.id; }).join(",") + "$" + variadic; + var typeKey = + $mapArray(params, function(p) { + return p.id; + }).join(",") + + "$" + + $mapArray(results, function(r) { + return r.id; + }).join(",") + + "$" + + variadic; var typ = $funcTypes[typeKey]; if (typ === undefined) { - var paramTypes = $mapArray(params, function(p) { return p.string; }); + var paramTypes = $mapArray(params, function(p) { + return p.string; + }); if (variadic) { paramTypes[paramTypes.length - 1] = "..." + paramTypes[paramTypes.length - 1].substr(2); } @@ -560,7 +651,12 @@ var $funcType = function(params, results, variadic) { if (results.length === 1) { string += " " + results[0].string; } else if (results.length > 1) { - string += " (" + $mapArray(results, function(r) { return r.string; }).join(", ") + ")"; + string += + " (" + + $mapArray(results, function(r) { + return r.string; + }).join(", ") + + ")"; } typ = $newType(4, $kindFunc, string, false, "", false, null); $funcTypes[typeKey] = typ; @@ -571,14 +667,19 @@ var $funcType = function(params, results, variadic) { var $interfaceTypes = {}; var $interfaceType = function(methods) { - var typeKey = $mapArray(methods, function(m) { return m.pkg + "," + m.name + "," + m.typ.id; }).join("$"); + var typeKey = $mapArray(methods, function(m) { + return m.pkg + "," + m.name + "," + m.typ.id; + }).join("$"); var typ = $interfaceTypes[typeKey]; if (typ === undefined) { var string = "interface {}"; if (methods.length !== 0) { - string = "interface { " + $mapArray(methods, function(m) { - return (m.pkg !== "" ? m.pkg + "." : "") + m.name + m.typ.string.substr(4); - }).join("; ") + " }"; + string = + "interface { " + + $mapArray(methods, function(m) { + return (m.pkg !== "" ? m.pkg + "." : "") + m.name + m.typ.string.substr(4); + }).join("; ") + + " }"; } typ = $newType(8, $kindInterface, string, false, "", false, null); $interfaceTypes[typeKey] = typ; @@ -589,7 +690,7 @@ var $interfaceType = function(methods) { var $emptyInterface = $interfaceType([]); var $ifaceNil = {}; var $error = $newType(8, $kindInterface, "error", true, "", false, null); -$error.init([{prop: "Error", name: "Error", pkg: "", typ: $funcType([], [$String], false)}]); +$error.init([{ prop: "Error", name: "Error", pkg: "", typ: $funcType([], [$String], false) }]); var $mapTypes = {}; var $mapType = function(key, elem) { @@ -625,12 +726,29 @@ var $newDataPointer = function(data, constructor) { if (constructor.elem.kind === $kindStruct) { return data; } - return new constructor(function() { return data; }, function(v) { data = v; }); + return new constructor( + function() { + return data; + }, + function(v) { + data = v; + } + ); }; var $indexPtr = function(array, index, constructor) { array.$ptr = array.$ptr || {}; - return array.$ptr[index] || (array.$ptr[index] = new constructor(function() { return array[index]; }, function(v) { array[index] = v; })); + return ( + array.$ptr[index] || + (array.$ptr[index] = new constructor( + function() { + return array[index]; + }, + function(v) { + array[index] = v; + } + )) + ); }; var $sliceType = function(elem) { @@ -663,12 +781,17 @@ var $makeSlice = function(typ, length, capacity) { var $structTypes = {}; var $structType = function(pkgPath, fields) { - var typeKey = $mapArray(fields, function(f) { return f.name + "," + f.typ.id + "," + f.tag; }).join("$"); + var typeKey = $mapArray(fields, function(f) { + return f.name + "," + f.typ.id + "," + f.tag; + }).join("$"); var typ = $structTypes[typeKey]; if (typ === undefined) { - var string = "struct { " + $mapArray(fields, function(f) { - return f.name + " " + f.typ.string + (f.tag !== "" ? (" \"" + f.tag.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\"") : ""); - }).join("; ") + " }"; + var string = + "struct { " + + $mapArray(fields, function(f) { + return f.name + " " + f.typ.string + (f.tag !== "" ? ' "' + f.tag.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"' : ""); + }).join("; ") + + " }"; if (fields.length === 0) { string = "struct {}"; } @@ -687,7 +810,9 @@ var $structType = function(pkgPath, fields) { }; var $assertType = function(value, type, returnTuple) { - var isInterface = (type.kind === $kindInterface), ok, missingMethod = ""; + var isInterface = type.kind === $kindInterface, + ok, + missingMethod = ""; if (value === $ifaceNil) { ok = false; } else if (!isInterface) { @@ -726,7 +851,7 @@ var $assertType = function(value, type, returnTuple) { if (returnTuple) { return [type.zero(), false]; } - $panic(new $packages["runtime"].TypeAssertionError.ptr("", (value === $ifaceNil ? "" : value.constructor.string), type.string, missingMethod)); + $panic(new $packages["runtime"].TypeAssertionError.ptr("", value === $ifaceNil ? "" : value.constructor.string, type.string, missingMethod)); } if (!isInterface) { diff --git a/package-lock.json b/package-lock.json index ed79b7a9b..f459c81fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,12 @@ "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", "dev": true }, + "prettier": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.0.tgz", + "integrity": "sha512-Wz0SMncgaglBzDcohH3ZIAi4nVpzOIEweFzCOmgVEoRSeO72b4dcKGfgxoRGVMaFlh1r7dlVaJ+f3CIHfeH6xg==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", diff --git a/package.json b/package.json index e74269587..183ba6139 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "gopherjs", "devDependencies": { - "uglify-es": "3.3.9" + "uglify-es": "3.3.9", + "prettier": "1.12.0" } }