jssys.nim 21 KB

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