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; }; -`