jssys.nim 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. proc log*(s: cstring) {.importc: "console.log", varargs, nodecl.}
  10. type
  11. PSafePoint = ptr SafePoint
  12. SafePoint {.compilerproc, final.} = object
  13. prev: PSafePoint # points to next safe point
  14. exc: ref Exception
  15. PCallFrame = ptr CallFrame
  16. CallFrame {.importc, nodecl, final.} = object
  17. prev: PCallFrame
  18. procname: cstring
  19. line: int # current line number
  20. filename: cstring
  21. PJSError = ref object
  22. columnNumber {.importc.}: int
  23. fileName {.importc.}: cstring
  24. lineNumber {.importc.}: int
  25. message {.importc.}: cstring
  26. stack {.importc.}: cstring
  27. JSRef = ref RootObj # Fake type.
  28. var
  29. framePtr {.importc, nodecl, volatile.}: PCallFrame
  30. excHandler {.importc, nodecl, volatile.}: int = 0
  31. lastJSError {.importc, nodecl, volatile.}: PJSError = nil
  32. {.push stacktrace: off, profiler:off.}
  33. proc nimBoolToStr(x: bool): string {.compilerproc.} =
  34. if x: result = "true"
  35. else: result = "false"
  36. proc nimCharToStr(x: char): string {.compilerproc.} =
  37. result = newString(1)
  38. result[0] = x
  39. proc isNimException(): bool {.asmNoStackFrame.} =
  40. asm "return `lastJSError`.m_type;"
  41. proc getCurrentException*(): ref Exception {.compilerRtl, benign.} =
  42. if isNimException(): result = cast[ref Exception](lastJSError)
  43. proc getCurrentExceptionMsg*(): string =
  44. if lastJSError != nil:
  45. if isNimException():
  46. return cast[Exception](lastJSError).msg
  47. else:
  48. var msg: cstring
  49. {.emit: """
  50. if (`lastJSError`.message !== undefined) {
  51. `msg` = `lastJSError`.message;
  52. }
  53. """.}
  54. if not msg.isNil:
  55. return $msg
  56. return ""
  57. proc auxWriteStackTrace(f: PCallFrame): string =
  58. type
  59. TempFrame = tuple[procname: cstring, line: int]
  60. var
  61. it = f
  62. i = 0
  63. total = 0
  64. tempFrames: array[0..63, TempFrame]
  65. while it != nil and i <= high(tempFrames):
  66. tempFrames[i].procname = it.procname
  67. tempFrames[i].line = it.line
  68. inc(i)
  69. inc(total)
  70. it = it.prev
  71. while it != nil:
  72. inc(total)
  73. it = it.prev
  74. result = ""
  75. # if the buffer overflowed print '...':
  76. if total != i:
  77. add(result, "(")
  78. add(result, $(total-i))
  79. add(result, " calls omitted) ...\n")
  80. for j in countdown(i-1, 0):
  81. add(result, tempFrames[j].procname)
  82. if tempFrames[j].line > 0:
  83. add(result, ", line: ")
  84. add(result, $tempFrames[j].line)
  85. add(result, "\n")
  86. proc rawWriteStackTrace(): string =
  87. if framePtr != nil:
  88. result = "Traceback (most recent call last)\n" & auxWriteStackTrace(framePtr)
  89. else:
  90. result = "No stack traceback available\n"
  91. proc getStackTrace*(): string = rawWriteStackTrace()
  92. proc getStackTrace*(e: ref Exception): string = e.trace
  93. proc unhandledException(e: ref Exception) {.
  94. compilerproc, asmNoStackFrame.} =
  95. var buf = ""
  96. if e.msg.len != 0:
  97. add(buf, "Error: unhandled exception: ")
  98. add(buf, e.msg)
  99. else:
  100. add(buf, "Error: unhandled exception")
  101. add(buf, " [")
  102. add(buf, e.name)
  103. add(buf, "]\n")
  104. when NimStackTrace:
  105. add(buf, rawWriteStackTrace())
  106. let cbuf : cstring = buf
  107. framePtr = nil
  108. {.emit: """
  109. if (typeof(Error) !== "undefined") {
  110. throw new Error(`cbuf`);
  111. }
  112. else {
  113. throw `cbuf`;
  114. }
  115. """.}
  116. proc raiseException(e: ref Exception, ename: cstring) {.
  117. compilerproc, asmNoStackFrame.} =
  118. e.name = ename
  119. if excHandler == 0:
  120. unhandledException(e)
  121. when NimStackTrace:
  122. e.trace = rawWriteStackTrace()
  123. asm "throw `e`;"
  124. proc reraiseException() {.compilerproc, asmNoStackFrame.} =
  125. if lastJSError == nil:
  126. raise newException(ReraiseError, "no exception to reraise")
  127. else:
  128. if excHandler == 0:
  129. if isNimException():
  130. unhandledException(cast[ref Exception](lastJSError))
  131. asm "throw lastJSError;"
  132. proc raiseOverflow {.exportc: "raiseOverflow", noreturn, compilerProc.} =
  133. raise newException(OverflowError, "over- or underflow")
  134. proc raiseDivByZero {.exportc: "raiseDivByZero", noreturn, compilerProc.} =
  135. raise newException(DivByZeroError, "division by zero")
  136. proc raiseRangeError() {.compilerproc, noreturn.} =
  137. raise newException(RangeError, "value out of range")
  138. proc raiseIndexError() {.compilerproc, noreturn.} =
  139. raise newException(IndexError, "index out of bounds")
  140. proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
  141. raise newException(FieldError, f & " is not accessible")
  142. proc setConstr() {.varargs, asmNoStackFrame, compilerproc.} =
  143. asm """
  144. var result = {};
  145. for (var i = 0; i < arguments.length; ++i) {
  146. var x = arguments[i];
  147. if (typeof(x) == "object") {
  148. for (var j = x[0]; j <= x[1]; ++j) {
  149. result[j] = true;
  150. }
  151. } else {
  152. result[x] = true;
  153. }
  154. }
  155. return result;
  156. """
  157. proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
  158. {.emit: """
  159. var ln = `c`.length;
  160. var result = new Array(ln);
  161. for (var i = 0; i < ln; ++i) {
  162. result[i] = `c`.charCodeAt(i);
  163. }
  164. return result;
  165. """.}
  166. proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
  167. {.emit: """
  168. var ln = `c`.length;
  169. var result = new Array(ln);
  170. var r = 0;
  171. for (var i = 0; i < ln; ++i) {
  172. var ch = `c`.charCodeAt(i);
  173. if (ch < 128) {
  174. result[r] = ch;
  175. }
  176. else {
  177. if (ch < 2048) {
  178. result[r] = (ch >> 6) | 192;
  179. }
  180. else {
  181. if (ch < 55296 || ch >= 57344) {
  182. result[r] = (ch >> 12) | 224;
  183. }
  184. else {
  185. ++i;
  186. ch = 65536 + (((ch & 1023) << 10) | (`c`.charCodeAt(i) & 1023));
  187. result[r] = (ch >> 18) | 240;
  188. ++r;
  189. result[r] = ((ch >> 12) & 63) | 128;
  190. }
  191. ++r;
  192. result[r] = ((ch >> 6) & 63) | 128;
  193. }
  194. ++r;
  195. result[r] = (ch & 63) | 128;
  196. }
  197. ++r;
  198. }
  199. return result;
  200. """.}
  201. proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
  202. asm """
  203. if (`s` === null) return "";
  204. var len = `s`.length;
  205. var asciiPart = new Array(len);
  206. var fcc = String.fromCharCode;
  207. var nonAsciiPart = null;
  208. var nonAsciiOffset = 0;
  209. for (var i = 0; i < len; ++i) {
  210. if (nonAsciiPart !== null) {
  211. var offset = (i - nonAsciiOffset) * 2;
  212. var code = `s`[i].toString(16);
  213. if (code.length == 1) {
  214. code = "0"+code;
  215. }
  216. nonAsciiPart[offset] = "%";
  217. nonAsciiPart[offset + 1] = code;
  218. }
  219. else if (`s`[i] < 128)
  220. asciiPart[i] = fcc(`s`[i]);
  221. else {
  222. asciiPart.length = i;
  223. nonAsciiOffset = i;
  224. nonAsciiPart = new Array((len - i) * 2);
  225. --i;
  226. }
  227. }
  228. asciiPart = asciiPart.join("");
  229. return (nonAsciiPart === null) ?
  230. asciiPart : asciiPart + decodeURIComponent(nonAsciiPart.join(""));
  231. """
  232. proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
  233. asm """
  234. return new Array(`len`);
  235. """
  236. proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
  237. # argument type is a fake
  238. asm """
  239. var result = 0;
  240. for (var elem in `a`) { ++result; }
  241. return result;
  242. """
  243. proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
  244. asm """
  245. for (var elem in `a`) { if (!`b`[elem]) return false; }
  246. for (var elem in `b`) { if (!`a`[elem]) return false; }
  247. return true;
  248. """
  249. proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
  250. asm """
  251. for (var elem in `a`) { if (!`b`[elem]) return false; }
  252. return true;
  253. """
  254. proc SetLt(a, b: int): bool {.compilerproc.} =
  255. result = SetLe(a, b) and not SetEq(a, b)
  256. proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  257. asm """
  258. var result = {};
  259. for (var elem in `a`) {
  260. if (`b`[elem]) { result[elem] = true; }
  261. }
  262. return result;
  263. """
  264. proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  265. asm """
  266. var result = {};
  267. for (var elem in `a`) { result[elem] = true; }
  268. for (var elem in `b`) { result[elem] = true; }
  269. return result;
  270. """
  271. proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
  272. asm """
  273. var result = {};
  274. for (var elem in `a`) {
  275. if (!`b`[elem]) { result[elem] = true; }
  276. }
  277. return result;
  278. """
  279. proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
  280. asm """
  281. if (`a` == `b`) return 0;
  282. if (!`a`) return -1;
  283. if (!`b`) return 1;
  284. for (var i = 0; i < `a`.length && i < `b`.length; i++) {
  285. var result = `a`[i] - `b`[i];
  286. if (result != 0) return result;
  287. }
  288. return `a`.length - `b`.length;
  289. """
  290. proc cmp(x, y: string): int =
  291. return cmpStrings(x, y)
  292. proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
  293. asm """
  294. if (`a` == `b`) return true;
  295. if (`a` === null && `b`.length == 0) return true;
  296. if (`b` === null && `a`.length == 0) return true;
  297. if ((!`a`) || (!`b`)) return false;
  298. var alen = `a`.length;
  299. if (alen != `b`.length) return false;
  300. for (var i = 0; i < alen; ++i)
  301. if (`a`[i] != `b`[i]) return false;
  302. return true;
  303. """
  304. when defined(kwin):
  305. proc rawEcho {.compilerproc, asmNoStackFrame.} =
  306. asm """
  307. var buf = "";
  308. for (var i = 0; i < arguments.length; ++i) {
  309. buf += `toJSStr`(arguments[i]);
  310. }
  311. print(buf);
  312. """
  313. elif not defined(nimOldEcho):
  314. proc ewriteln(x: cstring) = log(x)
  315. proc rawEcho {.compilerproc, asmNoStackFrame.} =
  316. asm """
  317. var buf = "";
  318. for (var i = 0; i < arguments.length; ++i) {
  319. buf += `toJSStr`(arguments[i]);
  320. }
  321. console.log(buf);
  322. """
  323. else:
  324. proc ewriteln(x: cstring) =
  325. var node : JSRef
  326. {.emit: "`node` = document.getElementsByTagName('body')[0];".}
  327. if node.isNil:
  328. raise newException(ValueError, "<body> element does not exist yet!")
  329. {.emit: """
  330. `node`.appendChild(document.createTextNode(`x`));
  331. `node`.appendChild(document.createElement("br"));
  332. """.}
  333. proc rawEcho {.compilerproc.} =
  334. var node : JSRef
  335. {.emit: "`node` = document.getElementsByTagName('body')[0];".}
  336. if node.isNil:
  337. raise newException(IOError, "<body> element does not exist yet!")
  338. {.emit: """
  339. for (var i = 0; i < arguments.length; ++i) {
  340. var x = `toJSStr`(arguments[i]);
  341. `node`.appendChild(document.createTextNode(x));
  342. }
  343. `node`.appendChild(document.createElement("br"));
  344. """.}
  345. # Arithmetic:
  346. proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  347. asm """
  348. var result = `a` + `b`;
  349. if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
  350. return result;
  351. """
  352. proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  353. asm """
  354. var result = `a` - `b`;
  355. if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
  356. return result;
  357. """
  358. proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  359. asm """
  360. var result = `a` * `b`;
  361. if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
  362. return result;
  363. """
  364. proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  365. asm """
  366. if (`b` == 0) `raiseDivByZero`();
  367. if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
  368. return Math.trunc(`a` / `b`);
  369. """
  370. proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  371. asm """
  372. if (`b` == 0) `raiseDivByZero`();
  373. if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
  374. return Math.trunc(`a` % `b`);
  375. """
  376. proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  377. asm """
  378. var result = `a` + `b`;
  379. if (result > 9223372036854775807
  380. || result < -9223372036854775808) `raiseOverflow`();
  381. return result;
  382. """
  383. proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  384. asm """
  385. var result = `a` - `b`;
  386. if (result > 9223372036854775807
  387. || result < -9223372036854775808) `raiseOverflow`();
  388. return result;
  389. """
  390. proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  391. asm """
  392. var result = `a` * `b`;
  393. if (result > 9223372036854775807
  394. || result < -9223372036854775808) `raiseOverflow`();
  395. return result;
  396. """
  397. proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  398. asm """
  399. if (`b` == 0) `raiseDivByZero`();
  400. if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
  401. return Math.trunc(`a` / `b`);
  402. """
  403. proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
  404. asm """
  405. if (`b` == 0) `raiseDivByZero`();
  406. if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
  407. return Math.trunc(`a` % `b`);
  408. """
  409. proc negInt(a: int): int {.compilerproc.} =
  410. result = a*(-1)
  411. proc negInt64(a: int64): int64 {.compilerproc.} =
  412. result = a*(-1)
  413. proc absInt(a: int): int {.compilerproc.} =
  414. result = if a < 0: a*(-1) else: a
  415. proc absInt64(a: int64): int64 {.compilerproc.} =
  416. result = if a < 0: a*(-1) else: a
  417. proc ze*(a: int): int {.compilerproc.} =
  418. result = a
  419. proc ze64*(a: int64): int64 {.compilerproc.} =
  420. result = a
  421. proc toU8*(a: int): int8 {.asmNoStackFrame, compilerproc.} =
  422. asm """
  423. return `a`;
  424. """
  425. proc toU16*(a: int): int16 {.asmNoStackFrame, compilerproc.} =
  426. asm """
  427. return `a`;
  428. """
  429. proc toU32*(a: int64): int32 {.asmNoStackFrame, compilerproc.} =
  430. asm """
  431. return `a`;
  432. """
  433. proc nimMin(a, b: int): int {.compilerproc.} = return if a <= b: a else: b
  434. proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
  435. proc chckNilDisp(p: pointer) {.compilerproc.} =
  436. if p == nil:
  437. sysFatal(NilAccessError, "cannot dispatch; dispatcher is nil")
  438. include "system/hti"
  439. proc isFatPointer(ti: PNimType): bool =
  440. # This has to be consistent with the code generator!
  441. return ti.base.kind notin {tyObject,
  442. tyArray, tyArrayConstr, tyTuple,
  443. tyOpenArray, tySet, tyVar, tyRef, tyPtr}
  444. proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef {.compilerproc.}
  445. proc nimCopyAux(dest, src: JSRef, n: ptr TNimNode) {.compilerproc.} =
  446. case n.kind
  447. of nkNone: sysAssert(false, "nimCopyAux")
  448. of nkSlot:
  449. asm """
  450. `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
  451. """
  452. of nkList:
  453. asm """
  454. for (var i = 0; i < `n`.sons.length; i++) {
  455. nimCopyAux(`dest`, `src`, `n`.sons[i]);
  456. }
  457. """
  458. of nkCase:
  459. asm """
  460. `dest`[`n`.offset] = nimCopy(`dest`[`n`.offset], `src`[`n`.offset], `n`.typ);
  461. for (var i = 0; i < `n`.sons.length; ++i) {
  462. nimCopyAux(`dest`, `src`, `n`.sons[i][1]);
  463. }
  464. """
  465. proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
  466. case ti.kind
  467. of tyPtr, tyRef, tyVar, tyNil:
  468. if not isFatPointer(ti):
  469. result = src
  470. else:
  471. asm "`result` = [`src`[0], `src`[1]];"
  472. of tySet:
  473. asm """
  474. if (`dest` === null || `dest` === undefined) {
  475. `dest` = {};
  476. }
  477. else {
  478. for (var key in `dest`) { delete `dest`[key]; }
  479. }
  480. for (var key in `src`) { `dest`[key] = `src`[key]; }
  481. `result` = `dest`;
  482. """
  483. of tyTuple, tyObject:
  484. if ti.base != nil: result = nimCopy(dest, src, ti.base)
  485. elif ti.kind == tyObject:
  486. asm "`result` = (`dest` === null || `dest` === undefined) ? {m_type: `ti`} : `dest`;"
  487. else:
  488. asm "`result` = (`dest` === null || `dest` === undefined) ? {} : `dest`;"
  489. nimCopyAux(result, src, ti.node)
  490. of tySequence, tyArrayConstr, tyOpenArray, tyArray:
  491. asm """
  492. if (`src` === null) {
  493. `result` = null;
  494. }
  495. else {
  496. if (`dest` === null || `dest` === undefined) {
  497. `dest` = new Array(`src`.length);
  498. }
  499. else {
  500. `dest`.length = `src`.length;
  501. }
  502. `result` = `dest`;
  503. for (var i = 0; i < `src`.length; ++i) {
  504. `result`[i] = nimCopy(`result`[i], `src`[i], `ti`.base);
  505. }
  506. }
  507. """
  508. of tyString:
  509. asm """
  510. if (`src` !== null) {
  511. `result` = `src`.slice(0);
  512. }
  513. """
  514. else:
  515. result = src
  516. proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
  517. asm "`result` = null;"
  518. case ti.kind
  519. of tyPtr, tyRef, tyVar, tyNil:
  520. if isFatPointer(ti):
  521. asm """
  522. `result` = [null, 0];
  523. """
  524. of tySet:
  525. asm """
  526. `result` = {};
  527. """
  528. of tyTuple, tyObject:
  529. if ti.kind == tyObject:
  530. asm "`result` = {m_type: `ti`};"
  531. else:
  532. asm "`result` = {};"
  533. of tySequence, tyOpenArray:
  534. asm """
  535. `result` = [];
  536. """
  537. of tyArrayConstr, tyArray:
  538. asm """
  539. `result` = new Array(`x`.length);
  540. for (var i = 0; i < `x`.length; ++i) {
  541. `result`[i] = genericReset(`x`[i], `ti`.base);
  542. }
  543. """
  544. else:
  545. discard
  546. proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
  547. asmNoStackFrame, compilerproc.} =
  548. # types are fake
  549. asm """
  550. var result = new Array(`len`);
  551. for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`);
  552. return result;
  553. """
  554. proc chckIndx(i, a, b: int): int {.compilerproc.} =
  555. if i >= a and i <= b: return i
  556. else: raiseIndexError()
  557. proc chckRange(i, a, b: int): int {.compilerproc.} =
  558. if i >= a and i <= b: return i
  559. else: raiseRangeError()
  560. proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
  561. # checks if obj is of type subclass:
  562. var x = obj
  563. if x == subclass: return # optimized fast path
  564. while x != subclass:
  565. if x == nil:
  566. raise newException(ObjectConversionError, "invalid object conversion")
  567. x = x.base
  568. proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
  569. # checks if obj is of type subclass:
  570. var x = obj
  571. if x == subclass: return true # optimized fast path
  572. while x != subclass:
  573. if x == nil: return false
  574. x = x.base
  575. return true
  576. proc addChar(x: string, c: char) {.compilerproc, asmNoStackFrame.} =
  577. asm "`x`.push(`c`);"
  578. {.pop.}
  579. proc tenToThePowerOf(b: int): BiggestFloat =
  580. var b = b
  581. var a = 10.0
  582. result = 1.0
  583. while true:
  584. if (b and 1) == 1:
  585. result = result * a
  586. b = b shr 1
  587. if b == 0: break
  588. a = a * a
  589. const
  590. IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
  591. # XXX use JS's native way here
  592. proc nimParseBiggestFloat(s: string, number: var BiggestFloat, start = 0): int {.
  593. compilerProc.} =
  594. var
  595. esign = 1.0
  596. sign = 1.0
  597. i = start
  598. exponent: int
  599. flags: int
  600. number = 0.0
  601. if s[i] == '+': inc(i)
  602. elif s[i] == '-':
  603. sign = -1.0
  604. inc(i)
  605. if s[i] == 'N' or s[i] == 'n':
  606. if s[i+1] == 'A' or s[i+1] == 'a':
  607. if s[i+2] == 'N' or s[i+2] == 'n':
  608. if s[i+3] notin IdentChars:
  609. number = NaN
  610. return i+3 - start
  611. return 0
  612. if s[i] == 'I' or s[i] == 'i':
  613. if s[i+1] == 'N' or s[i+1] == 'n':
  614. if s[i+2] == 'F' or s[i+2] == 'f':
  615. if s[i+3] notin IdentChars:
  616. number = Inf*sign
  617. return i+3 - start
  618. return 0
  619. while s[i] in {'0'..'9'}:
  620. # Read integer part
  621. flags = flags or 1
  622. number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
  623. inc(i)
  624. while s[i] == '_': inc(i)
  625. # Decimal?
  626. if s[i] == '.':
  627. var hd = 1.0
  628. inc(i)
  629. while s[i] in {'0'..'9'}:
  630. # Read fractional part
  631. flags = flags or 2
  632. number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
  633. hd = hd * 10.0
  634. inc(i)
  635. while s[i] == '_': inc(i)
  636. number = number / hd # this complicated way preserves precision
  637. # Again, read integer and fractional part
  638. if flags == 0: return 0
  639. # Exponent?
  640. if s[i] in {'e', 'E'}:
  641. inc(i)
  642. if s[i] == '+':
  643. inc(i)
  644. elif s[i] == '-':
  645. esign = -1.0
  646. inc(i)
  647. if s[i] notin {'0'..'9'}:
  648. return 0
  649. while s[i] in {'0'..'9'}:
  650. exponent = exponent * 10 + ord(s[i]) - ord('0')
  651. inc(i)
  652. while s[i] == '_': inc(i)
  653. # Calculate Exponent
  654. let hd = tenToThePowerOf(exponent)
  655. if esign > 0.0: number = number * hd
  656. else: number = number / hd
  657. # evaluate sign
  658. number = number * sign
  659. result = i - start
  660. when defined(nodejs):
  661. # Deprecated. Use `alert` defined in dom.nim
  662. proc alert*(s: cstring) {.importc: "console.log", nodecl, deprecated.}
  663. else:
  664. # Deprecated. Use `alert` defined in dom.nim
  665. proc alert*(s: cstring) {.importc, nodecl, deprecated.}
  666. # Workaround for IE, IE up to version 11 lacks 'Math.trunc'. We produce
  667. # 'Math.trunc' for Nim's ``div`` and ``mod`` operators:
  668. when not defined(nodejs):
  669. {.emit: """
  670. if (!Math.trunc) {
  671. Math.trunc = function(v) {
  672. v = +v;
  673. if (!isFinite(v)) return v;
  674. return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0);
  675. };
  676. }""".}