123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- #
- #
- # Nim's Runtime Library
- # (c) Copyright 2015 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- include system/indexerrors
- import std/private/miscdollars
- proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
- type
- PSafePoint = ptr SafePoint
- SafePoint {.compilerproc, final.} = object
- prev: PSafePoint # points to next safe point
- exc: ref Exception
- PCallFrame = ptr CallFrame
- CallFrame {.importc, nodecl, final.} = object
- prev: PCallFrame
- procname: cstring
- line: int # current line number
- filename: cstring
- PJSError = ref object
- columnNumber {.importc.}: int
- fileName {.importc.}: cstring
- lineNumber {.importc.}: int
- message {.importc.}: cstring
- stack {.importc.}: cstring
- JSRef = ref RootObj # Fake type.
- var
- framePtr {.importc, nodecl, volatile.}: PCallFrame
- excHandler {.importc, nodecl, volatile.}: int = 0
- lastJSError {.importc, nodecl, volatile.}: PJSError = nil
- {.push stacktrace: off, profiler:off.}
- proc nimBoolToStr(x: bool): string {.compilerproc.} =
- if x: result = "true"
- else: result = "false"
- proc nimCharToStr(x: char): string {.compilerproc.} =
- result = newString(1)
- result[0] = x
- proc isNimException(): bool {.asmNoStackFrame.} =
- asm "return `lastJSError` && `lastJSError`.m_type;"
- proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
- if isNimException(): result = cast[ref Exception](lastJSError)
- proc getCurrentExceptionMsg*(): string =
- if lastJSError != nil:
- if isNimException():
- return cast[Exception](lastJSError).msg
- else:
- var msg: cstring
- {.emit: """
- if (`lastJSError`.message !== undefined) {
- `msg` = `lastJSError`.message;
- }
- """.}
- if not msg.isNil:
- return $msg
- return ""
- proc setCurrentException*(exc: ref Exception) =
- lastJSError = cast[PJSError](exc)
- proc auxWriteStackTrace(f: PCallFrame): string =
- type
- TempFrame = tuple[procname: cstring, line: int, filename: cstring]
- var
- it = f
- i = 0
- total = 0
- tempFrames: array[0..63, TempFrame]
- while it != nil and i <= high(tempFrames):
- tempFrames[i].procname = it.procname
- tempFrames[i].line = it.line
- tempFrames[i].filename = it.filename
- inc(i)
- inc(total)
- it = it.prev
- while it != nil:
- inc(total)
- it = it.prev
- result = ""
- # if the buffer overflowed print '...':
- if total != i:
- add(result, "(")
- add(result, $(total-i))
- add(result, " calls omitted) ...\n")
- for j in countdown(i-1, 0):
- result.toLocation($tempFrames[j].filename, tempFrames[j].line, 0)
- add(result, " at ")
- add(result, tempFrames[j].procname)
- add(result, "\n")
- proc rawWriteStackTrace(): string =
- if framePtr != nil:
- result = "Traceback (most recent call last)\n" & auxWriteStackTrace(framePtr)
- else:
- result = "No stack traceback available\n"
- proc writeStackTrace() =
- var trace = rawWriteStackTrace()
- trace.setLen(trace.len - 1)
- echo trace
- proc getStackTrace*(): string = rawWriteStackTrace()
- proc getStackTrace*(e: ref Exception): string = e.trace
- proc unhandledException(e: ref Exception) {.
- compilerproc, asmNoStackFrame.} =
- var buf = ""
- if e.msg.len != 0:
- add(buf, "Error: unhandled exception: ")
- add(buf, e.msg)
- else:
- add(buf, "Error: unhandled exception")
- add(buf, " [")
- add(buf, e.name)
- add(buf, "]\n")
- when NimStackTrace:
- add(buf, rawWriteStackTrace())
- let cbuf = cstring(buf)
- when NimStackTrace:
- framePtr = nil
- {.emit: """
- if (typeof(Error) !== "undefined") {
- throw new Error(`cbuf`);
- }
- else {
- throw `cbuf`;
- }
- """.}
- proc raiseException(e: ref Exception, ename: cstring) {.
- compilerproc, asmNoStackFrame.} =
- e.name = ename
- if excHandler == 0:
- unhandledException(e)
- when NimStackTrace:
- e.trace = rawWriteStackTrace()
- asm "throw `e`;"
- proc reraiseException() {.compilerproc, asmNoStackFrame.} =
- if lastJSError == nil:
- raise newException(ReraiseDefect, "no exception to reraise")
- else:
- if excHandler == 0:
- if isNimException():
- unhandledException(cast[ref Exception](lastJSError))
- asm "throw lastJSError;"
- proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerproc.} =
- raise newException(OverflowDefect, "over- or underflow")
- proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerproc.} =
- raise newException(DivByZeroDefect, "division by zero")
- proc raiseRangeError() {.compilerproc, noreturn.} =
- raise newException(RangeDefect, "value out of range")
- proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} =
- raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b)))
- proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} =
- raise newException(FieldDefect, formatFieldDefect(f, discVal))
- proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
- asm """
- var result = {};
- for (var i = 0; i < arguments.length; ++i) {
- var x = arguments[i];
- if (typeof(x) == "object") {
- for (var j = x[0]; j <= x[1]; ++j) {
- result[j] = true;
- }
- } else {
- result[x] = true;
- }
- }
- return result;
- """
- proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
- {.emit: """
- var result = [];
- for (var i = 0; i < `c`.length; ++i) {
- result[i] = `c`.charCodeAt(i);
- }
- return result;
- """.}
- proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
- {.emit: """
- var ln = `c`.length;
- var result = new Array(ln);
- var r = 0;
- for (var i = 0; i < ln; ++i) {
- var ch = `c`.charCodeAt(i);
- if (ch < 128) {
- result[r] = ch;
- }
- else {
- if (ch < 2048) {
- result[r] = (ch >> 6) | 192;
- }
- else {
- if (ch < 55296 || ch >= 57344) {
- result[r] = (ch >> 12) | 224;
- }
- else {
- ++i;
- ch = 65536 + (((ch & 1023) << 10) | (`c`.charCodeAt(i) & 1023));
- result[r] = (ch >> 18) | 240;
- ++r;
- result[r] = ((ch >> 12) & 63) | 128;
- }
- ++r;
- result[r] = ((ch >> 6) & 63) | 128;
- }
- ++r;
- result[r] = (ch & 63) | 128;
- }
- ++r;
- }
- return result;
- """.}
- proc toJSStr(s: string): cstring {.compilerproc.} =
- proc fromCharCode(c: char): cstring {.importc: "String.fromCharCode".}
- proc join(x: openArray[cstring]; d = cstring""): cstring {.
- importcpp: "#.join(@)".}
- proc decodeURIComponent(x: cstring): cstring {.
- importc: "decodeURIComponent".}
- proc toHexString(c: char; d = 16): cstring {.importcpp: "#.toString(@)".}
- proc log(x: cstring) {.importc: "console.log".}
- var res = newSeq[cstring](s.len)
- var i = 0
- var j = 0
- while i < s.len:
- var c = s[i]
- if c < '\128':
- res[j] = fromCharCode(c)
- inc i
- else:
- var helper = newSeq[cstring]()
- while true:
- let code = toHexString(c)
- if code.len == 1:
- helper.add cstring"%0"
- else:
- helper.add cstring"%"
- helper.add code
- inc i
- if i >= s.len or s[i] < '\128': break
- c = s[i]
- try:
- res[j] = decodeURIComponent join(helper)
- except:
- res[j] = join(helper)
- inc j
- setLen(res, j)
- result = join(res)
- proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
- asm """
- return new Array(`len`);
- """
- proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
- # argument type is a fake
- asm """
- var result = 0;
- for (var elem in `a`) { ++result; }
- return result;
- """
- proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
- asm """
- for (var elem in `a`) { if (!`b`[elem]) return false; }
- for (var elem in `b`) { if (!`a`[elem]) return false; }
- return true;
- """
- proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
- asm """
- for (var elem in `a`) { if (!`b`[elem]) return false; }
- return true;
- """
- proc SetLt(a, b: int): bool {.compilerproc.} =
- result = SetLe(a, b) and not SetEq(a, b)
- proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
- asm """
- var result = {};
- for (var elem in `a`) {
- if (`b`[elem]) { result[elem] = true; }
- }
- return result;
- """
- proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
- asm """
- var result = {};
- for (var elem in `a`) { result[elem] = true; }
- for (var elem in `b`) { result[elem] = true; }
- return result;
- """
- proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
- asm """
- var result = {};
- for (var elem in `a`) {
- if (!`b`[elem]) { result[elem] = true; }
- }
- return result;
- """
- proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`a` == `b`) return 0;
- if (!`a`) return -1;
- if (!`b`) return 1;
- for (var i = 0; i < `a`.length && i < `b`.length; i++) {
- var result = `a`[i] - `b`[i];
- if (result != 0) return result;
- }
- return `a`.length - `b`.length;
- """
- proc cmp(x, y: string): int =
- when nimvm:
- if x == y: result = 0
- elif x < y: result = -1
- else: result = 1
- else:
- result = cmpStrings(x, y)
- proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`a` == `b`) return true;
- if (`a` === null && `b`.length == 0) return true;
- if (`b` === null && `a`.length == 0) return true;
- if ((!`a`) || (!`b`)) return false;
- var alen = `a`.length;
- if (alen != `b`.length) return false;
- for (var i = 0; i < alen; ++i)
- if (`a`[i] != `b`[i]) return false;
- return true;
- """
- when defined(kwin):
- proc rawEcho {.compilerproc, asmNoStackFrame.} =
- asm """
- var buf = "";
- for (var i = 0; i < arguments.length; ++i) {
- buf += `toJSStr`(arguments[i]);
- }
- print(buf);
- """
- elif not defined(nimOldEcho):
- proc ewriteln(x: cstring) = log(x)
- proc rawEcho {.compilerproc, asmNoStackFrame.} =
- asm """
- var buf = "";
- for (var i = 0; i < arguments.length; ++i) {
- buf += `toJSStr`(arguments[i]);
- }
- console.log(buf);
- """
- else:
- proc ewriteln(x: cstring) =
- var node : JSRef
- {.emit: "`node` = document.getElementsByTagName('body')[0];".}
- if node.isNil:
- raise newException(ValueError, "<body> element does not exist yet!")
- {.emit: """
- `node`.appendChild(document.createTextNode(`x`));
- `node`.appendChild(document.createElement("br"));
- """.}
- proc rawEcho {.compilerproc.} =
- var node : JSRef
- {.emit: "`node` = document.getElementsByTagName('body')[0];".}
- if node.isNil:
- raise newException(IOError, "<body> element does not exist yet!")
- {.emit: """
- for (var i = 0; i < arguments.length; ++i) {
- var x = `toJSStr`(arguments[i]);
- `node`.appendChild(document.createTextNode(x));
- }
- `node`.appendChild(document.createElement("br"));
- """.}
- # Arithmetic:
- proc checkOverflowInt(a: int) {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`a` > 2147483647 || `a` < -2147483648) `raiseOverflow`();
- """
- proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
- asm """
- var result = `a` + `b`;
- `checkOverflowInt`(result);
- return result;
- """
- proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
- asm """
- var result = `a` - `b`;
- `checkOverflowInt`(result);
- return result;
- """
- proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
- asm """
- var result = `a` * `b`;
- `checkOverflowInt`(result);
- return result;
- """
- proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`b` == 0) `raiseDivByZero`();
- if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
- return Math.trunc(`a` / `b`);
- """
- proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`b` == 0) `raiseDivByZero`();
- if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
- return Math.trunc(`a` % `b`);
- """
- proc checkOverflowInt64(a: int64) {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`a` > 9223372036854775807n || `a` < -9223372036854775808n) `raiseOverflow`();
- """
- proc addInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
- asm """
- var result = `a` + `b`;
- `checkOverflowInt64`(result);
- return result;
- """
- proc subInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
- asm """
- var result = `a` - `b`;
- `checkOverflowInt64`(result);
- return result;
- """
- proc mulInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
- asm """
- var result = `a` * `b`;
- `checkOverflowInt64`(result);
- return result;
- """
- proc divInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`b` == 0n) `raiseDivByZero`();
- if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`();
- return `a` / `b`;
- """
- proc modInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} =
- asm """
- if (`b` == 0n) `raiseDivByZero`();
- if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`();
- return `a` % `b`;
- """
- proc negInt(a: int): int {.compilerproc.} =
- result = a*(-1)
- proc negInt64(a: int64): int64 {.compilerproc.} =
- result = a*(-1)
- proc absInt(a: int): int {.compilerproc.} =
- result = if a < 0: a*(-1) else: a
- proc absInt64(a: int64): int64 {.compilerproc.} =
- result = if a < 0: a*(-1) else: a
- proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
- proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
- proc chckNilDisp(p: pointer) {.compilerproc.} =
- if p == nil:
- sysFatal(NilAccessDefect, "cannot dispatch; dispatcher is nil")
- include "system/hti"
- proc isFatPointer(ti: PNimType): bool =
- # This has to be consistent with the code generator!
- return ti.base.kind notin {tyObject,
- tyArray, tyArrayConstr, tyTuple,
- tyOpenArray, tySet, tyVar, tyRef, tyPtr}
- proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef {.compilerproc.}
- proc nimCopyAux(dest, src: JSRef, n: ptr TNimNode) {.compilerproc.} =
- case n.kind
- of nkNone: sysAssert(false, "nimCopyAux")
- of nkSlot:
- asm """
- `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
- """
- of nkList:
- asm """
- for (var i = 0; i < `n`.sons.length; i++) {
- nimCopyAux(`dest`, `src`, `n`.sons[i]);
- }
- """
- of nkCase:
- asm """
- `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
- for (var i = 0; i < `n`.sons.length; ++i) {
- nimCopyAux(`dest`, `src`, `n`.sons[i][1]);
- }
- """
- proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
- case ti.kind
- of tyPtr, tyRef, tyVar, tyNil:
- if not isFatPointer(ti):
- result = src
- else:
- asm "`result` = [`src`[0], `src`[1]];"
- of tySet:
- asm """
- if (`dest` === null || `dest` === undefined) {
- `dest` = {};
- }
- else {
- for (var key in `dest`) { delete `dest`[key]; }
- }
- for (var key in `src`) { `dest`[key] = `src`[key]; }
- `result` = `dest`;
- """
- of tyTuple, tyObject:
- if ti.base != nil: result = nimCopy(dest, src, ti.base)
- elif ti.kind == tyObject:
- asm "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;"
- else:
- asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;"
- nimCopyAux(result, src, ti.node)
- of tyArrayConstr, tyArray:
- # In order to prevent a type change (TypedArray -> Array) and to have better copying performance,
- # arrays constructors are considered separately
- asm """
- if(ArrayBuffer.isView(`src`)) {
- if(`dest` === null || `dest` === undefined || `dest`.length != `src`.length) {
- `dest` = new `src`.constructor(`src`);
- } else {
- `dest`.set(`src`, 0);
- }
- `result` = `dest`;
- } else {
- if (`src` === null) {
- `result` = null;
- }
- else {
- if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) {
- `dest` = new Array(`src`.length);
- }
- `result` = `dest`;
- for (var i = 0; i < `src`.length; ++i) {
- `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base);
- }
- }
- }
- """
- of tySequence, tyOpenArray:
- asm """
- if (`src` === null) {
- `result` = null;
- }
- else {
- if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) {
- `dest` = new Array(`src`.length);
- }
- `result` = `dest`;
- for (var i = 0; i < `src`.length; ++i) {
- `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base);
- }
- }
- """
- of tyString:
- asm """
- if (`src` !== null) {
- `result` = `src`.slice(0);
- }
- """
- else:
- result = src
- proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
- asm "`result` = null;"
- case ti.kind
- of tyPtr, tyRef, tyVar, tyNil:
- if isFatPointer(ti):
- asm """
- `result` = [null, 0];
- """
- of tySet:
- asm """
- `result` = {};
- """
- of tyTuple, tyObject:
- if ti.kind == tyObject:
- asm "`result` = {m_type: `ti`};"
- else:
- asm "`result` = {};"
- of tySequence, tyOpenArray, tyString:
- asm """
- `result` = [];
- """
- of tyArrayConstr, tyArray:
- asm """
- `result` = new Array(`x`.length);
- for (var i = 0; i < `x`.length; ++i) {
- `result`[i] = genericReset(`x`[i], `ti`.base);
- }
- """
- else:
- discard
- proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
- asmNoStackFrame, compilerproc.} =
- # types are fake
- asm """
- var result = new Array(`len`);
- for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`);
- return result;
- """
- proc chckIndx(i, a, b: int): int {.compilerproc.} =
- if i >= a and i <= b: return i
- else: raiseIndexError(i, a, b)
- proc chckRange(i, a, b: int): int {.compilerproc.} =
- if i >= a and i <= b: return i
- else: raiseRangeError()
- proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
- # checks if obj is of type subclass:
- var x = obj
- if x == subclass: return # optimized fast path
- while x != subclass:
- if x == nil:
- raise newException(ObjectConversionDefect, "invalid object conversion")
- x = x.base
- proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
- # checks if obj is of type subclass:
- var x = obj
- if x == subclass: return true # optimized fast path
- while x != subclass:
- if x == nil: return false
- x = x.base
- return true
- proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
- asm "`x`.push(`c`);"
- {.pop.}
- proc tenToThePowerOf(b: int): BiggestFloat =
- # xxx deadcode
- var b = b
- var a = 10.0
- result = 1.0
- while true:
- if (b and 1) == 1:
- result = result * a
- b = b shr 1
- if b == 0: break
- a = a * a
- const
- IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
- proc parseFloatNative(a: openarray[char]): float =
- var str = ""
- for x in a:
- str.add x
- let cstr = cstring str
- asm """
- `result` = Number(`cstr`);
- """
- proc nimParseBiggestFloat(s: openarray[char], number: var BiggestFloat): int {.compilerproc.} =
- var sign: bool
- var i = 0
- if s[i] == '+': inc(i)
- elif s[i] == '-':
- sign = true
- inc(i)
- if s[i] == 'N' or s[i] == 'n':
- if s[i+1] == 'A' or s[i+1] == 'a':
- if s[i+2] == 'N' or s[i+2] == 'n':
- if s[i+3] notin IdentChars:
- number = NaN
- return i+3
- return 0
- if s[i] == 'I' or s[i] == 'i':
- if s[i+1] == 'N' or s[i+1] == 'n':
- if s[i+2] == 'F' or s[i+2] == 'f':
- if s[i+3] notin IdentChars:
- number = if sign: -Inf else: Inf
- return i+3
- return 0
- var buf: string
- # we could also use an `array[char, N]` buffer to avoid reallocs, or
- # use a 2-pass algorithm that first computes the length.
- if sign: buf.add '-'
- template addInc =
- buf.add s[i]
- inc(i)
- template eatUnderscores =
- while s[i] == '_': inc(i)
- while s[i] in {'0'..'9'}: # Read integer part
- buf.add s[i]
- inc(i)
- eatUnderscores()
- if s[i] == '.': # Decimal?
- addInc()
- while s[i] in {'0'..'9'}: # Read fractional part
- addInc()
- eatUnderscores()
- # Again, read integer and fractional part
- if buf.len == ord(sign): return 0
- if s[i] in {'e', 'E'}: # Exponent?
- addInc()
- if s[i] == '+': inc(i)
- elif s[i] == '-': addInc()
- if s[i] notin {'0'..'9'}: return 0
- while s[i] in {'0'..'9'}:
- addInc()
- eatUnderscores()
- number = parseFloatNative(buf)
- result = i
- # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce
- # 'Math.trunc' for Nim's ``div`` and ``mod`` operators:
- when defined(nimJsMathTruncPolyfill):
- {.emit: """
- if (!Math.trunc) {
- Math.trunc = function(v) {
- v = +v;
- if (!isFinite(v)) return v;
- return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0);
- };
- }
- """.}
|