sci2-ts 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (357) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/LICENSE +21 -0
  3. package/README.md +113 -2
  4. package/apps/viewer/editor.html +43 -0
  5. package/apps/viewer/explore.html +27 -0
  6. package/apps/viewer/index.html +26 -0
  7. package/apps/viewer/package.json +27 -0
  8. package/apps/viewer/play.html +26 -0
  9. package/apps/viewer/plugin.d.ts +18 -0
  10. package/apps/viewer/plugin.js +75 -0
  11. package/apps/viewer/plugin.ts +84 -0
  12. package/apps/viewer/src/adlib.d.ts +20 -0
  13. package/apps/viewer/src/adlib.js +55 -0
  14. package/apps/viewer/src/adlib.ts +62 -0
  15. package/apps/viewer/src/app.d.ts +5 -0
  16. package/apps/viewer/src/app.js +5 -0
  17. package/apps/viewer/src/app.ts +5 -0
  18. package/apps/viewer/src/asset-index.d.ts +22 -0
  19. package/apps/viewer/src/asset-index.js +74 -0
  20. package/apps/viewer/src/asset-index.ts +90 -0
  21. package/apps/viewer/src/audio.d.ts +28 -0
  22. package/apps/viewer/src/audio.js +102 -0
  23. package/apps/viewer/src/audio.ts +110 -0
  24. package/apps/viewer/src/editor-handles.d.ts +63 -0
  25. package/apps/viewer/src/editor-handles.js +332 -0
  26. package/apps/viewer/src/editor-handles.ts +368 -0
  27. package/apps/viewer/src/editor-languages.d.ts +23 -0
  28. package/apps/viewer/src/editor-languages.js +157 -0
  29. package/apps/viewer/src/editor-languages.ts +135 -0
  30. package/apps/viewer/src/editor.css +213 -0
  31. package/apps/viewer/src/editor.d.ts +1 -0
  32. package/apps/viewer/src/editor.js +393 -0
  33. package/apps/viewer/src/editor.ts +412 -0
  34. package/apps/viewer/src/explore/classes.d.ts +7 -0
  35. package/apps/viewer/src/explore/classes.js +63 -0
  36. package/apps/viewer/src/explore/classes.ts +61 -0
  37. package/apps/viewer/src/explore/context.d.ts +33 -0
  38. package/apps/viewer/src/explore/context.js +96 -0
  39. package/apps/viewer/src/explore/context.ts +124 -0
  40. package/apps/viewer/src/explore/explore.css +93 -0
  41. package/apps/viewer/src/explore/explore.d.ts +1 -0
  42. package/apps/viewer/src/explore/explore.js +102 -0
  43. package/apps/viewer/src/explore/explore.ts +104 -0
  44. package/apps/viewer/src/explore/inspect.d.ts +5 -0
  45. package/apps/viewer/src/explore/inspect.js +208 -0
  46. package/apps/viewer/src/explore/inspect.ts +279 -0
  47. package/apps/viewer/src/explore/live.d.ts +22 -0
  48. package/apps/viewer/src/explore/live.js +318 -0
  49. package/apps/viewer/src/explore/live.ts +365 -0
  50. package/apps/viewer/src/explore/map.d.ts +11 -0
  51. package/apps/viewer/src/explore/map.js +182 -0
  52. package/apps/viewer/src/explore/map.ts +193 -0
  53. package/apps/viewer/src/files.d.ts +21 -0
  54. package/apps/viewer/src/files.js +69 -0
  55. package/apps/viewer/src/files.ts +72 -0
  56. package/apps/viewer/src/game-profile.d.ts +19 -0
  57. package/apps/viewer/src/game-profile.js +4 -0
  58. package/apps/viewer/src/game-profile.ts +26 -0
  59. package/apps/viewer/src/main.d.ts +1 -0
  60. package/apps/viewer/src/main.js +473 -0
  61. package/apps/viewer/src/main.ts +527 -0
  62. package/apps/viewer/src/music.d.ts +14 -0
  63. package/apps/viewer/src/music.js +32 -0
  64. package/apps/viewer/src/music.ts +34 -0
  65. package/apps/viewer/src/opl-worklet.d.ts +1 -0
  66. package/apps/viewer/src/opl-worklet.js +47 -0
  67. package/apps/viewer/src/opl-worklet.ts +55 -0
  68. package/apps/viewer/src/overlay.d.ts +31 -0
  69. package/apps/viewer/src/overlay.js +103 -0
  70. package/apps/viewer/src/overlay.ts +123 -0
  71. package/apps/viewer/src/play.css +14 -0
  72. package/apps/viewer/src/play.d.ts +1 -0
  73. package/apps/viewer/src/play.js +179 -0
  74. package/apps/viewer/src/play.ts +177 -0
  75. package/apps/viewer/src/saves.d.ts +10 -0
  76. package/apps/viewer/src/saves.js +50 -0
  77. package/apps/viewer/src/saves.ts +51 -0
  78. package/apps/viewer/src/session.d.ts +91 -0
  79. package/apps/viewer/src/session.js +301 -0
  80. package/apps/viewer/src/session.ts +321 -0
  81. package/apps/viewer/src/sound-preview.d.ts +7 -0
  82. package/apps/viewer/src/sound-preview.js +214 -0
  83. package/apps/viewer/src/sound-preview.ts +228 -0
  84. package/apps/viewer/src/style.css +64 -0
  85. package/apps/viewer/vite.config.ts +25 -0
  86. package/bin/sci-ts.mjs +9 -0
  87. package/lib/994.sc +49 -0
  88. package/lib/995.sc +53 -0
  89. package/lib/996.sc +299 -0
  90. package/lib/997.sc +198 -0
  91. package/lib/998.sc +338 -0
  92. package/lib/999.sc +189 -0
  93. package/lib/resources.d.ts +2 -0
  94. package/lib/resources.js +84 -0
  95. package/lib/resources.ts +88 -0
  96. package/lib/system.sh +62 -0
  97. package/package.json +75 -4
  98. package/packages/content/room.schema.json +267 -0
  99. package/packages/content/src/index.d.ts +3 -0
  100. package/packages/content/src/index.js +3 -0
  101. package/packages/content/src/index.ts +3 -0
  102. package/packages/content/src/room.d.ts +111 -0
  103. package/packages/content/src/room.js +886 -0
  104. package/packages/content/src/room.ts +1011 -0
  105. package/packages/content/src/target.d.ts +80 -0
  106. package/packages/content/src/target.js +1 -0
  107. package/packages/content/src/target.ts +60 -0
  108. package/packages/content/src/yarn.d.ts +90 -0
  109. package/packages/content/src/yarn.js +214 -0
  110. package/packages/content/src/yarn.ts +261 -0
  111. package/packages/sci/src/analysis/game.d.ts +90 -0
  112. package/packages/sci/src/analysis/game.js +221 -0
  113. package/packages/sci/src/analysis/game.ts +305 -0
  114. package/packages/sci/src/analysis/runtime.d.ts +58 -0
  115. package/packages/sci/src/analysis/runtime.js +133 -0
  116. package/packages/sci/src/analysis/runtime.ts +163 -0
  117. package/packages/sci/src/audio/adlib.d.ts +73 -0
  118. package/packages/sci/src/audio/adlib.js +280 -0
  119. package/packages/sci/src/audio/adlib.ts +329 -0
  120. package/packages/sci/src/audio/index.d.ts +43 -0
  121. package/packages/sci/src/audio/index.js +99 -0
  122. package/packages/sci/src/audio/index.ts +122 -0
  123. package/packages/sci/src/audio/midi.d.ts +92 -0
  124. package/packages/sci/src/audio/midi.js +242 -0
  125. package/packages/sci/src/audio/midi.ts +262 -0
  126. package/packages/sci/src/audio/opl2.d.ts +74 -0
  127. package/packages/sci/src/audio/opl2.js +283 -0
  128. package/packages/sci/src/audio/opl2.ts +283 -0
  129. package/packages/sci/src/audio/sol.d.ts +32 -0
  130. package/packages/sci/src/audio/sol.js +81 -0
  131. package/packages/sci/src/audio/sol.ts +100 -0
  132. package/packages/sci/src/audio/write.d.ts +35 -0
  133. package/packages/sci/src/audio/write.js +91 -0
  134. package/packages/sci/src/audio/write.ts +108 -0
  135. package/packages/sci/src/gfx/cel.d.ts +36 -0
  136. package/packages/sci/src/gfx/cel.js +82 -0
  137. package/packages/sci/src/gfx/cel.ts +110 -0
  138. package/packages/sci/src/gfx/palette.d.ts +24 -0
  139. package/packages/sci/src/gfx/palette.js +49 -0
  140. package/packages/sci/src/gfx/palette.ts +56 -0
  141. package/packages/sci/src/gfx/pic-file.d.ts +46 -0
  142. package/packages/sci/src/gfx/pic-file.js +114 -0
  143. package/packages/sci/src/gfx/pic-file.ts +155 -0
  144. package/packages/sci/src/gfx/pic.d.ts +27 -0
  145. package/packages/sci/src/gfx/pic.js +34 -0
  146. package/packages/sci/src/gfx/pic.ts +53 -0
  147. package/packages/sci/src/gfx/quantize.d.ts +42 -0
  148. package/packages/sci/src/gfx/quantize.js +199 -0
  149. package/packages/sci/src/gfx/quantize.ts +218 -0
  150. package/packages/sci/src/gfx/view-file.d.ts +62 -0
  151. package/packages/sci/src/gfx/view-file.js +182 -0
  152. package/packages/sci/src/gfx/view-file.ts +233 -0
  153. package/packages/sci/src/gfx/view.d.ts +28 -0
  154. package/packages/sci/src/gfx/view.js +45 -0
  155. package/packages/sci/src/gfx/view.ts +62 -0
  156. package/packages/sci/src/index.d.ts +38 -0
  157. package/packages/sci/src/index.js +38 -0
  158. package/packages/sci/src/index.ts +38 -0
  159. package/packages/sci/src/motion/pathfinding.d.ts +40 -0
  160. package/packages/sci/src/motion/pathfinding.js +140 -0
  161. package/packages/sci/src/motion/pathfinding.ts +147 -0
  162. package/packages/sci/src/resource/archive.d.ts +16 -0
  163. package/packages/sci/src/resource/archive.js +51 -0
  164. package/packages/sci/src/resource/archive.ts +56 -0
  165. package/packages/sci/src/resource/lzs.d.ts +12 -0
  166. package/packages/sci/src/resource/lzs.js +64 -0
  167. package/packages/sci/src/resource/lzs.ts +66 -0
  168. package/packages/sci/src/resource/manager.d.ts +45 -0
  169. package/packages/sci/src/resource/manager.js +158 -0
  170. package/packages/sci/src/resource/manager.ts +184 -0
  171. package/packages/sci/src/resource/map.d.ts +18 -0
  172. package/packages/sci/src/resource/map.js +34 -0
  173. package/packages/sci/src/resource/map.ts +44 -0
  174. package/packages/sci/src/resource/types.d.ts +37 -0
  175. package/packages/sci/src/resource/types.js +45 -0
  176. package/packages/sci/src/resource/types.ts +57 -0
  177. package/packages/sci/src/script/assembly.d.ts +67 -0
  178. package/packages/sci/src/script/assembly.js +748 -0
  179. package/packages/sci/src/script/assembly.ts +714 -0
  180. package/packages/sci/src/script/compiler.d.ts +75 -0
  181. package/packages/sci/src/script/compiler.js +993 -0
  182. package/packages/sci/src/script/compiler.ts +1040 -0
  183. package/packages/sci/src/script/disasm.d.ts +81 -0
  184. package/packages/sci/src/script/disasm.js +318 -0
  185. package/packages/sci/src/script/disasm.ts +323 -0
  186. package/packages/sci/src/script/kernel-names.d.ts +6 -0
  187. package/packages/sci/src/script/kernel-names.js +165 -0
  188. package/packages/sci/src/script/kernel-names.ts +165 -0
  189. package/packages/sci/src/script/opcodes.d.ts +22 -0
  190. package/packages/sci/src/script/opcodes.js +45 -0
  191. package/packages/sci/src/script/opcodes.ts +72 -0
  192. package/packages/sci/src/script/script.d.ts +56 -0
  193. package/packages/sci/src/script/script.js +63 -0
  194. package/packages/sci/src/script/script.ts +111 -0
  195. package/packages/sci/src/script/sexpr.d.ts +45 -0
  196. package/packages/sci/src/script/sexpr.js +151 -0
  197. package/packages/sci/src/script/sexpr.ts +139 -0
  198. package/packages/sci/src/script/vocab.d.ts +15 -0
  199. package/packages/sci/src/script/vocab.js +44 -0
  200. package/packages/sci/src/script/vocab.ts +48 -0
  201. package/packages/sci/src/script/world.d.ts +25 -0
  202. package/packages/sci/src/script/world.js +65 -0
  203. package/packages/sci/src/script/world.ts +70 -0
  204. package/packages/sci/src/text/font.d.ts +37 -0
  205. package/packages/sci/src/text/font.js +103 -0
  206. package/packages/sci/src/text/font.ts +125 -0
  207. package/packages/sci/src/text/message.d.ts +69 -0
  208. package/packages/sci/src/text/message.js +171 -0
  209. package/packages/sci/src/text/message.ts +205 -0
  210. package/packages/sci/src/vm/kernels/arrays.d.ts +19 -0
  211. package/packages/sci/src/vm/kernels/arrays.js +182 -0
  212. package/packages/sci/src/vm/kernels/arrays.ts +164 -0
  213. package/packages/sci/src/vm/kernels/audio.d.ts +70 -0
  214. package/packages/sci/src/vm/kernels/audio.js +347 -0
  215. package/packages/sci/src/vm/kernels/audio.ts +349 -0
  216. package/packages/sci/src/vm/kernels/core.d.ts +5 -0
  217. package/packages/sci/src/vm/kernels/core.js +87 -0
  218. package/packages/sci/src/vm/kernels/core.ts +91 -0
  219. package/packages/sci/src/vm/kernels/graphics.d.ts +141 -0
  220. package/packages/sci/src/vm/kernels/graphics.js +467 -0
  221. package/packages/sci/src/vm/kernels/graphics.ts +502 -0
  222. package/packages/sci/src/vm/kernels/index.d.ts +8 -0
  223. package/packages/sci/src/vm/kernels/index.js +29 -0
  224. package/packages/sci/src/vm/kernels/index.ts +32 -0
  225. package/packages/sci/src/vm/kernels/lists.d.ts +6 -0
  226. package/packages/sci/src/vm/kernels/lists.js +127 -0
  227. package/packages/sci/src/vm/kernels/lists.ts +111 -0
  228. package/packages/sci/src/vm/kernels/motion.d.ts +7 -0
  229. package/packages/sci/src/vm/kernels/motion.js +204 -0
  230. package/packages/sci/src/vm/kernels/motion.ts +194 -0
  231. package/packages/sci/src/vm/kernels/palette.d.ts +82 -0
  232. package/packages/sci/src/vm/kernels/palette.js +292 -0
  233. package/packages/sci/src/vm/kernels/palette.ts +303 -0
  234. package/packages/sci/src/vm/kernels/saves.d.ts +45 -0
  235. package/packages/sci/src/vm/kernels/saves.js +123 -0
  236. package/packages/sci/src/vm/kernels/saves.ts +149 -0
  237. package/packages/sci/src/vm/kernels/system.d.ts +62 -0
  238. package/packages/sci/src/vm/kernels/system.js +110 -0
  239. package/packages/sci/src/vm/kernels/system.ts +128 -0
  240. package/packages/sci/src/vm/kernels/text.d.ts +13 -0
  241. package/packages/sci/src/vm/kernels/text.js +338 -0
  242. package/packages/sci/src/vm/kernels/text.ts +328 -0
  243. package/packages/sci/src/vm/memory.d.ts +138 -0
  244. package/packages/sci/src/vm/memory.js +168 -0
  245. package/packages/sci/src/vm/memory.ts +266 -0
  246. package/packages/sci/src/vm/replace.d.ts +11 -0
  247. package/packages/sci/src/vm/replace.js +14 -0
  248. package/packages/sci/src/vm/replace.ts +16 -0
  249. package/packages/sci/src/vm/savegame.d.ts +89 -0
  250. package/packages/sci/src/vm/savegame.js +161 -0
  251. package/packages/sci/src/vm/savegame.ts +188 -0
  252. package/packages/sci/src/vm/value.d.ts +17 -0
  253. package/packages/sci/src/vm/value.js +12 -0
  254. package/packages/sci/src/vm/value.ts +25 -0
  255. package/packages/sci/src/vm/vm.d.ts +155 -0
  256. package/packages/sci/src/vm/vm.js +1053 -0
  257. package/packages/sci/src/vm/vm.ts +914 -0
  258. package/tools/adlib-render.d.ts +1 -0
  259. package/tools/adlib-render.js +49 -0
  260. package/tools/adlib-render.ts +42 -0
  261. package/tools/analyze.d.ts +1 -0
  262. package/tools/analyze.js +25 -0
  263. package/tools/analyze.ts +25 -0
  264. package/tools/art/build.d.ts +34 -0
  265. package/tools/art/build.js +175 -0
  266. package/tools/art/build.ts +153 -0
  267. package/tools/art.d.ts +1 -0
  268. package/tools/art.js +31 -0
  269. package/tools/art.ts +29 -0
  270. package/tools/asm.d.ts +1 -0
  271. package/tools/asm.js +61 -0
  272. package/tools/asm.ts +55 -0
  273. package/tools/cli.d.ts +1 -0
  274. package/tools/cli.js +99 -0
  275. package/tools/cli.ts +100 -0
  276. package/tools/editor-server.d.ts +29 -0
  277. package/tools/editor-server.js +162 -0
  278. package/tools/editor-server.ts +176 -0
  279. package/tools/explore.d.ts +1 -0
  280. package/tools/explore.js +305 -0
  281. package/tools/explore.ts +250 -0
  282. package/tools/game/audio.d.ts +19 -0
  283. package/tools/game/audio.js +143 -0
  284. package/tools/game/audio.ts +130 -0
  285. package/tools/game/build.d.ts +46 -0
  286. package/tools/game/build.js +259 -0
  287. package/tools/game/build.ts +283 -0
  288. package/tools/game/defaults.d.ts +26 -0
  289. package/tools/game/defaults.js +82 -0
  290. package/tools/game/defaults.ts +83 -0
  291. package/tools/game/font.d.ts +3 -0
  292. package/tools/game/font.js +124 -0
  293. package/tools/game/font.ts +126 -0
  294. package/tools/game/kit.d.ts +7 -0
  295. package/tools/game/kit.js +7 -0
  296. package/tools/game/kit.ts +10 -0
  297. package/tools/game/new.d.ts +8 -0
  298. package/tools/game/new.js +39 -0
  299. package/tools/game/new.ts +38 -0
  300. package/tools/game/target.d.ts +7 -0
  301. package/tools/game/target.js +41 -0
  302. package/tools/game/target.ts +42 -0
  303. package/tools/game/template/resources.ts.tmpl +43 -0
  304. package/tools/game/template/rooms/1.room.yaml +9 -0
  305. package/tools/game/template/rooms/1.yarn +17 -0
  306. package/tools/game/template/scripts/0.sc +24 -0
  307. package/tools/game.d.ts +1 -0
  308. package/tools/game.js +77 -0
  309. package/tools/game.ts +70 -0
  310. package/tools/mod-build.d.ts +28 -0
  311. package/tools/mod-build.js +173 -0
  312. package/tools/mod-build.ts +179 -0
  313. package/tools/mod-target.d.ts +16 -0
  314. package/tools/mod-target.js +26 -0
  315. package/tools/mod-target.ts +32 -0
  316. package/tools/mod.d.ts +1 -0
  317. package/tools/mod.js +47 -0
  318. package/tools/mod.ts +45 -0
  319. package/tools/msg.d.ts +1 -0
  320. package/tools/msg.js +40 -0
  321. package/tools/msg.ts +36 -0
  322. package/tools/node-files.d.ts +3 -0
  323. package/tools/node-files.js +34 -0
  324. package/tools/node-files.ts +33 -0
  325. package/tools/patches.d.ts +3 -0
  326. package/tools/patches.js +13 -0
  327. package/tools/patches.ts +13 -0
  328. package/tools/pic-build.d.ts +9 -0
  329. package/tools/pic-build.js +26 -0
  330. package/tools/pic-build.ts +27 -0
  331. package/tools/pic.d.ts +1 -0
  332. package/tools/pic.js +64 -0
  333. package/tools/pic.ts +61 -0
  334. package/tools/play.d.ts +1 -0
  335. package/tools/play.js +54 -0
  336. package/tools/play.ts +54 -0
  337. package/tools/png.d.ts +16 -0
  338. package/tools/png.js +124 -0
  339. package/tools/png.ts +123 -0
  340. package/tools/res.d.ts +1 -0
  341. package/tools/res.js +48 -0
  342. package/tools/res.ts +50 -0
  343. package/tools/scenario.d.ts +1 -0
  344. package/tools/scenario.js +74 -0
  345. package/tools/scenario.ts +80 -0
  346. package/tools/site/build.d.ts +8 -0
  347. package/tools/site/build.js +110 -0
  348. package/tools/site/build.ts +116 -0
  349. package/tools/site/markdown.d.ts +11 -0
  350. package/tools/site/markdown.js +88 -0
  351. package/tools/site/markdown.ts +84 -0
  352. package/tools/view-build.d.ts +34 -0
  353. package/tools/view-build.js +47 -0
  354. package/tools/view-build.ts +71 -0
  355. package/tools/view.d.ts +1 -0
  356. package/tools/view.js +54 -0
  357. package/tools/view.ts +52 -0
@@ -0,0 +1,45 @@
1
+ const op = (name, ...operands) => ({ name, operands });
2
+ const base = [
3
+ // 0x00–0x16: arithmetic and comparison. Binary ops combine the stack top with acc.
4
+ op("bnot"), op("add"), op("sub"), op("mul"), op("div"), op("mod"), op("shr"), op("shl"),
5
+ op("xor"), op("and"), op("or"), op("neg"), op("not"), op("eq?"), op("ne?"), op("gt?"),
6
+ op("ge?"), op("lt?"), op("le?"), op("ugt?"), op("uge?"), op("ult?"), op("ule?"),
7
+ // 0x17–0x1e: branches and the stack
8
+ op("bt", "R"), op("bnt", "R"), op("jmp", "R"), op("ldi", "S"), op("push"), op("pushi", "S"), op("toss"), op("dup"),
9
+ // 0x1f–0x25: calls. The last operand is the argument frame size in bytes.
10
+ op("link", "W"),
11
+ op("call", "R", "U"), // local procedure
12
+ op("callk", "W", "U"), // kernel (interpreter built-in)
13
+ op("callb", "W", "U"), // export of script 0
14
+ op("calle", "W", "W", "U"), // export of another script
15
+ op("ret"),
16
+ op("send", "W"), // send messages to the object in acc
17
+ // 0x26–0x2f: objects
18
+ op("dummy26"), op("dummy27"),
19
+ op("class", "W"), // acc = class object
20
+ op("dummy29"),
21
+ op("self", "W"), op("super", "W", "U"), op("&rest", "W"),
22
+ op("lea", "W", "W"), op("selfID"), op("dummy2f"),
23
+ // 0x30–0x38: properties of the current object (operand = property offset in bytes)
24
+ op("pprev"), op("pToa", "W"), op("aTop", "W"), op("pTos", "W"), op("sTop", "W"),
25
+ op("ipToa", "W"), op("dpToa", "W"), op("ipTos", "W"), op("dpTos", "W"),
26
+ // 0x39–0x3f
27
+ op("lofsa", "W"), op("lofss", "W"), // address of a heap object/string
28
+ op("push0"), op("push1"), op("push2"), op("pushSelf"), op("dummy3f"),
29
+ ];
30
+ /**
31
+ * 0x40–0x7f: variable access, generated from a pattern:
32
+ * bits 0-1: g(lobal) l(ocal) t(emp) p(aram)
33
+ * bit 2: a = acc, s = stack
34
+ * bit 3: i = indexed by acc
35
+ * bits 4-5: l(oad), s(tore), + (increment), - (decrement)
36
+ */
37
+ const varOps = Array.from({ length: 64 }, (_, i) => {
38
+ const kind = "gltp"[i & 3];
39
+ const target = i & 4 ? "s" : "a";
40
+ const indexed = i & 8 ? "i" : "";
41
+ const action = ["l", "s", "+", "-"][i >> 4];
42
+ return op(`${action}${target}${kind}${indexed}`, "W");
43
+ });
44
+ export const opcodes = [...base, ...varOps];
45
+ export const varKind = (opcode) => opcode >= 0x40 ? ["global", "local", "temp", "param"][opcode & 3] : undefined;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * SCI bytecode. Each instruction's first byte is `opcode << 1 | size`: when the low bit is
3
+ * set, "sized" operands are 1 byte instead of 2.
4
+ *
5
+ * Operand kinds:
6
+ * W sized unsigned (word or byte) S sized signed
7
+ * R sized signed, relative to the next instruction (jump/call target)
8
+ * B always 1 byte U always 2 bytes
9
+ *
10
+ * SCI2 quirk, found by measuring: the argument-frame operand of call/callk/callb/calle/super
11
+ * is always 16-bit, even in the byte form; send and self frames follow the size bit.
12
+ * (SCI0–1.1 used a fixed byte.) Decoding it as a byte leaves a stray 0x00, which shows up
13
+ * as thousands of bogus `bnot` instructions.
14
+ */
15
+ export type OperandKind = "W" | "S" | "R" | "B" | "U";
16
+
17
+ export interface OpcodeInfo {
18
+ name: string;
19
+ operands: OperandKind[];
20
+ }
21
+
22
+ const op = (name: string, ...operands: OperandKind[]): OpcodeInfo => ({ name, operands });
23
+
24
+ const base: OpcodeInfo[] = [
25
+ // 0x00–0x16: arithmetic and comparison. Binary ops combine the stack top with acc.
26
+ op("bnot"), op("add"), op("sub"), op("mul"), op("div"), op("mod"), op("shr"), op("shl"),
27
+ op("xor"), op("and"), op("or"), op("neg"), op("not"), op("eq?"), op("ne?"), op("gt?"),
28
+ op("ge?"), op("lt?"), op("le?"), op("ugt?"), op("uge?"), op("ult?"), op("ule?"),
29
+ // 0x17–0x1e: branches and the stack
30
+ op("bt", "R"), op("bnt", "R"), op("jmp", "R"), op("ldi", "S"), op("push"), op("pushi", "S"), op("toss"), op("dup"),
31
+ // 0x1f–0x25: calls. The last operand is the argument frame size in bytes.
32
+ op("link", "W"),
33
+ op("call", "R", "U"), // local procedure
34
+ op("callk", "W", "U"), // kernel (interpreter built-in)
35
+ op("callb", "W", "U"), // export of script 0
36
+ op("calle", "W", "W", "U"), // export of another script
37
+ op("ret"),
38
+ op("send", "W"), // send messages to the object in acc
39
+ // 0x26–0x2f: objects
40
+ op("dummy26"), op("dummy27"),
41
+ op("class", "W"), // acc = class object
42
+ op("dummy29"),
43
+ op("self", "W"), op("super", "W", "U"), op("&rest", "W"),
44
+ op("lea", "W", "W"), op("selfID"), op("dummy2f"),
45
+ // 0x30–0x38: properties of the current object (operand = property offset in bytes)
46
+ op("pprev"), op("pToa", "W"), op("aTop", "W"), op("pTos", "W"), op("sTop", "W"),
47
+ op("ipToa", "W"), op("dpToa", "W"), op("ipTos", "W"), op("dpTos", "W"),
48
+ // 0x39–0x3f
49
+ op("lofsa", "W"), op("lofss", "W"), // address of a heap object/string
50
+ op("push0"), op("push1"), op("push2"), op("pushSelf"), op("dummy3f"),
51
+ ];
52
+
53
+ /**
54
+ * 0x40–0x7f: variable access, generated from a pattern:
55
+ * bits 0-1: g(lobal) l(ocal) t(emp) p(aram)
56
+ * bit 2: a = acc, s = stack
57
+ * bit 3: i = indexed by acc
58
+ * bits 4-5: l(oad), s(tore), + (increment), - (decrement)
59
+ */
60
+ const varOps = Array.from({ length: 64 }, (_, i) => {
61
+ const kind = "gltp"[i & 3]!;
62
+ const target = i & 4 ? "s" : "a";
63
+ const indexed = i & 8 ? "i" : "";
64
+ const action = ["l", "s", "+", "-"][i >> 4]!;
65
+ return op(`${action}${target}${kind}${indexed}`, "W");
66
+ });
67
+
68
+ export const opcodes: readonly OpcodeInfo[] = [...base, ...varOps];
69
+
70
+ export type VarKind = "global" | "local" | "temp" | "param";
71
+ export const varKind = (opcode: number): VarKind | undefined =>
72
+ opcode >= 0x40 ? (["global", "local", "temp", "param"] as const)[opcode & 3] : undefined;
@@ -0,0 +1,56 @@
1
+ /** Object property slots common to every object (SCI1.1/SCI2 layout, in words). */
2
+ export declare const ObjectSlot: {
3
+ readonly Magic: 0;
4
+ readonly Size: 1;
5
+ readonly PropDict: 2;
6
+ readonly MethDict: 3;
7
+ readonly ClassScript: 4;
8
+ readonly Species: 5;
9
+ readonly Super: 6;
10
+ readonly Info: 7;
11
+ readonly Name: 8;
12
+ };
13
+ export interface Method {
14
+ selector: number;
15
+ /** Code offset in the script resource. */
16
+ offset: number;
17
+ }
18
+ export interface ScriptObject {
19
+ /** Offset of the object in the heap resource. */
20
+ offset: number;
21
+ name: string;
22
+ isClass: boolean;
23
+ species: number;
24
+ superclass: number;
25
+ /** Raw property values, including the header slots above. */
26
+ properties: number[];
27
+ /** Selector id per property; only present on classes (instances use their class's). */
28
+ propSelectors?: number[];
29
+ methods: Method[];
30
+ }
31
+ export interface Export {
32
+ index: number;
33
+ offset: number;
34
+ /** Objects live in the heap; procedures are code in the script. Offset 0 = unused slot. */
35
+ kind: "object" | "code" | "empty";
36
+ }
37
+ /**
38
+ * A loaded script: bytecode and dictionaries in the script resource, data (locals,
39
+ * objects, strings) in the heap resource of the same number. SCI3 later merged the two.
40
+ */
41
+ export interface Script {
42
+ number: number;
43
+ code: Uint8Array;
44
+ heap: Uint8Array;
45
+ exports: Export[];
46
+ locals: number[];
47
+ objects: ScriptObject[];
48
+ }
49
+ /** Reads a NUL-terminated Latin-1 string. */
50
+ export declare function readString(data: Uint8Array, offset: number): string;
51
+ /**
52
+ * Script resource: +0 u16 relocation table offset | +6 u16 export count | +8 u16 exports
53
+ * Heap resource: +0 u16 relocation table offset | +2 u16 local count | locals |
54
+ * objects (each starts with 0x1234) until a 0 word | strings
55
+ */
56
+ export declare function parseScript(number: number, code: Uint8Array, heap: Uint8Array): Script;
@@ -0,0 +1,63 @@
1
+ /** Object property slots common to every object (SCI1.1/SCI2 layout, in words). */
2
+ export const ObjectSlot = {
3
+ Magic: 0, // 0x1234
4
+ Size: 1, // property count
5
+ PropDict: 2, // script offset: selector id per property (classes only)
6
+ MethDict: 3, // script offset: u16 count, then (selector, code offset) pairs
7
+ ClassScript: 4,
8
+ Species: 5, // class number; 0xFFFF on instances
9
+ Super: 6, // superclass number
10
+ Info: 7, // flags; 0x8000 = class
11
+ Name: 8, // heap offset of the name string
12
+ };
13
+ const OBJECT_MAGIC = 0x1234;
14
+ const INFO_CLASS = 0x8000;
15
+ /** Reads a NUL-terminated Latin-1 string. */
16
+ export function readString(data, offset) {
17
+ let end = offset;
18
+ while (end < data.length && data[end] !== 0)
19
+ end++;
20
+ return new TextDecoder("latin1").decode(data.subarray(offset, end));
21
+ }
22
+ /**
23
+ * Script resource: +0 u16 relocation table offset | +6 u16 export count | +8 u16 exports
24
+ * Heap resource: +0 u16 relocation table offset | +2 u16 local count | locals |
25
+ * objects (each starts with 0x1234) until a 0 word | strings
26
+ */
27
+ export function parseScript(number, code, heap) {
28
+ const cv = new DataView(code.buffer, code.byteOffset, code.byteLength);
29
+ const hv = new DataView(heap.buffer, heap.byteOffset, heap.byteLength);
30
+ const heapWord = (o) => hv.getUint16(o, true);
31
+ const codeWord = (o) => cv.getUint16(o, true);
32
+ const localCount = heapWord(2);
33
+ const locals = Array.from({ length: localCount }, (_, i) => heapWord(4 + i * 2));
34
+ const objects = [];
35
+ for (let pos = 4 + localCount * 2; pos + 2 <= heap.length && heapWord(pos) === OBJECT_MAGIC;) {
36
+ const size = heapWord(pos + 2);
37
+ const properties = Array.from({ length: size }, (_, i) => heapWord(pos + i * 2));
38
+ const isClass = (properties[ObjectSlot.Info] & INFO_CLASS) !== 0;
39
+ const methDict = properties[ObjectSlot.MethDict];
40
+ const methods = Array.from({ length: codeWord(methDict) }, (_, i) => ({
41
+ selector: codeWord(methDict + 2 + i * 4),
42
+ offset: codeWord(methDict + 4 + i * 4),
43
+ }));
44
+ const propDict = properties[ObjectSlot.PropDict];
45
+ objects.push({
46
+ offset: pos,
47
+ name: readString(heap, properties[ObjectSlot.Name]),
48
+ isClass,
49
+ species: properties[ObjectSlot.Species],
50
+ superclass: properties[ObjectSlot.Super],
51
+ properties,
52
+ propSelectors: isClass ? Array.from({ length: size }, (_, i) => codeWord(propDict + i * 2)) : undefined,
53
+ methods,
54
+ });
55
+ pos += size * 2;
56
+ }
57
+ const objectOffsets = new Set(objects.map((o) => o.offset));
58
+ const exports = Array.from({ length: codeWord(6) }, (_, index) => {
59
+ const offset = codeWord(8 + index * 2);
60
+ return { index, offset, kind: offset === 0 ? "empty" : objectOffsets.has(offset) ? "object" : "code" };
61
+ });
62
+ return { number, code, heap, exports, locals, objects };
63
+ }
@@ -0,0 +1,111 @@
1
+ /** Object property slots common to every object (SCI1.1/SCI2 layout, in words). */
2
+ export const ObjectSlot = {
3
+ Magic: 0, // 0x1234
4
+ Size: 1, // property count
5
+ PropDict: 2, // script offset: selector id per property (classes only)
6
+ MethDict: 3, // script offset: u16 count, then (selector, code offset) pairs
7
+ ClassScript: 4,
8
+ Species: 5, // class number; 0xFFFF on instances
9
+ Super: 6, // superclass number
10
+ Info: 7, // flags; 0x8000 = class
11
+ Name: 8, // heap offset of the name string
12
+ } as const;
13
+
14
+ const OBJECT_MAGIC = 0x1234;
15
+ const INFO_CLASS = 0x8000;
16
+
17
+ export interface Method {
18
+ selector: number;
19
+ /** Code offset in the script resource. */
20
+ offset: number;
21
+ }
22
+
23
+ export interface ScriptObject {
24
+ /** Offset of the object in the heap resource. */
25
+ offset: number;
26
+ name: string;
27
+ isClass: boolean;
28
+ species: number;
29
+ superclass: number;
30
+ /** Raw property values, including the header slots above. */
31
+ properties: number[];
32
+ /** Selector id per property; only present on classes (instances use their class's). */
33
+ propSelectors?: number[];
34
+ methods: Method[];
35
+ }
36
+
37
+ export interface Export {
38
+ index: number;
39
+ offset: number;
40
+ /** Objects live in the heap; procedures are code in the script. Offset 0 = unused slot. */
41
+ kind: "object" | "code" | "empty";
42
+ }
43
+
44
+ /**
45
+ * A loaded script: bytecode and dictionaries in the script resource, data (locals,
46
+ * objects, strings) in the heap resource of the same number. SCI3 later merged the two.
47
+ */
48
+ export interface Script {
49
+ number: number;
50
+ code: Uint8Array;
51
+ heap: Uint8Array;
52
+ exports: Export[];
53
+ locals: number[];
54
+ objects: ScriptObject[];
55
+ }
56
+
57
+ /** Reads a NUL-terminated Latin-1 string. */
58
+ export function readString(data: Uint8Array, offset: number): string {
59
+ let end = offset;
60
+ while (end < data.length && data[end] !== 0) end++;
61
+ return new TextDecoder("latin1").decode(data.subarray(offset, end));
62
+ }
63
+
64
+ /**
65
+ * Script resource: +0 u16 relocation table offset | +6 u16 export count | +8 u16 exports
66
+ * Heap resource: +0 u16 relocation table offset | +2 u16 local count | locals |
67
+ * objects (each starts with 0x1234) until a 0 word | strings
68
+ */
69
+ export function parseScript(number: number, code: Uint8Array, heap: Uint8Array): Script {
70
+ const cv = new DataView(code.buffer, code.byteOffset, code.byteLength);
71
+ const hv = new DataView(heap.buffer, heap.byteOffset, heap.byteLength);
72
+ const heapWord = (o: number) => hv.getUint16(o, true);
73
+ const codeWord = (o: number) => cv.getUint16(o, true);
74
+
75
+ const localCount = heapWord(2);
76
+ const locals = Array.from({ length: localCount }, (_, i) => heapWord(4 + i * 2));
77
+
78
+ const objects: ScriptObject[] = [];
79
+ for (let pos = 4 + localCount * 2; pos + 2 <= heap.length && heapWord(pos) === OBJECT_MAGIC; ) {
80
+ const size = heapWord(pos + 2);
81
+ const properties = Array.from({ length: size }, (_, i) => heapWord(pos + i * 2));
82
+ const isClass = (properties[ObjectSlot.Info]! & INFO_CLASS) !== 0;
83
+
84
+ const methDict = properties[ObjectSlot.MethDict]!;
85
+ const methods = Array.from({ length: codeWord(methDict) }, (_, i) => ({
86
+ selector: codeWord(methDict + 2 + i * 4),
87
+ offset: codeWord(methDict + 4 + i * 4),
88
+ }));
89
+
90
+ const propDict = properties[ObjectSlot.PropDict]!;
91
+ objects.push({
92
+ offset: pos,
93
+ name: readString(heap, properties[ObjectSlot.Name]!),
94
+ isClass,
95
+ species: properties[ObjectSlot.Species]!,
96
+ superclass: properties[ObjectSlot.Super]!,
97
+ properties,
98
+ propSelectors: isClass ? Array.from({ length: size }, (_, i) => codeWord(propDict + i * 2)) : undefined,
99
+ methods,
100
+ });
101
+ pos += size * 2;
102
+ }
103
+
104
+ const objectOffsets = new Set(objects.map((o) => o.offset));
105
+ const exports = Array.from({ length: codeWord(6) }, (_, index): Export => {
106
+ const offset = codeWord(8 + index * 2);
107
+ return { index, offset, kind: offset === 0 ? "empty" : objectOffsets.has(offset) ? "object" : "code" };
108
+ });
109
+
110
+ return { number, code, heap, exports, locals, objects };
111
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The reader for SCI script source: parenthesised lists, with a few kinds of atom.
3
+ *
4
+ * (send obj x: 1) a list [buf 3] an array element (or declaration)
5
+ * foo x: y? &rest symbols 42 -7 $1F %101 `a numbers
6
+ * "text" {text} strings #init a selector
7
+ * @buf @[buf i] a variable's address, an element's ; ... a comment, to the end of the line
8
+ */
9
+ export type Node = {
10
+ kind: "list";
11
+ items: Node[];
12
+ line: number;
13
+ } | {
14
+ kind: "index";
15
+ items: Node[];
16
+ line: number;
17
+ } | {
18
+ kind: "sym";
19
+ name: string;
20
+ line: number;
21
+ } | {
22
+ kind: "num";
23
+ value: number;
24
+ line: number;
25
+ } | {
26
+ kind: "str";
27
+ value: string;
28
+ line: number;
29
+ } | {
30
+ kind: "sel";
31
+ name: string;
32
+ line: number;
33
+ } | {
34
+ kind: "addr";
35
+ name: string;
36
+ index?: Node;
37
+ line: number;
38
+ };
39
+ export declare class ReadError extends Error {
40
+ readonly line: number;
41
+ constructor(message: string, line: number);
42
+ }
43
+ export declare function read(text: string): Node[];
44
+ /** A node as source text again, for error messages. */
45
+ export declare function show(n: Node): string;
@@ -0,0 +1,151 @@
1
+ export class ReadError extends Error {
2
+ line;
3
+ constructor(message, line) {
4
+ super(`line ${line}: ${message}`);
5
+ this.line = line;
6
+ }
7
+ }
8
+ const DELIMITERS = new Set([..."()[]{}\";"]);
9
+ const isSpace = (c) => c === " " || c === "\t" || c === "\r" || c === "\n";
10
+ export function read(text) {
11
+ let p = 0, line = 1;
12
+ const top = [];
13
+ const stack = [];
14
+ const add = (n) => (stack.length ? stack[stack.length - 1].node.items : top).push(n);
15
+ while (p < text.length) {
16
+ const c = text[p];
17
+ if (c === "\n") {
18
+ line++;
19
+ p++;
20
+ continue;
21
+ }
22
+ if (isSpace(c)) {
23
+ p++;
24
+ continue;
25
+ }
26
+ if (c === ";") {
27
+ while (p < text.length && text[p] !== "\n")
28
+ p++;
29
+ continue;
30
+ }
31
+ if (c === "(" || c === "[") {
32
+ const node = { kind: c === "(" ? "list" : "index", items: [], line };
33
+ add(node);
34
+ stack.push({ node, close: c === "(" ? ")" : "]" });
35
+ p++;
36
+ continue;
37
+ }
38
+ if (c === ")" || c === "]") {
39
+ const open = stack.pop();
40
+ if (!open)
41
+ throw new ReadError(`unexpected ${c}`, line);
42
+ if (open.close !== c)
43
+ throw new ReadError(`expected ${open.close} to close the ${open.close === ")" ? "(" : "["} on line ${open.node.line}, got ${c}`, line);
44
+ p++;
45
+ continue;
46
+ }
47
+ if (c === '"' || c === "{") {
48
+ const end = c === '"' ? '"' : "}";
49
+ const start = line;
50
+ let value = "";
51
+ p++;
52
+ for (;;) {
53
+ if (p >= text.length)
54
+ throw new ReadError("string never ends", start);
55
+ const ch = text[p];
56
+ if (ch === end) {
57
+ p++;
58
+ break;
59
+ }
60
+ if (ch === "\n")
61
+ line++;
62
+ if (ch === "\\") {
63
+ const n = text[p + 1] ?? "";
64
+ if (n === "n")
65
+ value += "\n";
66
+ else if (n === "t")
67
+ value += "\t";
68
+ else if (/[0-9a-fA-F]/.test(n) && /[0-9a-fA-F]/.test(text[p + 2] ?? "")) {
69
+ value += String.fromCharCode(parseInt(text.slice(p + 1, p + 3), 16));
70
+ p++;
71
+ }
72
+ else
73
+ value += n;
74
+ p += 2;
75
+ continue;
76
+ }
77
+ value += ch;
78
+ p++;
79
+ }
80
+ add({ kind: "str", value, line: start });
81
+ continue;
82
+ }
83
+ if (c === "`") {
84
+ // A character: `a is 97; `^a is control-A; `#4 is a key with a scan code (not supported).
85
+ const ch = text[p + 1];
86
+ if (ch === undefined)
87
+ throw new ReadError("` needs a character", line);
88
+ if (ch === "^" && text[p + 2] && !isSpace(text[p + 2])) {
89
+ add({ kind: "num", value: text[p + 2].toUpperCase().charCodeAt(0) - 64, line });
90
+ p += 3;
91
+ }
92
+ else {
93
+ add({ kind: "num", value: ch.charCodeAt(0), line });
94
+ p += 2;
95
+ }
96
+ continue;
97
+ }
98
+ let e = p;
99
+ while (e < text.length && !isSpace(text[e]) && !DELIMITERS.has(text[e]))
100
+ e++;
101
+ const token = text.slice(p, e);
102
+ p = e;
103
+ add(atom(token, line));
104
+ }
105
+ if (stack.length)
106
+ throw new ReadError(`( never closed`, stack[stack.length - 1].node.line);
107
+ return addresses(top);
108
+ }
109
+ /** `@` then `[buf i]` is one thing: the address of an element. */
110
+ function addresses(nodes) {
111
+ const out = [];
112
+ for (let i = 0; i < nodes.length; i++) {
113
+ const n = nodes[i];
114
+ const next = nodes[i + 1];
115
+ if (n.kind === "sym" && n.name === "@" && next?.kind === "index" && next.items.length === 2 && next.items[0].kind === "sym") {
116
+ out.push({ kind: "addr", name: next.items[0].name, index: addresses([next.items[1]])[0], line: n.line });
117
+ i++;
118
+ continue;
119
+ }
120
+ if (n.kind === "list" || n.kind === "index")
121
+ out.push({ ...n, items: addresses(n.items) });
122
+ else
123
+ out.push(n);
124
+ }
125
+ return out;
126
+ }
127
+ function atom(token, line) {
128
+ if (/^-?\d+$/.test(token))
129
+ return { kind: "num", value: Number(token), line };
130
+ if (/^-?\$[0-9a-fA-F]+$/.test(token))
131
+ return { kind: "num", value: (token.startsWith("-") ? -1 : 1) * parseInt(token.replace(/^-?\$/, ""), 16), line };
132
+ if (/^%[01]+$/.test(token))
133
+ return { kind: "num", value: parseInt(token.slice(1), 2), line };
134
+ if (token.startsWith("#") && token.length > 1)
135
+ return { kind: "sel", name: token.slice(1), line };
136
+ if (token.startsWith("@") && token.length > 1)
137
+ return { kind: "addr", name: token.slice(1), line };
138
+ return { kind: "sym", name: token, line };
139
+ }
140
+ /** A node as source text again, for error messages. */
141
+ export function show(n) {
142
+ switch (n.kind) {
143
+ case "list": return `(${n.items.map(show).join(" ")})`;
144
+ case "index": return `[${n.items.map(show).join(" ")}]`;
145
+ case "sym": return n.name;
146
+ case "num": return String(n.value);
147
+ case "str": return JSON.stringify(n.value);
148
+ case "sel": return `#${n.name}`;
149
+ case "addr": return n.index ? `@[${n.name} ${show(n.index)}]` : `@${n.name}`;
150
+ }
151
+ }