jssys.nim 21 KB

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