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