diff options
Diffstat (limited to 'lib/system/jssys.nim')
-rw-r--r-- | lib/system/jssys.nim | 557 |
1 files changed, 280 insertions, 277 deletions
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim index e12bab184..5599240fd 100644 --- a/lib/system/jssys.nim +++ b/lib/system/jssys.nim @@ -7,6 +7,9 @@ # distribution, for details about the copyright. # +include system/indexerrors +import std/private/miscdollars + proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.} type @@ -31,8 +34,6 @@ type JSRef = ref RootObj # Fake type. -{.deprecated: [TSafePoint: SafePoint, TCallFrame: CallFrame].} - var framePtr {.importc, nodecl, volatile.}: PCallFrame excHandler {.importc, nodecl, volatile.}: int = 0 @@ -48,7 +49,7 @@ proc nimCharToStr(x: char): string {.compilerproc.} = result[0] = x proc isNimException(): bool {.asmNoStackFrame.} = - asm "return `lastJSError`.m_type;" + {.emit: "return `lastJSError` && `lastJSError`.m_type;".} proc getCurrentException*(): ref Exception {.compilerRtl, benign.} = if isNimException(): result = cast[ref Exception](lastJSError) @@ -68,9 +69,16 @@ proc getCurrentExceptionMsg*(): string = return $msg return "" +proc setCurrentException*(exc: ref Exception) = + lastJSError = cast[PJSError](exc) + +proc closureIterSetupExc(e: ref Exception) {.compilerproc, inline.} = + ## Used to set up exception handling for closure iterators + setCurrentException(e) + proc auxWriteStackTrace(f: PCallFrame): string = type - TempFrame = tuple[procname: cstring, line: int] + TempFrame = tuple[procname: cstring, line: int, filename: cstring] var it = f i = 0 @@ -79,6 +87,7 @@ proc auxWriteStackTrace(f: PCallFrame): string = 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 @@ -92,10 +101,9 @@ proc auxWriteStackTrace(f: PCallFrame): string = 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) - if tempFrames[j].line > 0: - add(result, ", line: ") - add(result, $tempFrames[j].line) add(result, "\n") proc rawWriteStackTrace(): string = @@ -104,13 +112,18 @@ proc rawWriteStackTrace(): string = 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 != nil and e.msg[0] != '\0': + if e.msg.len != 0: add(buf, "Error: unhandled exception: ") add(buf, e.msg) else: @@ -120,8 +133,9 @@ proc unhandledException(e: ref Exception) {. add(buf, "]\n") when NimStackTrace: add(buf, rawWriteStackTrace()) - let cbuf : cstring = buf - framePtr = nil + let cbuf = cstring(buf) + when NimStackTrace: + framePtr = nil {.emit: """ if (typeof(Error) !== "undefined") { throw new Error(`cbuf`); @@ -138,35 +152,35 @@ proc raiseException(e: ref Exception, ename: cstring) {. unhandledException(e) when NimStackTrace: e.trace = rawWriteStackTrace() - asm "throw `e`;" + {.emit: "throw `e`;".} proc reraiseException() {.compilerproc, asmNoStackFrame.} = if lastJSError == nil: - raise newException(ReraiseError, "no exception to reraise") + raise newException(ReraiseDefect, "no exception to reraise") else: if excHandler == 0: if isNimException(): unhandledException(cast[ref Exception](lastJSError)) - asm "throw lastJSError;" + {.emit: "throw lastJSError;".} -proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerProc.} = - raise newException(OverflowError, "over- or underflow") +proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerproc.} = + raise newException(OverflowDefect, "over- or underflow") -proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerProc.} = - raise newException(DivByZeroError, "division by zero") +proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerproc.} = + raise newException(DivByZeroDefect, "division by zero") proc raiseRangeError() {.compilerproc, noreturn.} = - raise newException(RangeError, "value out of range") + raise newException(RangeDefect, "value out of range") -proc raiseIndexError() {.compilerproc, noreturn.} = - raise newException(IndexError, "index out of bounds") +proc raiseIndexError(i, a, b: int) {.compilerproc, noreturn.} = + raise newException(IndexDefect, formatErrorIndexBound(int(i), int(a), int(b))) -proc raiseFieldError(f: string) {.compilerproc, noreturn.} = - raise newException(FieldError, f & " is not accessible") +proc raiseFieldError2(f: string, discVal: string) {.compilerproc, noreturn.} = + raise newException(FieldDefect, formatFieldDefect(f, discVal)) proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = {}; for (var i = 0; i < arguments.length; ++i) { var x = arguments[i]; @@ -179,17 +193,14 @@ proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} = } } return result; - """ + """.} proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = {.emit: """ - var ln = `c`.length; - var result = new Array(ln + 1); - var i = 0; - for (; i < ln; ++i) { + var result = []; + for (var i = 0; i < `c`.length; ++i) { result[i] = `c`.charCodeAt(i); } - result[i] = 0; // terminating zero return result; """.} @@ -227,146 +238,159 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = } ++r; } - result[r] = 0; // terminating zero return result; """.} -proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = - asm """ - var len = `s`.length-1; - var asciiPart = new Array(len); - var fcc = String.fromCharCode; - var nonAsciiPart = null; - var nonAsciiOffset = 0; - for (var i = 0; i < len; ++i) { - if (nonAsciiPart !== null) { - var offset = (i - nonAsciiOffset) * 2; - var code = `s`[i].toString(16); - if (code.length == 1) { - code = "0"+code; - } - nonAsciiPart[offset] = "%"; - nonAsciiPart[offset + 1] = code; - } - else if (`s`[i] < 128) - asciiPart[i] = fcc(`s`[i]); - else { - asciiPart.length = i; - nonAsciiOffset = i; - nonAsciiPart = new Array((len - i) * 2); - --i; - } - } - asciiPart = asciiPart.join(""); - return (nonAsciiPart === null) ? - asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join("")); - """ +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 """ - var result = new Array(`len`+1); - result[0] = 0; - result[`len`] = 0; + {.emit: """ + var result = new Array(`len`); + for (var i = 0; i < `len`; i++) {result[i] = 0;} return result; - """ + """.} proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = # argument type is a fake - asm """ + {.emit: """ var result = 0; for (var elem in `a`) { ++result; } return result; - """ + """.} proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ 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 """ + {.emit: """ 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 """ + {.emit: """ var result = {}; for (var elem in `a`) { if (`b`[elem]) { result[elem] = true; } } return result; - """ + """.} proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} = - asm """ + {.emit: """ 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 """ + {.emit: """ var result = {}; for (var elem in `a`) { if (!`b`[elem]) { result[elem] = true; } } return result; - """ + """.} -proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = - asm """ +proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerproc.} = + {.emit: """ if (`a` == `b`) return 0; if (!`a`) return -1; if (!`b`) return 1; - for (var i = 0; i < `a`.length - 1 && i < `b`.length - 1; i++) { + 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 = - return cmpStrings(x, y) + 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 """ +proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerproc.} = + {.emit: """ 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 """ + {.emit: """ 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 """ + {.emit: """ var buf = ""; for (var i = 0; i < arguments.length; ++i) { buf += `toJSStr`(arguments[i]); } console.log(buf); - """ + """.} else: proc ewriteln(x: cstring) = @@ -393,78 +417,85 @@ else: """.} # Arithmetic: +proc checkOverflowInt(a: int) {.asmNoStackFrame, compilerproc.} = + {.emit: """ + if (`a` > 2147483647 || `a` < -2147483648) `raiseOverflow`(); + """.} + proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` + `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + `checkOverflowInt`(result); return result; - """ + """.} proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` - `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + `checkOverflowInt`(result); return result; - """ + """.} proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ var result = `a` * `b`; - if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); + `checkOverflowInt`(result); return result; - """ + """.} proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`b` == 0) `raiseDivByZero`(); if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); return Math.trunc(`a` / `b`); - """ + """.} proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ + {.emit: """ if (`b` == 0) `raiseDivByZero`(); if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); return Math.trunc(`a` % `b`); - """ + """.} -proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ +proc checkOverflowInt64(a: int64) {.asmNoStackFrame, compilerproc.} = + {.emit: """ + if (`a` > 9223372036854775807n || `a` < -9223372036854775808n) `raiseOverflow`(); + """.} + +proc addInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = + {.emit: """ var result = `a` + `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); + `checkOverflowInt64`(result); return result; - """ + """.} -proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ +proc subInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = + {.emit: """ var result = `a` - `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); + `checkOverflowInt64`(result); return result; - """ + """.} -proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ +proc mulInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = + {.emit: """ var result = `a` * `b`; - if (result > 9223372036854775807 - || result < -9223372036854775808) `raiseOverflow`(); + `checkOverflowInt64`(result); return result; - """ + """.} -proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` / `b`); - """ +proc divInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = + {.emit: """ + if (`b` == 0n) `raiseDivByZero`(); + if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); + return `a` / `b`; + """.} -proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = - asm """ - if (`b` == 0) `raiseDivByZero`(); - if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); - return Math.trunc(`a` % `b`); - """ +proc modInt64(a, b: int64): int64 {.asmNoStackFrame, compilerproc.} = + {.emit: """ + if (`b` == 0n) `raiseDivByZero`(); + if (`b` == -1n && `a` == 9223372036854775807n) `raiseOverflow`(); + return `a` % `b`; + """.} proc negInt(a: int): int {.compilerproc.} = result = a*(-1) @@ -478,35 +509,13 @@ proc absInt(a: int): int {.compilerproc.} = proc absInt64(a: int64): int64 {.compilerproc.} = result = if a < 0: a*(-1) else: a -proc ze*(a: int): int {.compilerproc.} = - result = a - -proc ze64*(a: int64): int64 {.compilerproc.} = - result = a - -proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} = - asm """ - return `a`; - """ - -proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} = - asm """ - return `a`; - """ - -proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} = - asm """ - return `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.} = +proc chckNilDisp(p: JSRef) {.compilerproc.} = if p == nil: - sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil") + sysFatal(NilAccessDefect, "cannot dispatch; dispatcher is nil") -type NimString = string # hack for hti.nim include "system/hti" proc isFatPointer(ti: PNimType): bool = @@ -521,19 +530,22 @@ proc nimCopyAux(dest, src: JSRef, n: ptr TNimNode) {.compilerproc.} = case n.kind of nkNone: sysAssert(false, "nimCopyAux") of nkSlot: - asm """ + {.emit: """ `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ); - """ + """.} of nkList: - for i in 0..n.len-1: - nimCopyAux(dest, src, n.sons[i]) + {.emit: """ + for (var i = 0; i < `n`.sons.length; i++) { + nimCopyAux(`dest`, `src`, `n`.sons[i]); + } + """.} of nkCase: - asm """ + {.emit: """ `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 @@ -541,9 +553,9 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = if not isFatPointer(ti): result = src else: - asm "`result` = [`src`[0], `src`[1]];" + {.emit: "`result` = [`src`[0], `src`[1]];".} of tySet: - asm """ + {.emit: """ if (`dest` === null || `dest` === undefined) { `dest` = {}; } @@ -552,84 +564,76 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef = } 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`;" + {.emit: "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;".} else: - asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;" + {.emit: "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;".} nimCopyAux(result, src, ti.node) - of tySequence, tyArrayConstr, tyOpenArray, tyArray: - asm """ + of tyArrayConstr, tyArray: + # In order to prevent a type change (TypedArray -> Array) and to have better copying performance, + # arrays constructors are considered separately + {.emit: """ + 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: + {.emit: """ if (`src` === null) { `result` = null; } else { - if (`dest` === null || `dest` === undefined) { + if (`dest` === null || `dest` === undefined || `dest`.length != `src`.length) { `dest` = new Array(`src`.length); } - else { - `dest`.length = `src`.length; - } `result` = `dest`; for (var i = 0; i < `src`.length; ++i) { `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base); } } - """ + """.} of tyString: - asm """ + {.emit: """ 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: - 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 """ + {.emit: """ 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() + else: raiseIndexError(i, a, b) proc chckRange(i, a, b: int): int {.compilerproc.} = if i >= a and i <= b: return i @@ -641,7 +645,7 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} = if x == subclass: return # optimized fast path while x != subclass: if x == nil: - raise newException(ObjectConversionError, "invalid object conversion") + raise newException(ObjectConversionDefect, "invalid object conversion") x = x.base proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = @@ -654,13 +658,12 @@ proc isObj(obj, subclass: PNimType): bool {.compilerproc.} = return true proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} = - asm """ - `x`[`x`.length-1] = `c`; `x`.push(0); - """ + {.emit: "`x`.push(`c`);".} {.pop.} proc tenToThePowerOf(b: int): BiggestFloat = + # xxx deadcode var b = b var a = 10.0 result = 1.0 @@ -674,92 +677,92 @@ proc tenToThePowerOf(b: int): BiggestFloat = const IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} -# XXX use JS's native way here -proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {. - compilerProc.} = - var - esign = 1.0 - sign = 1.0 - i = start - exponent: int - flags: int - number = 0.0 + +proc parseFloatNative(a: openarray[char]): float = + var str = "" + for x in a: + str.add x + + let cstr = cstring str + + {.emit: """ + `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 = -1.0 + 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 - start + 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 = Inf*sign - return i+3 - start + number = if sign: -Inf else: Inf + return i+3 return 0 - while s[i] in {'0'..'9'}: - # Read integer part - flags = flags or 1 - number = number * 10.0 + toFloat(ord(s[i]) - ord('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) - # Decimal? - if s[i] == '.': - var hd = 1.0 + while s[i] in {'0'..'9'}: # Read integer part + buf.add s[i] inc(i) - while s[i] in {'0'..'9'}: - # Read fractional part - flags = flags or 2 - number = number * 10.0 + toFloat(ord(s[i]) - ord('0')) - hd = hd * 10.0 - inc(i) - while s[i] == '_': inc(i) - number = number / hd # this complicated way preserves precision + eatUnderscores() + if s[i] == '.': # Decimal? + addInc() + while s[i] in {'0'..'9'}: # Read fractional part + addInc() + eatUnderscores() # Again, read integer and fractional part - if flags == 0: return 0 - # Exponent? - if s[i] in {'e', 'E'}: - inc(i) - if s[i] == '+': - inc(i) - elif s[i] == '-': - esign = -1.0 - inc(i) - if s[i] notin {'0'..'9'}: - return 0 + 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'}: - exponent = exponent * 10 + ord(s[i]) - ord('0') - inc(i) - while s[i] == '_': inc(i) - # Calculate Exponent - let hd = tenToThePowerOf(exponent) - if esign > 0.0: number = number * hd - else: number = number / hd - # evaluate sign - number = number * sign - result = i - start - -when defined(nodejs): - # Deprecated. Use `alert` defined in dom.nim - proc alert*(s: cstring) {.importc: "console.log", nodecl, deprecated.} -else: - # Deprecated. Use `alert` defined in dom.nim - proc alert*(s: cstring) {.importc, nodecl, deprecated.} + 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 not defined(nodejs): +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); + }; +} +""".} + +proc cmpClosures(a, b: JSRef): bool {.compilerproc, asmNoStackFrame.} = + # Both `a` and `b` need to be a closure {.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); - }; - }""".} + if (`a` !== null && `a`.ClP_0 !== undefined && + `b` !== null && `b`.ClP_0 !== undefined) { + return `a`.ClP_0 == `b`.ClP_0 && `a`.ClE_0 == `b`.ClE_0; + } else { + return `a` == `b`; + } + """ + .} |