jssys.nim 20 KB

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