1034 Commits

Author SHA1 Message Date
John Alanbrook
4b7cde9400 progress on aot 2026-02-16 21:58:45 -06:00
John Alanbrook
a1ee7dd458 better json pretty print 2026-02-16 17:00:06 -06:00
John Alanbrook
9dbe699033 better make 2026-02-16 01:45:00 -06:00
John Alanbrook
f809cb05f0 Merge branch 'fix_core_scripts' into quicken_mcode 2026-02-16 01:43:08 -06:00
John Alanbrook
788ea98651 bootstrap init 2026-02-16 01:36:36 -06:00
John Alanbrook
433ce8a86e update actors 2026-02-16 01:35:07 -06:00
John Alanbrook
cd6e357b6e Merge branch 'quicken_mcode' into gen_dylib 2026-02-16 00:35:40 -06:00
John Alanbrook
f4f56ed470 run dylibs 2026-02-16 00:35:23 -06:00
John Alanbrook
ff61ab1f50 better streamline 2026-02-16 00:34:49 -06:00
John Alanbrook
46c345d34e cache invalidation 2026-02-16 00:04:30 -06:00
John Alanbrook
dc440587ff pretty json 2026-02-15 22:55:11 -06:00
John Alanbrook
8f92870141 correct syntax errors in core scripts 2026-02-15 22:23:04 -06:00
John Alanbrook
7fc4a205f6 go reuses frames 2026-02-15 19:45:17 -06:00
John Alanbrook
23b201bdd7 dynamic dispatch 2026-02-15 17:51:07 -06:00
John Alanbrook
913ec9afb1 Merge branch 'audit_gc' into fix_slots 2026-02-15 15:44:28 -06:00
John Alanbrook
56de0ce803 fix infinite loop in shop 2026-02-15 15:41:09 -06:00
John Alanbrook
96bbb9e4c8 idompent 2026-02-15 14:58:46 -06:00
John Alanbrook
ebd624b772 fixing gc bugs; nearly idempotent 2026-02-15 13:14:26 -06:00
John Alanbrook
7de20b39da more detail on broken pipeline and vm suit tests 2026-02-15 11:51:23 -06:00
John Alanbrook
ee646db394 failsafe boot mode 2026-02-15 11:44:33 -06:00
John Alanbrook
ff80e0d30d Merge branch 'fix_gc' into pitweb 2026-02-15 10:04:54 -06:00
John Alanbrook
d9f41db891 fix syntax errors in build 2026-02-15 09:29:07 -06:00
John Alanbrook
860632e0fa update cli docs and fix cli scripts with new syntax 2026-02-14 22:24:32 -06:00
John Alanbrook
dcc9659e6b Merge branch 'runtime_rework' into fix_gc 2026-02-14 22:11:31 -06:00
John Alanbrook
2f7f2233b8 compiling 2026-02-14 22:08:55 -06:00
John Alanbrook
eee06009b9 no more special case for core C 2026-02-14 22:00:12 -06:00
John Alanbrook
a765872017 remove if/else dispatch from compile chain 2026-02-14 17:57:48 -06:00
John Alanbrook
a93218e1ff faster streamline 2026-02-14 17:14:43 -06:00
John Alanbrook
f2c4fa2f2b remove redundant check 2026-02-14 16:49:16 -06:00
John Alanbrook
5fe05c60d3 faster gc 2026-02-14 16:46:11 -06:00
John Alanbrook
e75596ce30 respsect array and object length requests 2026-02-14 15:42:19 -06:00
John Alanbrook
86609c27f8 correct sections 2026-02-14 15:13:18 -06:00
John Alanbrook
356c51bde3 better array allocation 2026-02-14 14:44:00 -06:00
John Alanbrook
89421e11a4 pull out prettify mcode 2026-02-14 14:14:34 -06:00
John Alanbrook
e5fc04fecd faster mach compile 2026-02-14 14:02:15 -06:00
John Alanbrook
8ec56e85fa shop audit 2026-02-14 14:00:27 -06:00
John Alanbrook
f49ca530bb fix delete gc bug 2026-02-13 21:52:37 -06:00
John Alanbrook
83263379bd ocaml style rooting macros 2026-02-13 20:46:31 -06:00
John Alanbrook
e80e615634 fix array gc bug; new gc error chasing 2026-02-13 16:58:42 -06:00
John Alanbrook
c1430fd59b Merge branch 'fix_gc' into runtime_rework 2026-02-13 15:42:37 -06:00
John Alanbrook
db73eb4eeb Merge branch 'mcode_streamline' into runtime_rework 2026-02-13 15:42:20 -06:00
John Alanbrook
f2556c5622 proper shop caching 2026-02-13 09:04:25 -06:00
John Alanbrook
291304f75d new way to track actor bad memory access 2026-02-13 09:03:33 -06:00
John Alanbrook
3795533554 clean up bytecode 2026-02-13 09:03:00 -06:00
John Alanbrook
d26a96bc62 cached bootstrap 2026-02-13 08:11:35 -06:00
John Alanbrook
0acaabd5fa merge add 2026-02-13 08:09:12 -06:00
John Alanbrook
1ba060668e growable buddy memory runtime 2026-02-13 07:59:52 -06:00
John Alanbrook
77fa058135 mach loading 2026-02-13 07:26:49 -06:00
John Alanbrook
f7e2ff13b5 guard hoisting 2026-02-13 06:32:58 -06:00
John Alanbrook
36fd0a35f9 Merge branch 'fix_gc' into mcode_streamline 2026-02-13 05:59:11 -06:00
John Alanbrook
77c02bf9bf simplify text 2026-02-13 05:59:01 -06:00
John Alanbrook
f251691146 Merge branch 'mach_memory' into mcode_streamline 2026-02-13 05:58:21 -06:00
John Alanbrook
e9ea6ec299 Merge branch 'runtime_rework' into mach_memory 2026-02-13 05:54:28 -06:00
John Alanbrook
bf5fdbc688 backward inference 2026-02-13 05:39:25 -06:00
John Alanbrook
b960d03eeb immediate ascii for string path 2026-02-13 05:35:11 -06:00
John Alanbrook
b4d42fb83d stone pool renamed to constant pool - more appropriate 2026-02-13 05:17:22 -06:00
John Alanbrook
0a680a0cd3 gc print 2026-02-13 05:03:45 -06:00
John Alanbrook
9f0fd84f4f fix growing gc 2026-02-13 04:33:32 -06:00
John Alanbrook
cb9d6e0c0e mmap for poison heap 2026-02-13 04:03:36 -06:00
John Alanbrook
4f18a0b524 tco 2026-02-13 03:57:18 -06:00
John Alanbrook
f296a0c10d fix segv 2026-02-13 03:08:27 -06:00
John Alanbrook
1df6553577 Merge branch 'runtime_rework' into mcode_streamline 2026-02-13 02:52:54 -06:00
John Alanbrook
30a9cfee79 simplify gc model 2026-02-13 02:33:25 -06:00
John Alanbrook
6fff96d9d9 lower intrinsics in mcode 2026-02-13 02:31:16 -06:00
John Alanbrook
4a50d0587d guards in mcode 2026-02-13 02:30:41 -06:00
John Alanbrook
e346348eb5 Merge branch 'fix_gc' into mcode_streamline 2026-02-12 19:15:13 -06:00
John Alanbrook
ff560973f3 Merge branch 'fix_gc' into runtime_rework 2026-02-12 18:57:44 -06:00
John Alanbrook
de4b3079d4 organize 2026-02-12 18:53:06 -06:00
John Alanbrook
29227e655b Merge branch 'pretty_mcode' into mcode_streamline 2026-02-12 18:48:17 -06:00
John Alanbrook
588e88373e Merge branch 'fix_ternary' into pretty_mcode 2026-02-12 18:46:04 -06:00
John Alanbrook
9aca365771 Merge branch 'runtime_rework' into pretty_mcode 2026-02-12 18:44:56 -06:00
John Alanbrook
c56d4d5c3c some cleanup 2026-02-12 18:44:09 -06:00
John Alanbrook
c1e101b24f benchmarks 2026-02-12 18:41:15 -06:00
John Alanbrook
9f0dfbc6a2 fix ternary operator in object literals 2026-02-12 18:33:43 -06:00
John Alanbrook
5c9403a43b compiler optimization output 2026-02-12 18:27:19 -06:00
John Alanbrook
89e34ba71d comprehensive testing for regression analysis 2026-02-12 18:15:03 -06:00
John Alanbrook
73bfa8d7b1 rm some functions 2026-02-12 18:08:56 -06:00
John Alanbrook
4aedb8b0c5 Merge branch 'cli_audit' into ir_artifact 2026-02-12 17:20:45 -06:00
John Alanbrook
ec072f3b63 Merge branch 'runtime_rework' into ir_artifact 2026-02-12 17:18:23 -06:00
John Alanbrook
65755d9c0c fix using old mach 2026-02-12 17:17:12 -06:00
John Alanbrook
19524b3a53 faster json decode 2026-02-12 17:06:48 -06:00
John Alanbrook
f901332c5b clean up cli 2026-02-12 16:45:10 -06:00
John Alanbrook
add136c140 Merge branch 'pretty_mcode' into runtime_rework 2026-02-12 16:36:58 -06:00
John Alanbrook
c1a99dfd4c mcode looks better 2026-02-12 16:36:53 -06:00
John Alanbrook
7b46c6e947 update docs 2026-02-12 16:34:45 -06:00
John Alanbrook
1efb0b1bc9 run with mcode 2026-02-12 16:14:46 -06:00
John Alanbrook
0ba2783b48 Merge branch 'bytecode_cleanup' into mach 2026-02-12 14:08:45 -06:00
John Alanbrook
6de542f0d0 Merge branch 'mach_suite_fix' into bytecode_cleanup 2026-02-12 12:32:06 -06:00
John Alanbrook
6ba4727119 rm call 2026-02-12 11:58:29 -06:00
John Alanbrook
900db912a5 streamline mcode 2026-02-12 09:43:13 -06:00
John Alanbrook
b771b2b5d8 suite passes now with mcode->mach lowering 2026-02-12 09:40:24 -06:00
John Alanbrook
68fb440502 Merge branch 'mach' into bytecode_cleanup 2026-02-12 07:50:09 -06:00
John Alanbrook
e7a2f16004 mcode to mach 2026-02-12 05:23:33 -06:00
John Alanbrook
3a8a17ab60 mcode->mach 2026-02-12 04:28:14 -06:00
John Alanbrook
8a84be65e1 new path 2026-02-11 14:41:37 -06:00
John Alanbrook
c1910ee1db Merge branch 'mcode2' into mach 2026-02-11 13:16:07 -06:00
John Alanbrook
7036cdf2d1 Merge branch 'mach' into bytecode_cleanup 2026-02-11 13:15:20 -06:00
John Alanbrook
fbeec17ce5 simplifications 2026-02-11 13:15:04 -06:00
John Alanbrook
2c55ae8cb2 quiesence exit 2026-02-11 11:50:29 -06:00
John Alanbrook
259bc139fc rm stack usage 2026-02-11 10:17:55 -06:00
John Alanbrook
a252412eca removal of old code 2026-02-11 09:47:30 -06:00
John Alanbrook
b327e16463 rm unused functions 2026-02-11 09:09:40 -06:00
John Alanbrook
da6f096a56 qbe rt 2026-02-10 20:28:51 -06:00
John Alanbrook
1320ef9f47 Merge branch 'mcode2' into mach 2026-02-10 19:04:35 -06:00
John Alanbrook
ed4a5474d5 Merge branch 'mach' into mcode2 2026-02-10 19:04:22 -06:00
John Alanbrook
f52dd80d52 fix compile error 2026-02-10 19:02:42 -06:00
John Alanbrook
504e268b9d run native modules 2026-02-10 18:52:11 -06:00
John Alanbrook
0d47002167 add compile script 2026-02-10 18:35:18 -06:00
John Alanbrook
b65db63447 remove vm_test, update test harness 2026-02-10 17:52:57 -06:00
John Alanbrook
c1ccff5437 fix >256 object literal error 2026-02-10 17:42:58 -06:00
John Alanbrook
2f681fa366 output for parser stages and c runtime doc 2026-02-10 17:38:15 -06:00
John Alanbrook
682b1cf9cf Merge branch 'pitweb' into mcode2 2026-02-10 17:29:03 -06:00
John Alanbrook
ddf3fc1c77 add object literal test 2026-02-10 17:28:59 -06:00
John Alanbrook
f1a5072ff2 fix increment operators on objects 2026-02-10 17:17:36 -06:00
John Alanbrook
f44fb502be string literal error 2026-02-10 17:02:22 -06:00
John Alanbrook
d75ce916d7 compile optimization 2026-02-10 16:37:11 -06:00
John Alanbrook
fe5dc6ecc9 fix fd.c bugs 2026-02-10 14:21:49 -06:00
John Alanbrook
54673e4a04 better disrupt logging; actor exit on crash 2026-02-10 12:38:06 -06:00
John Alanbrook
0d8b5cfb04 bootstrap loads engine 2026-02-10 12:13:18 -06:00
John Alanbrook
3d71f4a363 Merge branch 'mach' into pitweb 2026-02-10 11:15:44 -06:00
John Alanbrook
4deb0e2577 new syntax for internals 2026-02-10 11:03:01 -06:00
John Alanbrook
67b96e1627 add test for multiple declaration 2026-02-10 10:39:23 -06:00
John Alanbrook
4e5f1d8faa fix labeled loops, do-while, shorthand property syntax, and added more tests 2026-02-10 10:32:54 -06:00
John Alanbrook
bd577712d9 fix function shorthand default params 2026-02-10 10:13:46 -06:00
John Alanbrook
6df3b741cf add runtime warnings for stale files 2026-02-10 10:05:27 -06:00
John Alanbrook
178837b88d bootstrap 2026-02-10 09:53:41 -06:00
John Alanbrook
120ce9d30c Merge branch 'mcode2' into pitweb 2026-02-10 09:23:30 -06:00
John Alanbrook
58f185b379 fix merge 2026-02-10 09:21:33 -06:00
John Alanbrook
f7b5252044 core flag 2026-02-10 09:21:21 -06:00
John Alanbrook
ded5f7d74b cell shop env var 2026-02-10 09:13:10 -06:00
John Alanbrook
fe6033d6cb deploy website script 2026-02-10 08:12:51 -06:00
John Alanbrook
60e61eef76 scheduler starts 2026-02-10 08:12:42 -06:00
John Alanbrook
ad863fb89b postfix/prefix operators handled correctly 2026-02-10 08:12:27 -06:00
John Alanbrook
96f8157039 Merge branch 'mach' into mcode2 2026-02-10 07:38:35 -06:00
John Alanbrook
c4ff0bc109 intrinsics rewritten without ++, --, etc 2026-02-10 07:19:45 -06:00
John Alanbrook
877250b1d8 decomposed mcode 2026-02-10 07:12:27 -06:00
John Alanbrook
747227de40 better parse errors 2026-02-10 06:51:26 -06:00
John Alanbrook
3f7e34cd7a more useful parse errors 2026-02-10 06:08:15 -06:00
John Alanbrook
cef5c50169 add is_letter intrinsic 2026-02-10 06:00:47 -06:00
John Alanbrook
0428424ec7 Merge branch 'mach' into mcode2 2026-02-10 05:53:51 -06:00
John Alanbrook
78e64c5067 optimize parse 2026-02-10 05:53:49 -06:00
John Alanbrook
ff11c49c39 optimize tokenize 2026-02-10 05:52:19 -06:00
John Alanbrook
b8b110b616 bootstrap with serialized mach 2026-02-09 22:54:42 -06:00
John Alanbrook
930dcfba36 Merge branch 'mach' into mqbe 2026-02-09 22:22:15 -06:00
John Alanbrook
eeccb3b34a bootstrap 2026-02-09 22:21:55 -06:00
John Alanbrook
407797881c bytecode serialization 2026-02-09 22:19:41 -06:00
John Alanbrook
7069475729 Merge branch 'pitweb' into mcode2 2026-02-09 20:33:56 -06:00
John Alanbrook
3e42c57479 rm tokenizer/parser/mcode generators from C 2026-02-09 20:05:50 -06:00
John Alanbrook
4b76728230 ast folding 2026-02-09 20:04:40 -06:00
John Alanbrook
4ff9332d38 lsp 2026-02-09 18:53:13 -06:00
John Alanbrook
27e852af5b Merge branch 'mach' into mqbe 2026-02-09 18:46:10 -06:00
John Alanbrook
66a44595c8 fix errors with mcode 2026-02-09 18:45:55 -06:00
John Alanbrook
fc0a1547dc Merge branch 'mach' into mqbe 2026-02-09 18:36:47 -06:00
John Alanbrook
c0b4e70eb2 fix two gc bugs 2026-02-09 18:32:41 -06:00
John Alanbrook
f4714b2b36 qbe macros 2026-02-09 18:17:31 -06:00
John Alanbrook
7f691fd52b fix mach vm suite errors 2026-02-09 18:12:44 -06:00
John Alanbrook
d5209e1d59 fix issues with parse.cm and tokenize.cm 2026-02-09 17:43:44 -06:00
John Alanbrook
68e2395b92 mcode generators 2026-02-09 17:01:39 -06:00
John Alanbrook
1b747720b7 fix regex parser error 2026-02-09 14:34:33 -06:00
John Alanbrook
849123d8fc streamlined cell running 2026-02-09 13:12:05 -06:00
John Alanbrook
6ad919624b Merge branch 'mcode2' into mach 2026-02-09 12:58:05 -06:00
John Alanbrook
a11f3e7d47 Merge branch 'pitweb' into mach 2026-02-09 12:57:01 -06:00
John Alanbrook
3d1fd37979 rm quickjs vm 2026-02-09 12:54:55 -06:00
John Alanbrook
8fc9bfe013 parse and tokenize modules 2026-02-09 12:19:05 -06:00
John Alanbrook
368511f666 parse.ce and tokenize.ce 2026-02-09 11:56:09 -06:00
John Alanbrook
3934cdb683 fix disrupts 2026-02-09 11:28:10 -06:00
John Alanbrook
45556c344d Merge branch 'pitweb' into mach 2026-02-09 11:17:45 -06:00
John Alanbrook
bc87fe5f70 string indexing 2026-02-09 11:17:42 -06:00
John Alanbrook
790293d915 Merge branch 'mach' into pitweb 2026-02-09 11:15:44 -06:00
John Alanbrook
872cd6ab51 more correct syntax and AI instructions 2026-02-09 11:00:23 -06:00
John Alanbrook
e04ab4c30c bootstrap 2026-02-09 10:56:15 -06:00
John Alanbrook
0503acb7e6 rm block scope 2026-02-09 10:11:22 -06:00
John Alanbrook
d0c68d7a7d Merge branch 'mcode2' into pitweb 2026-02-09 10:00:28 -06:00
John Alanbrook
7469383e66 refactor into multiple files 2026-02-08 16:32:14 -06:00
John Alanbrook
1fee8f9f8b condense jsruntime and jscontext 2026-02-08 10:10:42 -06:00
John Alanbrook
a4f3b025c5 update 2026-02-08 08:25:48 -06:00
John Alanbrook
d18ea1b330 update engine.cm 2026-02-08 08:24:49 -06:00
John Alanbrook
4de0659474 allow tokens as properties 2026-02-08 00:34:15 -06:00
John Alanbrook
27a9b72b07 functino tests; default args for mach and mcode 2026-02-08 00:31:18 -06:00
John Alanbrook
a3622bd5bd better parser error reporting 2026-02-08 00:23:47 -06:00
John Alanbrook
2f6700415e add functinos 2026-02-07 23:38:39 -06:00
John Alanbrook
243d92f7f3 rm ?? and .? 2026-02-07 22:09:40 -06:00
John Alanbrook
8f9d026b9b use casesensitive json 2026-02-07 17:01:11 -06:00
John Alanbrook
2c9ac8f7b6 no json roundtrip for mcode 2026-02-07 16:29:04 -06:00
John Alanbrook
80f24e131f all suite asan errors fixed for mcode 2026-02-07 16:15:58 -06:00
John Alanbrook
a8f8af7662 Merge branch 'mach' into mcode2 2026-02-07 15:49:38 -06:00
John Alanbrook
f5b3494762 memfree for mcode 2026-02-07 15:49:36 -06:00
John Alanbrook
13a6f6c79d faster mach bytecode generation 2026-02-07 15:49:09 -06:00
John Alanbrook
1a925371d3 faster parsing 2026-02-07 15:38:36 -06:00
John Alanbrook
08d2bacb1f improve ast parsing time 2026-02-07 15:22:18 -06:00
John Alanbrook
7322153e57 Merge branch 'mach' into mcode2 2026-02-07 14:53:41 -06:00
John Alanbrook
cc72c4cb0f fix mem errors for mcode 2026-02-07 14:53:35 -06:00
John Alanbrook
ae1f09a28f fix all memory errors 2026-02-07 14:53:14 -06:00
John Alanbrook
3c842912a1 gc fixing in mach vm 2026-02-07 14:25:04 -06:00
John Alanbrook
7cacf32078 Merge branch 'mach' into mcode2 2026-02-07 14:24:52 -06:00
John Alanbrook
b740612761 gc fixing in mach vm 2026-02-07 14:24:49 -06:00
John Alanbrook
6001c2b4bb Merge branch 'mach' into mcode2 2026-02-07 14:19:19 -06:00
John Alanbrook
98625fa15b mcode fix tests 2026-02-07 14:19:17 -06:00
John Alanbrook
87fafa44c8 fix last error 2026-02-07 13:43:13 -06:00
John Alanbrook
45ce76aef7 fixes 2026-02-07 12:50:46 -06:00
John Alanbrook
32fb44857c 1 test failing now 2026-02-07 12:50:26 -06:00
John Alanbrook
31d67f6710 fix vm suite tests 2026-02-07 12:34:18 -06:00
John Alanbrook
bae4e957e9 hugo website for pit 2026-02-07 12:01:58 -06:00
John Alanbrook
3621b1ef33 Merge branch 'mach' into mcode2 2026-02-07 11:53:44 -06:00
John Alanbrook
836227c8d3 fix mach proxy and templates 2026-02-07 11:53:39 -06:00
John Alanbrook
0ae59705d4 fix errors 2026-02-07 11:53:26 -06:00
John Alanbrook
8e2607b6ca Merge branch 'mcode2' into mach 2026-02-07 10:54:19 -06:00
John Alanbrook
dc73e86d8c handle mcode in callinternal 2026-02-07 10:51:45 -06:00
John Alanbrook
555cceb9d6 fixed text runner 2026-02-07 10:51:27 -06:00
John Alanbrook
fbb7933eb6 Merge branch 'mcode2' into mach 2026-02-07 10:40:20 -06:00
John Alanbrook
0287d6ada4 regex uses C strings now 2026-02-07 10:28:35 -06:00
John Alanbrook
73cd6a255d more test fixing 2026-02-07 07:59:52 -06:00
John Alanbrook
83ea67c01b Merge branch 'mach' into mcode2 2026-02-07 00:10:01 -06:00
John Alanbrook
16059cca4e fix tests 2026-02-07 00:09:58 -06:00
John Alanbrook
9ffe60ebef vm suite 2026-02-07 00:09:41 -06:00
John Alanbrook
2beafec5d9 fix tests 2026-02-07 00:09:21 -06:00
John Alanbrook
aba8eb66bd crash fixes 2026-02-06 23:38:56 -06:00
John Alanbrook
1abcaa92c7 Merge branch 'mach' into mcode2 2026-02-06 23:20:55 -06:00
John Alanbrook
168f7c71d5 fix text header chasing 2026-02-06 23:20:48 -06:00
John Alanbrook
56ed895b6e Merge branch 'mach' into mcode2 2026-02-06 23:15:38 -06:00
John Alanbrook
1e4646999d fix mach crashes 2026-02-06 23:15:33 -06:00
John Alanbrook
68d6c907fe fix mcode compilation 2026-02-06 23:13:13 -06:00
John Alanbrook
8150c64c7d pitcode 2026-02-06 22:58:21 -06:00
John Alanbrook
024d796ca4 add asan error vm stacktrace 2026-02-06 21:49:53 -06:00
John Alanbrook
ea185dbffd rm typeof 2026-02-06 21:26:45 -06:00
John Alanbrook
6571262af0 mach disrupt support 2026-02-06 21:09:18 -06:00
John Alanbrook
77ae133747 Merge branch 'mcode2' into mach 2026-02-06 20:45:57 -06:00
John Alanbrook
142a2d518b Merge branch 'stacktrace' into mach 2026-02-06 20:44:43 -06:00
John Alanbrook
5b65c64fe5 stack traces 2026-02-06 20:44:38 -06:00
John Alanbrook
e985fa5fe1 disrupt/disruption; remove try/catch 2026-02-06 18:40:56 -06:00
John Alanbrook
160ade2410 smarter gc malloc for large allocations 2026-02-06 18:38:23 -06:00
John Alanbrook
e2bc5948c1 fix functions and closures in mach 2026-02-06 18:30:26 -06:00
John Alanbrook
8cf98d8a9e Merge branch 'mcode2' into mach 2026-02-06 15:14:40 -06:00
John Alanbrook
3c38e828e5 context free tokenizing, parsing, compiling 2026-02-06 15:14:18 -06:00
John Alanbrook
af2d296f40 use new parser info 2026-02-06 12:45:25 -06:00
John Alanbrook
0a45394689 fix crash related to allocating in context heap 2026-02-06 12:43:19 -06:00
John Alanbrook
32885a422f bring in mcode 2026-02-06 04:24:14 -06:00
John Alanbrook
8959e53303 Merge branch 'newsyn' into mcode2 2026-02-06 03:55:56 -06:00
John Alanbrook
8a9a02b131 Merge branch 'newsyn' into mach 2026-02-06 03:54:38 -06:00
John Alanbrook
f9d68b2990 fix if/else, chained assignment 2026-02-06 03:54:25 -06:00
John Alanbrook
017a57b1eb use new parser information 2026-02-06 03:44:44 -06:00
John Alanbrook
ff8c68d01c mcode and mcode interpreter 2026-02-06 03:31:31 -06:00
John Alanbrook
9212003401 cannot set unbound 2026-02-06 03:24:01 -06:00
John Alanbrook
f9f8a4db42 Merge branch 'newsyn' into mach 2026-02-06 03:10:14 -06:00
John Alanbrook
8db95c654b more info in AST parser 2026-02-06 03:00:46 -06:00
John Alanbrook
63feabed5d mach vm 2026-02-06 02:50:48 -06:00
John Alanbrook
c814c0e1d8 rm new; rm void 2026-02-06 02:12:19 -06:00
John Alanbrook
bead0c48d4 Merge branch 'mcode' into newsyn 2026-02-06 02:02:46 -06:00
John Alanbrook
98dcab4ba7 comprehensive syntax test; fix multiple default args 2026-02-06 02:02:17 -06:00
John Alanbrook
ae44ce7b4b mcode and mach 2026-02-06 01:56:26 -06:00
John Alanbrook
1c38699b5a fix scope resolution 2026-02-06 01:41:03 -06:00
John Alanbrook
9a70a12d82 object literal 2026-02-05 21:41:34 -06:00
John Alanbrook
a8a271e014 Merge branch 'syntax' into ast 2026-02-05 20:39:56 -06:00
John Alanbrook
91761c03e6 push/pop syntax 2026-02-05 20:39:53 -06:00
John Alanbrook
5a479cc765 function literal in record literal 2026-02-05 20:32:57 -06:00
John Alanbrook
97a003e025 errors 2026-02-05 20:12:06 -06:00
John Alanbrook
20f14abd17 string templates 2026-02-05 19:34:06 -06:00
John Alanbrook
19ba184fec default params for functions 2026-02-05 18:44:40 -06:00
John Alanbrook
7909b11f6b better errors 2026-02-05 18:35:48 -06:00
John Alanbrook
27229c675c add parser and tokenizer errors 2026-02-05 18:14:49 -06:00
John Alanbrook
64d234ee35 Merge branch 'syntax' into ast 2026-02-05 17:45:15 -06:00
John Alanbrook
e861d73eec mkarecord 2026-02-05 17:45:13 -06:00
John Alanbrook
a24331aae5 tokenize 2026-02-05 11:21:34 -06:00
John Alanbrook
c1cb922b64 more comprehensive ast 2026-02-05 10:59:56 -06:00
John Alanbrook
aacb0b48bf more vm tests 2026-02-05 10:44:53 -06:00
John Alanbrook
b38aec95b6 Merge branch 'syntax' into ast 2026-02-05 10:29:29 -06:00
John Alanbrook
b29d3c2fe0 add vm tests 2026-02-05 10:29:09 -06:00
John Alanbrook
1cc3005b68 better jump labels 2026-02-05 10:28:13 -06:00
John Alanbrook
b86cd042fc vm unit tests 2026-02-05 10:21:16 -06:00
John Alanbrook
8b7af0c22a vm bytecode output 2026-02-05 10:14:14 -06:00
John Alanbrook
f71f6a296b register vm 2026-02-05 06:55:45 -06:00
John Alanbrook
9bd764b11b add go 2026-02-05 03:10:06 -06:00
John Alanbrook
058cdfd2e4 groundwork for vm 2026-02-05 02:59:16 -06:00
John Alanbrook
1ef837c6ff rm bound function stuff 2026-02-05 02:36:14 -06:00
John Alanbrook
cd21de3d70 rm realm concept on function 2026-02-05 02:33:50 -06:00
John Alanbrook
a98faa4dbb debugging 2026-02-05 02:27:26 -06:00
John Alanbrook
08559234c4 fix closures 2026-02-05 02:07:18 -06:00
John Alanbrook
c3dc27eac6 machine code 2026-02-04 23:45:51 -06:00
John Alanbrook
7170a9c7eb ast 2026-02-04 22:20:57 -06:00
John Alanbrook
a08ee50f84 serializable bytecode 2026-02-04 20:57:44 -06:00
John Alanbrook
ed7dd91c3f rm global 2026-02-04 18:57:45 -06:00
John Alanbrook
3abe20fee0 merge 2026-02-04 18:38:46 -06:00
John Alanbrook
a92a96118e remove eval parser; consolidate addintrinsic 2026-02-04 17:15:03 -06:00
John Alanbrook
4e407fe301 migrate nota, wota into quickjs.c 2026-02-04 17:03:48 -06:00
John Alanbrook
ab74cdc173 merge warningfix 2026-02-04 16:17:52 -06:00
John Alanbrook
2c9d039271 massive cleanup 2026-02-04 14:26:17 -06:00
John Alanbrook
80d314c58f Merge templatefix branch
Use PPretext for parser string building to avoid GC issues during parsing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:21:25 -06:00
John Alanbrook
611fba2b6f fix regexp parsing 2026-02-04 14:19:39 -06:00
John Alanbrook
f5fad52d47 Rewrite template literals with OP_format_template
Replace complex template literal handling with a simple format-based
approach. Template literals like `hello ${x}` now compile to:
  <push x>
  OP_format_template expr_count=1, cpool_idx=N
where cpool[N] = "hello {0}"

The opcode handler parses the format string, substitutes {N} placeholders
with stringified stack values, and produces the result string.

Key implementation details:
- Uses PPretext (parser pretext) with pjs_malloc to avoid GC issues
- Re-reads b->cpool[cpool_idx] after any GC-triggering operation
- Opcode layout is u16 expr_count followed by u32 cpool_idx - the u16
  must come first because compute_stack_size reads the pop count from
  position 1 for npop_u16 format opcodes

Removed:
- OP_template_concat opcode and handler
- Tagged template literal support (users can use format() directly)
- FuncCallType enum (FUNC_CALL_TEMPLATE case no longer needed)
- Complex template object creation logic in js_parse_template

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:18:02 -06:00
John Alanbrook
2fc7d333ad new environment tact for engine 2026-02-04 14:12:57 -06:00
John Alanbrook
d4635f2a75 remove unused vars, fix warnings 2026-02-04 13:49:43 -06:00
John Alanbrook
19576533d9 no more global obj; eval w/ env 2026-02-03 23:07:30 -06:00
John Alanbrook
c08249b6f1 clean up var ref 2026-02-03 22:01:42 -06:00
John Alanbrook
dc348d023f optimize lref 2026-02-03 21:37:17 -06:00
John Alanbrook
fd5e4d155e varref cleanup 2026-02-03 20:09:35 -06:00
John Alanbrook
e734353722 Begin removal of varref 2026-02-03 19:13:17 -06:00
John Alanbrook
94f1645be1 new closure model 2026-02-03 19:04:38 -06:00
John Alanbrook
41e3a6d91a closures work 2026-02-03 18:42:14 -06:00
John Alanbrook
04c569eab1 fix parser 2026-02-03 18:24:06 -06:00
John Alanbrook
dc3c474b3a link 2026-02-03 18:01:31 -06:00
John Alanbrook
f1117bbd41 get_global 2026-02-03 17:35:24 -06:00
John Alanbrook
43faad95e0 new opcodes 2026-02-03 17:21:41 -06:00
John Alanbrook
acc9878b36 bytecode dump 2026-02-03 17:08:21 -06:00
John Alanbrook
03c45ee8b0 lexer 2026-02-03 16:59:20 -06:00
John Alanbrook
a171a0d2af -e flag run script 2026-02-03 16:06:18 -06:00
John Alanbrook
bb8d3930b3 fix many internals wrt gc 2026-02-03 06:55:26 -06:00
John Alanbrook
522ae6128a add FORCE_GC_AT_MALLOC logic 2026-02-03 03:00:46 -06:00
John Alanbrook
16c26e4bf2 fix object fwd growth 2026-02-03 02:53:06 -06:00
John Alanbrook
a9804785e0 fix gc 2026-02-03 02:44:52 -06:00
John Alanbrook
11ae703693 suite.c roots 2026-02-03 02:40:40 -06:00
John Alanbrook
f203278c3e more gc correctness 2026-02-03 02:31:14 -06:00
John Alanbrook
a80557283a fix poison heap 2026-02-03 02:06:29 -06:00
John Alanbrook
3e40885e07 extensive debugging; fixed forwarding error 2026-02-03 01:50:30 -06:00
John Alanbrook
e4b7de46f6 add function aware to gc 2026-02-03 01:20:24 -06:00
John Alanbrook
e680439a9b gc asan poison 2026-02-03 01:03:23 -06:00
John Alanbrook
ae11504e00 copy gc 2026-02-03 00:34:07 -06:00
John Alanbrook
893deaec23 suite.c all works 2026-02-02 23:39:12 -06:00
John Alanbrook
69b032d3dc rm gc 2026-02-02 23:02:50 -06:00
John Alanbrook
256a00c501 fix mem errors 2026-02-02 22:54:38 -06:00
John Alanbrook
8e166b8f98 gc aware 2026-02-02 22:46:07 -06:00
John Alanbrook
ddbdd00496 update text and object to be gc aware 2026-02-02 22:37:42 -06:00
John Alanbrook
bdf0461e1f extensive C testing 2026-02-02 21:26:46 -06:00
John Alanbrook
0b86af1d4c array gc 2026-02-02 20:33:11 -06:00
John Alanbrook
beac9608ea chase 2026-02-02 18:54:15 -06:00
John Alanbrook
a04bebd0d7 fix str 2026-02-02 10:38:48 -06:00
John Alanbrook
ce74f726dd compiles + runs 2026-02-02 10:24:02 -06:00
John Alanbrook
4d1ab60852 rm notion of object values 2026-02-02 09:54:36 -06:00
John Alanbrook
22ab6c8098 rm gc fns 2026-02-02 09:22:51 -06:00
John Alanbrook
9a9775690f rm function proto 2026-02-02 08:35:14 -06:00
John Alanbrook
be71ae3bba remove **Free type functions 2026-02-02 08:32:11 -06:00
John Alanbrook
f2a76cbb55 fix number rep 2026-02-02 07:56:53 -06:00
John Alanbrook
2d834c37b3 simplify eq 2026-02-02 06:56:46 -06:00
John Alanbrook
ba1b92aa78 rm freevalue and dupvalue 2026-02-02 06:27:08 -06:00
John Alanbrook
c356fe462d compiles 2026-02-02 06:15:10 -06:00
John Alanbrook
b23b918f97 compiles 2026-02-01 23:03:01 -06:00
John Alanbrook
e720152bcd gc plan 2026-02-01 20:58:42 -06:00
John Alanbrook
f093e6f5a3 reformat 2026-02-01 19:36:20 -06:00
John Alanbrook
4fc904de63 rm 2026-02-01 19:33:19 -06:00
John Alanbrook
e53f55fb23 pretext 2026-02-01 18:59:52 -06:00
John Alanbrook
6150406905 pretext 2026-02-01 18:34:35 -06:00
John Alanbrook
a189440769 stringbuffer 2026-02-01 17:58:11 -06:00
John Alanbrook
6c3c492446 rm jsstring and string_buffer 2026-02-01 12:34:38 -06:00
John Alanbrook
bb83327a52 transformation 2026-02-01 07:45:44 -06:00
John Alanbrook
c74bee89a7 plan 2026-01-31 14:59:31 -06:00
John Alanbrook
271a3d6724 before gc rewrite 2026-01-31 14:43:21 -06:00
John Alanbrook
c5ccc66e51 simpler enumeration of property names 2026-01-31 12:13:35 -06:00
John Alanbrook
3a0ea31896 rm dump profile 2026-01-31 12:01:33 -06:00
John Alanbrook
67e82fd12c merge objects and recs 2026-01-31 11:40:16 -06:00
John Alanbrook
3c59087c0c merge jsobject to jsrecord 2026-01-31 11:36:07 -06:00
John Alanbrook
b79e07f57b more atom removal 2026-01-31 11:14:02 -06:00
John Alanbrook
fdcb374403 fix formatting 2026-01-31 10:33:29 -06:00
John Alanbrook
03feb370fd rm atoms 2026-01-31 06:51:19 -06:00
John Alanbrook
6712755940 edit lexer atoms 2026-01-30 21:33:10 -06:00
John Alanbrook
b3f3bc8a5f rm atoms 2026-01-30 20:16:08 -06:00
John Alanbrook
a49b94e0a1 phase3 2026-01-30 17:02:50 -06:00
John Alanbrook
24ecff3f1c rm atom' 2026-01-30 09:58:02 -06:00
John Alanbrook
3ccaf68a5b begin rm atoms 2026-01-30 02:12:05 -06:00
John Alanbrook
64933260d4 docs 2026-01-29 22:07:48 -06:00
John Alanbrook
561ab9d917 mem 2026-01-29 20:33:38 -06:00
John Alanbrook
bcd6e641a5 initial try 2026-01-27 19:17:44 -06:00
John Alanbrook
2857581271 cleanup 2026-01-27 10:42:49 -06:00
John Alanbrook
378ad6dc98 tracy 2026-01-26 20:13:44 -06:00
John Alanbrook
06f7791159 use internal calls for internals 2026-01-26 11:44:21 -06:00
John Alanbrook
086508bacd quicken 2026-01-25 20:29:49 -06:00
John Alanbrook
8325253f1a fixed function arity 2026-01-25 13:51:34 -06:00
John Alanbrook
802c94085b rm flags in c fn calls 2026-01-25 09:45:13 -06:00
John Alanbrook
f9170b33e5 rm old function as object code 2026-01-24 09:55:24 -06:00
John Alanbrook
20f10ab887 initial attempt change functions to intrinsic type 2026-01-24 08:57:20 -06:00
John Alanbrook
d8b13548d2 objects directly used as properties now instead of shadow symbol table 2026-01-23 23:33:52 -06:00
John Alanbrook
0d93741c31 fix array free 2026-01-23 22:54:49 -06:00
John Alanbrook
c6440ff98c tag array coverage 2026-01-23 22:51:46 -06:00
John Alanbrook
a01b48dabc add rc trace" 2026-01-23 17:22:07 -06:00
John Alanbrook
beea76949c rm bigint 2026-01-23 15:05:57 -06:00
John Alanbrook
36833db2c9 ArrayLength returns correct value 2026-01-23 11:40:23 -06:00
John Alanbrook
b7615bb801 fix error messaging 2026-01-23 11:28:06 -06:00
John Alanbrook
e6838338fc fix failing tests 2026-01-23 11:03:32 -06:00
John Alanbrook
4cf0ce00de fix tests 2026-01-23 05:58:47 -06:00
John Alanbrook
0714017547 atoms 2026-01-23 05:44:02 -06:00
John Alanbrook
b60e79ccad rm integer atoms 2026-01-22 19:12:12 -06:00
John Alanbrook
420c2b859a rm getset 2026-01-22 09:55:02 -06:00
John Alanbrook
6c1f53ec5f rm autoinit 2026-01-22 09:16:01 -06:00
John Alanbrook
45d82438ca intrinsic arrays 2026-01-22 08:30:41 -06:00
John Alanbrook
addb38da65 intrinsic arrays 2026-01-21 19:38:38 -06:00
John Alanbrook
aa847ddf6e no more string class type 2026-01-21 17:36:19 -06:00
John Alanbrook
4da63db16e rm constructor 2026-01-21 13:38:38 -06:00
John Alanbrook
bfdd920178 rm some more fns 2026-01-21 10:41:29 -06:00
John Alanbrook
26fce3a5a8 rm array proto funcs 2026-01-21 00:52:18 -06:00
John Alanbrook
ef49606098 rm numeric 2026-01-20 20:09:06 -06:00
John Alanbrook
854d94e5c3 rm constructors 2026-01-20 16:46:30 -06:00
John Alanbrook
dc02d6899d prune eq 2026-01-20 16:38:24 -06:00
John Alanbrook
b28ef39562 rm string coercion 2026-01-20 14:13:16 -06:00
John Alanbrook
2841e91f40 add property get 2026-01-20 12:04:16 -06:00
John Alanbrook
8d601dfce3 rm constructors 2026-01-20 12:01:40 -06:00
John Alanbrook
2b60e3a242 rm dependence on tostring 2026-01-20 10:08:35 -06:00
John Alanbrook
823183c510 length 2026-01-20 08:36:28 -06:00
John Alanbrook
c051a99e75 restore toml cache regression 2026-01-20 05:33:44 -06:00
John Alanbrook
b3c0837d49 rm new 2026-01-20 05:20:45 -06:00
John Alanbrook
ff18682485 rm for ... in 2026-01-19 18:56:54 -06:00
John Alanbrook
9b3891c126 rm spreads and iterators 2026-01-19 16:01:39 -06:00
John Alanbrook
38a3697e28 meme 2026-01-19 14:39:55 -06:00
John Alanbrook
cbf99295da rm of 2026-01-19 01:06:45 -06:00
John Alanbrook
5271688dd4 length 2026-01-18 11:22:17 -06:00
John Alanbrook
98cb2c3239 switch to length fn 2026-01-18 10:35:05 -06:00
John Alanbrook
e695810e64 fix build 2026-01-18 09:59:54 -06:00
John Alanbrook
bbd2d298ba arrfor" 2026-01-18 08:54:48 -06:00
John Alanbrook
a7a323a74e rm index and indexof 2026-01-17 16:21:02 -06:00
John Alanbrook
97ece8e5cb text extract 2026-01-17 15:48:43 -06:00
John Alanbrook
45ee4a337c add not 2026-01-17 11:12:54 -06:00
John Alanbrook
ce7d83ec91 rm fns 2026-01-16 20:55:57 -06:00
John Alanbrook
b46406f755 rm js fns 2026-01-16 18:15:29 -06:00
John Alanbrook
ac91495679 rm top level fns 2026-01-15 18:16:34 -06:00
John Alanbrook
5018901acb cache config in package.cm 2026-01-15 15:54:58 -06:00
John Alanbrook
78a46b4a72 rm map/set 2026-01-15 14:39:37 -06:00
John Alanbrook
66a9ca27e2 rm new 2026-01-13 22:16:28 -06:00
John Alanbrook
ac4b47f075 rm function proto funcs 2026-01-11 23:34:35 -06:00
John Alanbrook
6b9f75247e log is a proxy now 2026-01-11 23:22:15 -06:00
John Alanbrook
b039b0c4ba fn proxy 2026-01-11 23:13:58 -06:00
John Alanbrook
ffe7b61ae2 remove property access for bytecode functions 2026-01-11 13:22:36 -06:00
John Alanbrook
17b9aaaf51 fix issue where linked packages would not load dylibs correctly 2026-01-11 11:49:48 -06:00
John Alanbrook
5fd29366a6 skip relink when content hasn't changed 2026-01-09 11:51:05 -06:00
John Alanbrook
f16586eaa2 fix fetch 2026-01-09 11:49:22 -06:00
John Alanbrook
86a70bce3a fd check blob stone 2026-01-09 08:23:40 -06:00
John Alanbrook
e04b15973a link 2026-01-09 07:36:48 -06:00
John Alanbrook
d044bde4f9 clean up cmd line 2026-01-09 05:37:37 -06:00
John Alanbrook
8403883b9d blob w32 2026-01-08 21:00:56 -06:00
John Alanbrook
69245f82db remove instanceof operator 2026-01-08 12:26:11 -06:00
John Alanbrook
8203f6d1c3 fixes 2026-01-08 12:07:32 -06:00
John Alanbrook
ef94b55058 update 2026-01-08 09:10:47 -06:00
John Alanbrook
3a3e77eccd remove number and boolean prototypes 2026-01-07 07:06:02 -06:00
John Alanbrook
438c90acb5 ignore 2026-01-06 20:31:49 -06:00
John Alanbrook
dd309b1a37 remove isa 2026-01-06 11:17:07 -06:00
John Alanbrook
63cf76dcf9 remove typeof' 2026-01-06 11:08:27 -06:00
John Alanbrook
df07069c38 return null in bad retrieval, throw on bad insert 2026-01-06 09:16:15 -06:00
John Alanbrook
eba0727247 object cannot use anything but string and obj as keys 2026-01-06 09:11:47 -06:00
John Alanbrook
b0f0a5f63f remove some unneeded functions 2026-01-03 08:25:32 -06:00
John Alanbrook
d12d77c22c objects now work as private non enumerable keys 2026-01-02 16:28:02 -06:00
John Alanbrook
d6468e7fd2 remove old math code 2026-01-02 15:41:29 -06:00
John Alanbrook
7ae5a0c06b null + anything = null 2025-12-30 14:40:54 -06:00
John Alanbrook
0664c11af6 set up quickening for adds 2025-12-30 00:39:43 -06:00
John Alanbrook
058ad89c96 op switch 2025-12-29 20:46:12 -06:00
John Alanbrook
a0038a7ab2 blob 2025-12-29 17:53:21 -06:00
John Alanbrook
d0674e7921 remove internal scripts 2025-12-29 15:45:21 -06:00
John Alanbrook
b586df63ad move internals to pure C 2025-12-29 14:28:54 -06:00
John Alanbrook
05b57550da vm trampoline setup 2025-12-29 13:01:05 -06:00
John Alanbrook
fa616ee444 trampoline 2025-12-29 01:35:57 -06:00
John Alanbrook
0720368c48 go 2025-12-29 01:26:25 -06:00
John Alanbrook
4f3e2819fe var behaves like let 2025-12-29 00:48:28 -06:00
John Alanbrook
3b53a9dcc3 prop ic 2025-12-28 23:55:57 -06:00
John Alanbrook
6d7581eff8 IC structure 2025-12-28 23:38:10 -06:00
John Alanbrook
dca1963b5d null access 2025-12-28 22:57:53 -06:00
John Alanbrook
1833a3c74c remove some globals 2025-12-28 22:46:05 -06:00
John Alanbrook
4201be47ee dump_profile 2025-12-28 21:53:12 -06:00
John Alanbrook
c388fb311b larger test suite 2025-12-28 21:04:30 -06:00
John Alanbrook
c432bc211f bench 2025-12-28 19:50:27 -06:00
John Alanbrook
5f471ee003 fix array length creation 2025-12-28 16:22:11 -06:00
John Alanbrook
5d384e2706 fix meme 2025-12-28 16:14:29 -06:00
John Alanbrook
a0daf98ca8 patch so core path is recognized 2025-12-28 16:03:13 -06:00
John Alanbrook
3b42426e6f string + number throws 2025-12-28 14:25:57 -06:00
John Alanbrook
a035e28100 string add throw 2025-12-28 13:43:10 -06:00
John Alanbrook
4f076bc868 better commands 2025-12-27 13:51:11 -06:00
John Alanbrook
c8831c85d0 proper dylib loading order 2025-12-27 13:15:59 -06:00
John Alanbrook
3cf7aa473e add wf and w16 fns to blob 2025-12-22 16:29:38 -06:00
John Alanbrook
8b9e088385 util 2025-12-21 10:37:02 -06:00
John Alanbrook
d50f4119ee remove global 2025-12-18 18:43:23 -06:00
John Alanbrook
aa18a8c8d2 remove json as a global 2025-12-18 11:20:39 -06:00
John Alanbrook
04a648a73e mkdocs website 2025-12-17 03:45:09 -06:00
John Alanbrook
363ca1c3c1 docs revamp 2025-12-17 02:53:01 -06:00
John Alanbrook
3211b59408 no more js 2025-12-17 00:48:02 -06:00
John Alanbrook
169448f156 fix random() 2025-12-14 13:30:46 -06:00
John Alanbrook
b98cef6e8d add pronto and tests 2025-12-13 19:14:20 -06:00
John Alanbrook
33dc6b053c fix fetch failure 2025-12-12 17:27:51 -06:00
John Alanbrook
6ff54d8347 fix module resolution 2025-12-11 23:18:58 -06:00
John Alanbrook
bf421743a5 fix scheduler 2025-12-11 14:42:30 -06:00
John Alanbrook
5a3e260821 simplify docs 2025-12-10 15:18:53 -06:00
John Alanbrook
d0f5dc6951 playdate cake 2025-12-10 15:01:20 -06:00
John Alanbrook
752479e250 fix links, fix hot reload 2025-12-10 01:37:21 -06:00
John Alanbrook
37f2cff6ec fix 2025-12-09 23:19:25 -06:00
John Alanbrook
657e342159 core is now at packages/core 2025-12-09 01:00:10 -06:00
John Alanbrook
de4c9c724e fixing shop 2025-12-09 00:48:59 -06:00
John Alanbrook
5c5427fdd9 reduce shop 2025-12-08 19:50:09 -06:00
John Alanbrook
38d6b4d4e8 turn into a cell package 2025-12-08 17:39:17 -06:00
John Alanbrook
aae267a6e9 dynamic works; static works for non cell builds 2025-12-08 15:27:20 -06:00
John Alanbrook
dbc1b2c31e reorganize 2025-12-08 13:49:27 -06:00
John Alanbrook
32301cf61f remove some comments 2025-12-08 13:38:18 -06:00
John Alanbrook
270521a01e fix link and remove 2025-12-08 13:22:07 -06:00
John Alanbrook
401f69b503 global cell shops 2025-12-08 13:01:44 -06:00
John Alanbrook
1bcdab64ff add toolchain targets; better names for logging 2025-12-07 18:49:05 -06:00
John Alanbrook
107c4a5dce tests can now start actor based tests 2025-12-07 15:35:45 -06:00
John Alanbrook
16aba47782 packing 2025-12-07 13:50:57 -06:00
John Alanbrook
14cf48931d add emscripten target 2025-12-07 11:54:03 -06:00
John Alanbrook
c24a5079cb playdate support 2025-12-07 04:04:11 -06:00
John Alanbrook
ce5949e0ee remove tracy, mimalloc, enet subprojects; now it's just enet.h 2025-12-07 00:44:02 -06:00
John Alanbrook
3f2b4177d6 start playdate support 2025-12-06 17:35:23 -06:00
John Alanbrook
687c6d264f playdate cross file 2025-12-06 15:20:40 -06:00
John Alanbrook
abf1332bf5 remove curl dep 2025-12-06 14:54:00 -06:00
John Alanbrook
7c0f4dcd5f fixme freeze 2025-12-06 12:30:14 -06:00
John Alanbrook
33ebd8f45d more debug functions 2025-12-06 12:02:19 -06:00
John Alanbrook
5ac58dfbb0 reload module 2025-12-06 11:33:34 -06:00
John Alanbrook
825c6aa284 fix why 2025-12-06 10:37:00 -06:00
John Alanbrook
3bcc642158 add linking 2025-12-06 10:35:06 -06:00
John Alanbrook
ea510d609f fix tests 2025-12-05 23:21:07 -06:00
John Alanbrook
744f64b83b remove sdl header reqs; better compile invalidation 2025-12-05 19:31:56 -06:00
John Alanbrook
7a6209df72 add tests 2025-12-05 15:38:38 -06:00
John Alanbrook
dde0efc8aa better list; add why 2025-12-05 14:57:50 -06:00
John Alanbrook
d6daa97ac7 main wrapper 2025-12-05 12:52:40 -06:00
John Alanbrook
230880a02f fix 2025-12-05 08:30:51 -06:00
John Alanbrook
d229784d8d fix cached modules 2025-12-04 21:54:38 -06:00
John Alanbrook
19e747c120 fixed linking 2025-12-04 20:15:32 -06:00
John Alanbrook
22d3adca93 update local dirs 2025-12-04 14:56:11 -06:00
John Alanbrook
20fa012b57 add symlink capabilities to fd.c 2025-12-04 14:19:02 -06:00
John Alanbrook
95ac4bd096 fix blob 2025-12-04 13:54:00 -06:00
John Alanbrook
6b8464aca4 fix blob 2025-12-04 07:35:31 -06:00
John Alanbrook
39ac340e01 compilation 2025-12-03 23:42:19 -06:00
John Alanbrook
fc87c05daf ls 2025-12-03 20:18:46 -06:00
John Alanbrook
1886f10211 add list and ls functions 2025-12-03 19:03:01 -06:00
John Alanbrook
c8ce152ade use build if built 2025-12-03 16:40:37 -06:00
John Alanbrook
1a9734f265 grabbing module works now 2025-12-03 15:39:49 -06:00
John Alanbrook
ac718fdb13 remove some scripts 2025-12-03 15:34:01 -06:00
John Alanbrook
1769d7f456 update shop 2025-12-03 15:29:42 -06:00
John Alanbrook
85e0e3dab1 check hashes on cached files 2025-12-03 13:53:47 -06:00
John Alanbrook
ddfa636ac0 locks 2025-12-03 09:11:51 -06:00
John Alanbrook
ee3a890d4a fix 2025-12-03 08:28:33 -06:00
John Alanbrook
76bdccc4ee fix 2025-12-03 07:59:31 -06:00
John Alanbrook
814ee7c0db use 2025-12-03 06:41:18 -06:00
John Alanbrook
0c5609c4e9 fix compile 2025-12-02 06:45:09 -06:00
John Alanbrook
20f5e4e81c fix random numer generating; add cell_random_fit to complement cell_random) 2025-12-01 16:26:27 -06:00
John Alanbrook
139405a30b update miniz to 3.1 2025-12-01 16:10:58 -06:00
John Alanbrook
495f145524 single threaded executor 2025-12-01 15:54:12 -06:00
John Alanbrook
6cfba975e5 remove sdl dependency 2025-12-01 15:38:04 -06:00
John Alanbrook
fd4222f196 fix compile 2025-12-01 09:10:12 -06:00
John Alanbrook
5971924785 scheduler 2025-12-01 08:47:09 -06:00
John Alanbrook
8e4c60baf3 remove sdl from os.c 2025-12-01 06:21:00 -06:00
John Alanbrook
53085d7e3a remove jsffi 2025-11-30 20:43:25 -06:00
John Alanbrook
c88d551cad remove qjs_wota 2025-11-30 20:30:57 -06:00
John Alanbrook
4b5ceb4c02 fix compile warnings; remove soloud 2025-11-30 19:33:04 -06:00
John Alanbrook
2b90a160ba remove qjs_macros.h 2025-11-30 17:28:05 -06:00
John Alanbrook
4df134b327 intenrals no longer depend on cellfs 2025-11-30 17:24:02 -06:00
John Alanbrook
b44d79ccab compile cpp files 2025-11-30 16:37:36 -06:00
John Alanbrook
b29cdc8b93 add variable linker flags per platform 2025-11-30 14:59:35 -06:00
John Alanbrook
42bede58bc js doc 2025-11-30 01:26:59 -06:00
John Alanbrook
3800c23eae remove num.c 2025-11-29 23:47:47 -06:00
John Alanbrook
8fa80b4720 move away from cellfs 2025-11-29 23:44:40 -06:00
John Alanbrook
acf842e2a1 remove cell doc 2025-11-29 23:35:10 -06:00
John Alanbrook
1d295d11e5 modifications to importing 2025-11-29 18:34:37 -06:00
John Alanbrook
0ddbc3e953 remove more unneeded from the std 2025-11-29 17:26:29 -06:00
John Alanbrook
9f696a0342 random 2025-11-29 16:43:03 -06:00
John Alanbrook
efe93b7206 move random number gen 2025-11-29 14:22:19 -06:00
John Alanbrook
a9cff079d9 cell2 2025-11-29 12:40:59 -06:00
John Alanbrook
d361cb0555 get c symbol 2025-11-28 13:07:36 -06:00
John Alanbrook
b577e889a1 script folder 2025-11-26 20:25:00 -06:00
John Alanbrook
e28e241485 cleanup 2025-11-26 18:22:22 -06:00
John Alanbrook
2110688fa5 strip out prosperon from cell 2025-11-26 12:23:57 -06:00
John Alanbrook
fd19ecb41e sdl audio 2025-11-26 02:07:44 -06:00
John Alanbrook
155d0bf4b5 remove quirc 2025-11-25 23:36:56 -06:00
John Alanbrook
311a57b1e2 header cleanup 2025-11-25 21:05:48 -06:00
John Alanbrook
2cf94f7c57 allow installing headers for cell mods 2025-11-25 16:06:48 -06:00
John Alanbrook
9b19d19698 qopconv; now uses cell's own qopconv for building 2025-11-25 12:25:28 -06:00
John Alanbrook
67badc3e48 remove physfs; cellfs now is at parity 2025-11-25 09:56:44 -06:00
John Alanbrook
820413a72a cellfs 2025-11-25 09:16:50 -06:00
John Alanbrook
8bc31e3ac6 fetch 2025-11-24 23:08:40 -06:00
John Alanbrook
b613c7b6fa qop 2025-11-24 08:40:20 -06:00
John Alanbrook
8bdcaf7d9d qop 2025-11-23 11:20:59 -06:00
John Alanbrook
2beb369af9 move rtree to its own lib 2025-11-23 10:11:54 -06:00
John Alanbrook
44c46f2bb4 use curl 2025-11-22 22:25:59 -06:00
John Alanbrook
20685d80f1 add big file test to cellfs 2025-11-22 20:23:10 -06:00
John Alanbrook
532cfd0ed0 initial attempt at cellfs 2025-11-22 19:07:22 -06:00
John Alanbrook
34de9e6dc4 remove prosperon 2025-11-22 17:46:53 -06:00
John Alanbrook
9881158e62 init 2025-11-22 15:02:21 -06:00
John Alanbrook
be416b0124 clay 2025-11-22 01:48:30 -06:00
John Alanbrook
906b60276a update dmon to work on macos 2025-11-22 01:00:03 -06:00
John Alanbrook
d61f98f81d hover 2025-11-22 00:37:05 -06:00
John Alanbrook
dbf9f8ef30 clay 2025-11-18 19:12:30 -06:00
John Alanbrook
0082eab729 clay accepts any size canvas now 2025-11-06 18:23:39 -06:00
John Alanbrook
60d2d3b8d6 fix text 2025-11-06 18:11:01 -06:00
John Alanbrook
0dd4ad8046 fix font 2025-11-06 15:02:03 -06:00
John Alanbrook
c02b42f710 attempting to fix text wrapping ... 2025-11-06 14:47:36 -06:00
John Alanbrook
6961e19114 clay tree 2025-11-06 13:49:51 -06:00
John Alanbrook
721ac3bb93 fix word wrap meausrement 2025-11-06 13:15:38 -06:00
John Alanbrook
768ad399de clay recognize text size 2025-11-05 17:40:01 -06:00
John Alanbrook
a05dda4914 text wrap 2025-11-04 19:16:36 -06:00
John Alanbrook
149ee23e45 imgui with sdl gpu 2025-11-03 23:24:34 -06:00
John Alanbrook
c9b504ead4 feat: improve image and text rendering defaults
- Added default dimensions for images when width/height not specified, using original image size
- Enhanced text rendering to use natural text dimensions when width/height not provided
- Disabled file monitoring system by nullifying dmon to prevent unnecessary file watching
2025-11-03 14:00:02 -06:00
John Alanbrook
a8eed4e0d8 fix clay 2025-11-01 14:12:58 -05:00
John Alanbrook
708c01ee29 use prosperon.camera 2025-10-26 13:59:08 -05:00
John Alanbrook
8a33be3550 fix camera 2025-10-24 12:45:39 -05:00
John Alanbrook
175146ab37 sprites don't warp 2025-10-24 11:06:37 -05:00
John Alanbrook
ef7b492984 update render 2025-10-23 15:10:41 -05:00
John Alanbrook
923b5bc3d6 tilemap no longer uses ppu 2025-10-09 03:32:08 -05:00
John Alanbrook
5b2a88d520 fix nota 2025-09-15 22:52:55 -05:00
John Alanbrook
b5496d93bc refactor out duplicate and dead code 2025-08-08 14:40:59 -04:00
John Alanbrook
faf19db27e hud cursor coordinates 2025-08-04 21:29:33 -05:00
John Alanbrook
07595aad63 gpu backend uniform binding 2025-08-01 13:13:54 -05:00
John Alanbrook
8033c161d0 change pipelines 2025-08-01 06:35:25 -05:00
John Alanbrook
625503e654 ppu rendering 2025-08-01 05:46:33 -05:00
John Alanbrook
6a9a1a90dd add image conversion functions 2025-07-31 13:18:18 -05:00
John Alanbrook
ce5b4950d4 camera render to surface 2025-07-30 08:47:11 -05:00
John Alanbrook
cba6f4fd59 gpu renderer 2025-07-29 19:14:58 -05:00
John Alanbrook
e5c19e7e80 working gpu renderer 2025-07-29 15:15:18 -05:00
John Alanbrook
09c3d5cc4e sdl 3 gpu 2025-07-28 16:34:29 -05:00
John Alanbrook
5ae95aee01 render update 2025-07-27 17:08:29 -05:00
John Alanbrook
d5789598a0 clay screen res 2025-07-26 23:02:41 -05:00
John Alanbrook
8ffb4ec73a fix crash for mouse y inversion 2025-07-26 17:45:26 -05:00
John Alanbrook
fecc4b1285 tilemap clear 2025-07-25 14:29:59 -05:00
John Alanbrook
f82d924577 tween cancel 2025-07-23 23:33:25 -05:00
John Alanbrook
f389609bd9 improvements 2025-07-21 14:42:26 -05:00
John Alanbrook
ff7b2f4db7 add scale to draw2d image 2025-07-20 11:48:05 -05:00
John Alanbrook
8fb50a129f add gamepad type grabbing 2025-07-19 15:29:29 -05:00
John Alanbrook
b3c4b1fee9 tween timelines 2025-07-19 13:43:21 -05:00
John Alanbrook
bb3c2c34d0 add tween update callback 2025-07-19 07:52:41 -05:00
John Alanbrook
7fb0d9e80a fix sound destruction 2025-07-18 14:20:33 -05:00
John Alanbrook
f49d4180ed warning when compiled without profiling when attempting to enable 2025-07-18 06:31:11 -05:00
John Alanbrook
7bfd244bf2 add compile time configs for tracy, mimalloc and qrencode 2025-07-18 05:23:00 -05:00
John Alanbrook
881407a64f massively expand steam api 2025-07-17 20:28:47 -05:00
John Alanbrook
e677832b12 fix dmon leak; fix underlings not stopping when overling crashes 2025-07-17 16:32:22 -05:00
John Alanbrook
13c1e7560a empty text works 2025-07-16 20:18:50 -05:00
John Alanbrook
2e275adcd2 bug fix: graphics now correctly returns frames of single anims 2025-07-16 18:11:38 -05:00
John Alanbrook
2607604a0b play gifs with strings 2025-07-16 17:45:12 -05:00
John Alanbrook
d1d9a296a8 separate clay layout and clay input 2025-07-16 14:51:19 -05:00
John Alanbrook
7edbb85e4e clay id handling 2025-07-16 14:37:38 -05:00
John Alanbrook
874252db87 fix text menu render 2025-07-16 05:03:40 -05:00
John Alanbrook
13dd685f65 render layers 2025-07-15 20:33:55 -05:00
John Alanbrook
4b817b8d1b text drawing 2025-07-15 16:22:11 -05:00
John Alanbrook
09b78781e6 animations 2025-07-15 15:06:06 -05:00
John Alanbrook
19ce1008b1 emitter 2025-07-14 09:52:25 -05:00
John Alanbrook
d1c7ff768d prosperon module 2025-07-14 03:14:06 -05:00
John Alanbrook
0d97b47728 support for gamepad events 2025-07-12 22:38:18 -05:00
John Alanbrook
c87f85cf6c Update files for cross compilation fixes; add dockerfiles for windows/linux/emscripten builds; add commands to makefile to build via dockerfiles
Some checks failed
Build and Deploy / build-macos (push) Failing after 29s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-07-12 20:39:25 -05:00
John Alanbrook
f0afdfc7d9 add base64 and base64url encoder/decoders 2025-07-12 10:31:54 -05:00
John Alanbrook
ac9f40fd26 add set window size 2025-07-11 21:22:10 -05:00
John Alanbrook
39152c1eb2 fix base32 conversion/deconversion 2025-07-11 19:38:49 -05:00
John Alanbrook
6ff50cb521 add combo box to imgui 2025-07-11 14:11:34 -05:00
John Alanbrook
2b7b3985d5 tilemap render 2025-07-10 18:10:55 -05:00
John Alanbrook
a9b59750e3 fix mouse pos 2025-07-09 22:55:41 -05:00
John Alanbrook
525263a8a6 add imgui 2025-07-08 01:43:52 -05:00
John Alanbrook
310a0db99e fix draw 2025-07-07 18:51:18 -05:00
John Alanbrook
6e66bf59f6 input reports mod keys now 2025-07-07 15:26:45 -05:00
John Alanbrook
71c0056df4 layout uses x,y 2025-07-06 20:35:15 -05:00
John Alanbrook
d4f0059419 add benchmark and cell doc 2025-07-05 10:25:27 -05:00
John Alanbrook
d52d50fe61 fixes for gameplay 2025-07-05 10:24:09 -05:00
John Alanbrook
1bc34bb99c fix some rendering bug 2025-06-24 08:33:29 -05:00
John Alanbrook
8ac78e0be6 add layout 2025-06-23 22:58:25 -05:00
John Alanbrook
dca3ede464 add function disassembler 2025-06-23 21:28:15 -05:00
John Alanbrook
7b622d9788 initial attempt at adding IC 2025-06-23 17:20:39 -05:00
John Alanbrook
42087910ab remove proxy and many exotic methods 2025-06-23 15:32:05 -05:00
John Alanbrook
c581935fd8 add detail to cell.md 2025-06-23 10:21:33 -05:00
John Alanbrook
632b038561 remove last two master updates and remove proxy 2025-06-23 10:21:07 -05:00
John Alanbrook
6eb33b8e48 remove unneeded object properties and if 0 code 2025-06-19 08:46:40 -05:00
John Alanbrook
3d5f345236 all compilation is strict 2025-06-18 16:37:55 -05:00
John Alanbrook
4689ea1167 remove module eval branches 2025-06-18 14:10:51 -05:00
John Alanbrook
15d85096a2 remove global symbols 2025-06-18 14:03:12 -05:00
John Alanbrook
f2c2ecf692 remove all private stuff 2025-06-18 13:59:47 -05:00
John Alanbrook
458215f838 remove arguments object 2025-06-18 13:24:22 -05:00
John Alanbrook
7f002e306d remove reflect 2025-06-18 08:46:42 -05:00
John Alanbrook
91a3fef065 finish removing big int stuff; fixes memory leak 2025-06-17 21:36:06 -05:00
John Alanbrook
843b4bd8a8 remove usage of map 2025-06-17 21:16:35 -05:00
John Alanbrook
41fdf49df5 remove bigint 2025-06-17 15:02:40 -05:00
John Alanbrook
c9adbed3ff remove undefined; only use null now 2025-06-17 14:32:27 -05:00
John Alanbrook
3459d85a82 binary logic only works on ints; returns null otherwise 2025-06-17 12:54:20 -05:00
John Alanbrook
9ecdaae7a7 simpler addition rule 2025-06-16 20:40:41 -05:00
John Alanbrook
43b55b29f3 comparing anything but two numbers or two strings is an error 2025-06-16 18:45:57 -05:00
John Alanbrook
a88cee7fae Remove weak-everything. remove throwing on type differences in equality; remove using 'def' as some variable names 2025-06-16 17:02:24 -05:00
John Alanbrook
8b3f5476a9 remove module checks 2025-06-16 15:56:04 -05:00
John Alanbrook
233f59e04a clean up unused functions 2025-06-16 15:49:54 -05:00
John Alanbrook
7b16259c00 Merge branch 'js-rm-eq' into js-rm-modules 2025-06-16 14:20:23 -05:00
John Alanbrook
43baa23dfe Merge remote-tracking branch 'origin/js-rm-htmldda' into js-rm-modules 2025-06-16 14:18:40 -05:00
John Alanbrook
a9ebea9f26 Merge remote-tracking branch 'origin/js-def' into js-rm-modules 2025-06-16 14:16:01 -05:00
John Alanbrook
19b729afbf Merge remote-tracking branch 'origin/js-rm-with' into js-rm-modules 2025-06-16 14:09:29 -05:00
John Alanbrook
47729c225f Merge branch 'js-rm-ta' into js-rm-modules 2025-06-16 14:04:06 -05:00
John Alanbrook
ea6cf5db49 Merge remote-tracking branch 'origin/js-rm-class' into js-rm-modules 2025-06-16 14:01:12 -05:00
John Alanbrook
794baf8598 remove dynamic equality 2025-06-16 13:48:09 -05:00
John Alanbrook
a551368681 def now works as const 2025-06-16 08:07:45 -05:00
John Alanbrook
c20ca8c937 initial attempt 2025-06-15 19:48:48 -05:00
John Alanbrook
0217cf0da6 remove with 2025-06-15 19:40:58 -05:00
John Alanbrook
6bd7251933 initial rm 2025-06-15 10:30:58 -05:00
John Alanbrook
6dc8d97001 remove htmldda 2025-06-15 09:47:09 -05:00
John Alanbrook
9c0565d34f montecarlo faster; rm qjs-layout 2025-06-15 05:18:22 -05:00
John Alanbrook
0702e3495d finish remove? 2025-06-15 05:15:51 -05:00
John Alanbrook
108c39d22d initial attempt 2025-06-14 20:40:28 -05:00
John Alanbrook
946ebe5cd7 remove date intrinsic 2025-06-14 18:04:27 -05:00
John Alanbrook
fa12281ab9 add benchmarks 2025-06-14 17:03:49 -05:00
John Alanbrook
38a52fcb73 add tilemap 2025-06-13 20:48:33 -05:00
John Alanbrook
95a95e55e3 more details on cell 2025-06-13 20:42:53 -05:00
John Alanbrook
fc978a5766 add cell doc 2025-06-11 16:35:46 -05:00
John Alanbrook
9082ee2c47 move quickjs into source 2025-06-11 01:18:26 -05:00
John Alanbrook
b8ad8431f4 optimize 2025-06-11 01:13:58 -05:00
John Alanbrook
1c2b8228fe add num 2025-06-10 04:33:15 -05:00
John Alanbrook
a274fb174f faster text conversion to hex; guid generation now dealt with with -u.random_fit and blob formation; mersenne twister used for -u.random functions 2025-06-08 13:42:20 -05:00
John Alanbrook
3622a5ec58 actor messages now delivered as blobs 2025-06-08 11:06:59 -05:00
John Alanbrook
8a5f8a4d74 even faster wota encoding and decoding 2025-06-08 10:34:12 -05:00
John Alanbrook
c1d341eecd faster wota encoding 2025-06-08 08:35:12 -05:00
John Alanbrook
3176e6775d attempt for jswota in js 2025-06-08 00:49:19 -05:00
John Alanbrook
34dcd0a235 fix actors not running correctly 2025-06-07 23:35:47 -05:00
John Alanbrook
cbda7dfbc9 add utf8 and kim text encoder/decoders 2025-06-07 23:35:19 -05:00
John Alanbrook
d039e2cfe6 use spinlocks and other fixes 2025-06-07 17:09:03 -05:00
John Alanbrook
c02bd06ec0 signal kill works 2025-06-07 13:46:31 -05:00
John Alanbrook
efa63771e6 fix sockets 2025-06-07 12:24:34 -05:00
John Alanbrook
9f6d27fb3c fix multiple main thread actors not working 2025-06-06 21:26:29 -05:00
John Alanbrook
1a61ae6f77 actors keep running if they have messages, until no threads are available 2025-06-06 18:22:12 -05:00
John Alanbrook
83c816fd0e fix actors not freeing correctly if error in startup script 2025-06-06 17:42:28 -05:00
John Alanbrook
adbaa92dd5 fd now uses numbers to fix the inability to exit 2025-06-06 17:29:06 -05:00
John Alanbrook
580df9f233 add fstat; tests/cat as an example 2025-06-06 16:49:19 -05:00
John Alanbrook
d5d17560f9 add chunked reading; example with cat.ce 2025-06-06 16:15:39 -05:00
John Alanbrook
cd05ab97b5 Update agents directive 2025-06-06 14:59:30 -05:00
John Alanbrook
4eecbd692b fix actor not dying if killed while not in a turn 2025-06-06 13:59:14 -05:00
John Alanbrook
72beed7177 fix string leak with blob write_text 2025-06-06 13:58:46 -05:00
John Alanbrook
e0595de71a closes #19: kill underlings with system level interrupts 2025-06-06 12:24:32 -05:00
John Alanbrook
6687008d1a closes #14 2025-06-06 10:46:16 -05:00
John Alanbrook
5b9f1b8f51 closes #12 2025-06-06 10:31:41 -05:00
John Alanbrook
c570de7f41 closes #18: actor data now behind private symbol 2025-06-06 10:18:45 -05:00
John Alanbrook
d0138a6c23 ammend tests 2025-06-06 09:22:56 -05:00
John Alanbrook
29aa25e866 fix bug when calling unneeded inside of unneeded callback 2025-06-06 09:05:35 -05:00
John Alanbrook
ef28be93db fix js leak
Some checks failed
Build and Deploy / build-macos (push) Failing after 2s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-06-06 08:42:16 -05:00
John Alanbrook
0d7be6a94e attempt fix 2025-06-05 16:19:06 -05:00
John Alanbrook
4fe78c4a63 move timer to its own file 2025-06-05 13:34:50 -05:00
John Alanbrook
b52edb2746 fix updated render loop 2025-06-05 12:04:45 -05:00
John Alanbrook
79d5412fe6 massively simplify loop logic 2025-06-05 01:08:27 -05:00
John Alanbrook
fcec2cd1dc sockets and fd 2025-06-04 22:28:06 -05:00
John Alanbrook
2038ce15a7 factor out sdl input
Some checks failed
Build and Deploy / build-macos (push) Failing after 2s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-06-04 16:25:06 -05:00
John Alanbrook
08557011cb single threads; custom timer; letters
Some checks failed
Build and Deploy / build-macos (push) Failing after 2s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-06-04 14:39:58 -05:00
John Alanbrook
3e87bfd6cc add to look for same folder name as well as main
Some checks failed
Build and Deploy / build-macos (push) Failing after 2s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-06-04 13:22:58 -05:00
John Alanbrook
ef86dd3ecf remove some docstrings to save per actor memory 2025-06-03 23:58:44 -05:00
John Alanbrook
c887bcf7b9 no longer need to send ids to window renderer; per actor config 2025-06-03 16:13:54 -05:00
John Alanbrook
709f2459e4 add config options for ar timers 2025-06-03 14:33:51 -05:00
John Alanbrook
cdf8686c64 fix video start
Some checks failed
Build and Deploy / build-macos (push) Failing after 10s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-06-03 08:42:55 -05:00
John Alanbrook
2fdf74f6ee fix blob; throw on non stone reads; update blob test 2025-06-02 13:23:05 -05:00
John Alanbrook
e689679aac add checking for new mod versions 2025-06-02 12:12:05 -05:00
John Alanbrook
f70f65d1c3 add man files; add mod hash checking; add text decoding for blob 2025-06-02 11:10:18 -05:00
John Alanbrook
d9b316270d add text function 2025-06-02 10:35:30 -05:00
John Alanbrook
e2668b330e omit port when sending request if 80 or 443 2025-06-02 09:25:38 -05:00
John Alanbrook
90b5d1430f vendor qjs_miniz 2025-06-02 08:49:02 -05:00
John Alanbrook
7c47c43655 improve globfs performance 2025-06-02 08:48:49 -05:00
John Alanbrook
9e45219706 add clean command 2025-06-02 08:18:26 -05:00
John Alanbrook
d098800c88 fix path mounting 2025-06-02 08:18:08 -05:00
John Alanbrook
3a40076958 fix http; faster blob; list and help commands 2025-06-01 09:34:15 -05:00
John Alanbrook
06108df3d4 fix blob and http 2025-05-31 17:57:17 -05:00
John Alanbrook
a442cf5a4d update to new naming scheme 2025-05-31 16:45:56 -05:00
John Alanbrook
6dee29d213 Merge branch 'master' into modules 2025-05-31 15:58:06 -05:00
John Alanbrook
7711c644a0 congif from .cell/cell.toml
Some checks failed
Build and Deploy / build-macos (push) Failing after 10s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-31 15:55:24 -05:00
John Alanbrook
aab0a56349 fix routing 2025-05-31 15:32:30 -05:00
John Alanbrook
13245bbc98 register root actor 2025-05-31 09:02:53 -05:00
John Alanbrook
c25166d35a no more js leaking on free 2025-05-31 02:39:36 -05:00
John Alanbrook
fc09693c93 test program 2025-05-30 19:11:33 -05:00
John Alanbrook
b71c72db8b remove actors being created via cmd line args 2025-05-30 18:05:02 -05:00
John Alanbrook
66591e32b5 fixes #13: actor files can now be named use
Some checks failed
Build and Deploy / build-macos (push) Failing after 8s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-30 15:34:46 -05:00
John Alanbrook
fba05fa0fb update gitignore 2025-05-30 15:29:22 -05:00
John Alanbrook
11357d4fb5 actor files now .ce; module files now .cm; add toml encoder/decoder and test 2025-05-30 15:25:31 -05:00
John Alanbrook
674eb237e0 start of rename to cell 2025-05-30 12:07:03 -05:00
John Alanbrook
939269b060 initial modules attempt
Some checks failed
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-29 18:48:19 -05:00
John Alanbrook
f54200a7dd cwd works correctly for when running from a different folder
Some checks failed
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-29 17:59:33 -05:00
John Alanbrook
9ae2357493 new tracy build options 2025-05-29 14:11:47 -05:00
John Alanbrook
da525cd111 add compiling and saving bytecode 2025-05-29 13:55:03 -05:00
John Alanbrook
c3f07c0ef5 separate out cell stuff & prosperon stuff 2025-05-29 13:54:42 -05:00
John Alanbrook
2e7643aa2a add stone function 2025-05-29 11:28:51 -05:00
John Alanbrook
aca9baf585 add docstring symbol to C level actor 2025-05-29 10:29:57 -05:00
John Alanbrook
b4371ba3e0 improve time 2025-05-29 02:56:30 -05:00
John Alanbrook
4e118dd8e9 fix parseq and parseq test 2025-05-29 02:19:24 -05:00
John Alanbrook
9279e21b84 moth now filters events to the correct space 2025-05-29 01:21:45 -05:00
John Alanbrook
8d9bb4a2c9 use log instead of console 2025-05-29 00:39:14 -05:00
John Alanbrook
1040c61863 fix blob usage errors
Some checks failed
Build and Deploy / build-macos (push) Failing after 8s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-28 23:56:18 -05:00
John Alanbrook
e86bdf52fe switch to blobs from arraybuffers
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m29s
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-28 22:33:32 -05:00
John Alanbrook
53b3f0af9c fix mutex race
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m27s
Build and Deploy / build-macos (push) Failing after 8s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-28 18:50:39 -05:00
John Alanbrook
09f48d08b9 update chess to use moth
Some checks failed
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-28 17:49:37 -05:00
John Alanbrook
4eb592b740 moth handles camera now 2025-05-28 16:47:27 -05:00
John Alanbrook
c603e8f006 separate out blob and quickjs hooks into a blob.h header 2025-05-28 14:55:35 -05:00
John Alanbrook
f334a2ad56 expand qjs_blob 2025-05-28 14:38:43 -05:00
John Alanbrook
a39f287a88 remove prosperon.on and prosperon.dispatch 2025-05-28 13:51:58 -05:00
John Alanbrook
758b3e4704 remove tracy if not specified on cmd line 2025-05-28 13:16:08 -05:00
John Alanbrook
aa70dcbdc2 update 2025-05-28 02:28:20 -05:00
John Alanbrook
3667d53eae tracy is cell level now 2025-05-27 17:06:03 -05:00
John Alanbrook
01df337ccc draw2d now generates high level commands; turned into instructions by moth 2025-05-27 13:46:56 -05:00
John Alanbrook
ad182d68ec announce useful functions in qjs_common.h and remove externs 2025-05-27 10:23:07 -05:00
John Alanbrook
f7dcc8f57c correct pixelformat bug 2025-05-27 10:03:40 -05:00
John Alanbrook
f73f738459 add fd module 2025-05-27 01:52:27 -05:00
John Alanbrook
bf74a3c7d4 move keyboard and mouse functions that are main thread only to sdl_video
Some checks failed
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-27 01:30:50 -05:00
John Alanbrook
e8fb50659d add colorspace support; fix webcam 2025-05-27 01:00:55 -05:00
John Alanbrook
00df0899fa add nv12 pixel 2025-05-26 23:37:10 -05:00
John Alanbrook
ae5ba67fc8 surface pixel handling
Some checks failed
Build and Deploy / build-macos (push) Failing after 6s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-26 22:43:50 -05:00
John Alanbrook
bc929988b2 extend camera
Some checks failed
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-26 20:55:57 -05:00
John Alanbrook
2346040d46 matching actor2js function; sdl_video returns actor now 2025-05-26 18:00:42 -05:00
John Alanbrook
2eb6b3e0b4 input now contains function to register any actor to OS events 2025-05-26 17:56:43 -05:00
John Alanbrook
2edcd89780 add sdl cursor support 2025-05-26 16:24:19 -05:00
John Alanbrook
a63e5c5b55 move surface to its own module 2025-05-26 15:59:28 -05:00
John Alanbrook
af21e10e97 draw textures with draw2d
Some checks failed
Build and Deploy / build-macos (push) Failing after 6s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-26 13:25:56 -05:00
John Alanbrook
1b97527120 draw2d uses object prototype for command creation 2025-05-26 12:53:41 -05:00
John Alanbrook
8074e2a82e draw2d now can send batches of draws to video backends 2025-05-26 12:48:19 -05:00
John Alanbrook
db1afb6477 drop message sends if message has no return instead of throw error
Some checks failed
Build and Deploy / build-macos (push) Failing after 6s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-26 09:27:58 -05:00
John Alanbrook
45311408d6 render command ops 2025-05-26 00:57:29 -05:00
John Alanbrook
1141fca63a add window message handling for sdl actor 2025-05-25 22:47:35 -05:00
John Alanbrook
7b70def11f more full window object
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Waiting to run
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-linux (push) Failing after 1m27s
2025-05-25 21:55:21 -05:00
John Alanbrook
aac0c3813b window actor now created when use('sdl_video') is called 2025-05-25 19:06:24 -05:00
John Alanbrook
49786842f0 pull out sdl_video into its own module 2025-05-25 18:02:43 -05:00
John Alanbrook
9f9dfe03a6 removed internal functions from accessible via use
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-linux (push) Failing after 2m15s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-25 11:51:01 -05:00
John Alanbrook
792da2ce4b Merge remote-tracking branch 'origin/misty'
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-24 22:24:01 -05:00
John Alanbrook
0c9d78a3d3 initialize parts of SDL only when required, and return errors
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-24 21:30:29 -05:00
John Alanbrook
e929f43a96 add steam module 2025-05-24 21:29:58 -05:00
John Alanbrook
01eff40690 auto latest docker image
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Waiting to run
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-linux (push) Failing after 2m15s
2025-05-24 09:37:29 -05:00
John Alanbrook
23813a4c31 http downloading in chunks 2025-05-24 00:55:56 -05:00
John Alanbrook
1248b94244 remove curl and openssl dependencies
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Successful in 1m44s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-05-24 00:07:37 -05:00
John Alanbrook
f754d91e14 fix compilation errors on windows and linux
Some checks failed
Build and Deploy / build-macos (push) Failing after 4s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Failing after 1m59s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-05-23 18:24:52 -05:00
John Alanbrook
7246016b8b example nat 2025-05-23 14:23:52 -05:00
John Alanbrook
b42eec96f6 separate the idea of misty actor and scene tree actor
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Failing after 1m30s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-05-23 12:20:47 -05:00
John Alanbrook
efd98460c5 -u is no longer available as a global, only within the running actor code; enable passing args to use
Some checks failed
Build and Deploy / build-macos (push) Failing after 4s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-22 18:59:57 -05:00
John Alanbrook
698dbd81ae removed unneeded functions and split out actor specific functions 2025-05-22 18:16:51 -05:00
John Alanbrook
13c2a0ba0c sprites, rtrees, and transforms made with constructor functions 2025-05-22 17:00:31 -05:00
John Alanbrook
d0fdb469dd rtrees are now created as a constructor 2025-05-22 16:30:48 -05:00
John Alanbrook
32366483dc split out debug 2025-05-22 16:17:11 -05:00
John Alanbrook
707b2845b1 split out spline and js 2025-05-22 16:05:42 -05:00
John Alanbrook
693087afae move rtree to its own module 2025-05-22 15:42:45 -05:00
John Alanbrook
51940080a8 fully compiles 2025-05-22 13:23:13 -05:00
John Alanbrook
a204fce4b5 initial refactor
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-macos (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-22 11:48:27 -05:00
John Alanbrook
7bab2f1b7a clean up graphics
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m32s
Build and Deploy / build-macos (push) Failing after 7s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-22 01:28:03 -05:00
John Alanbrook
f5ee3aada6 fix portal connection
Some checks failed
Build and Deploy / build-macos (push) Failing after 4s
Build and Deploy / build-linux (push) Failing after 1m34s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-21 23:56:02 -05:00
John Alanbrook
449e25e0f3 fix non local host networking
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-macos (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-21 13:02:30 -05:00
John Alanbrook
3cbb95831c networked chess example
Some checks failed
Build and Deploy / build-macos (push) Failing after 4s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-21 12:25:17 -05:00
John Alanbrook
146baf1d23 networked chess 2025-05-21 10:34:33 -05:00
John Alanbrook
e7cc716590 initial moth
Some checks failed
Build and Deploy / build-macos (push) Failing after 10s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-19 09:01:17 -05:00
John Alanbrook
3aa2d549d1 add claude.md 2025-05-18 22:24:31 -05:00
John Alanbrook
901012064a add chess example
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-macos (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-18 08:57:34 -05:00
John Alanbrook
bf2336a172 add cwd command line arg 2025-05-18 08:56:25 -05:00
John Alanbrook
708a112449 add AGENTS.md and fix rect render
Some checks failed
Build and Deploy / build-macos (push) Failing after 9s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-17 23:06:42 -05:00
John Alanbrook
85ee724754 add texture mode for renderer
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-11 09:34:31 -05:00
John Alanbrook
ff2ee3d6db add animation test; help qr API
Some checks failed
Build and Deploy / build-macos (push) Failing after 5s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-09 12:57:54 -05:00
John Alanbrook
6bc04830d3 load image/texture from arraybuffer
Some checks failed
Build and Deploy / build-macos (push) Failing after 3s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-07 08:13:22 -05:00
John Alanbrook
589bb365bd http now returns byte array and content type
Some checks failed
Build and Deploy / build-macos (push) Failing after 4s
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-06 22:50:24 -05:00
John Alanbrook
0b8a43eb91 Merge branch 'https' into misty
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-macos (push) Failing after 3s
Build and Deploy / build-linux (push) Failing after 1m30s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-05-06 19:07:32 -05:00
John Alanbrook
bb3087dc37 fix qr code encoding to always be array buffers instead of strings 2025-05-06 18:53:08 -05:00
John Alanbrook
92f56570d9 fix qr decoding 2025-05-06 12:48:13 -05:00
John Alanbrook
938da0d4dc Use thin lto for release builds; move 'strip' to meson.build for release
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Successful in 1m44s
Build and Deploy / build-macos (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-05-05 13:55:09 -05:00
John Alanbrook
3d94859151 macos build
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-macos (push) Failing after 1m46s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-05-04 17:50:03 -05:00
John Alanbrook
a85b1873dd sprite rework
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-04 11:28:45 -05:00
John Alanbrook
446ad080e1 render sprite geometry 2025-05-02 11:18:13 -05:00
John Alanbrook
ead61e648a changes to update to newer quickjs version
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-05-01 12:50:03 -05:00
John Alanbrook
600fbfd3b7 fast sprite render
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-05-01 01:35:05 -05:00
John Alanbrook
f3031d6cd0 add bcrypt as windows dependency
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-04-30 14:09:11 -05:00
John Alanbrook
7152ae093e audio working from soloud -> sdl3
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-29 12:43:25 -05:00
John Alanbrook
2bd93ff9e0 closer to web build 2025-04-29 12:43:17 -05:00
John Alanbrook
f68e45f898 sdl audio
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-04-28 08:48:44 -05:00
John Alanbrook
7eca07c7d1 fix actor delay time always being 0 2025-04-26 09:42:23 -05:00
John Alanbrook
ee4ec2fc39 fix draw.image
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-26 08:08:15 -05:00
John Alanbrook
b93a5a3ac0 refactor draw2d and render
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-04-25 17:56:17 -05:00
John Alanbrook
de63e0e52d round rect and rounded filled rect
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-04-24 14:04:27 -05:00
John Alanbrook
daef2fd2f2 circle and elipse
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-04-24 09:19:56 -05:00
John Alanbrook
6705ce8980 sdl renderer
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-23 20:39:07 -05:00
John Alanbrook
f443816355 render
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-22 11:18:21 -05:00
John Alanbrook
c8c08d5fbe renderer now has camera matrix
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-21 09:23:50 -05:00
John Alanbrook
b8328657df add camera test
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-04-14 22:46:07 -05:00
John Alanbrook
8d235ddf12 add cycle detection with use 2025-04-14 18:01:41 -05:00
John Alanbrook
05f284e3fa remove unnecessary functions
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-14 09:05:49 -05:00
John Alanbrook
566baa250c sdl renderer
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
'
2025-04-13 21:32:34 -05:00
John Alanbrook
19a8bd41a9 update sdl3
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-04-03 13:12:57 -05:00
John Alanbrook
58cad839b6 fix crash
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m15s
Build and Deploy / build-windows (CLANG64) (push) Failing after 15m44s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-03-28 14:44:57 -05:00
John Alanbrook
34035ae6ac sdl renderer backend
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-03-28 12:29:15 -05:00
John Alanbrook
3a4547fb80 add blob; pull out crypto, time; add sdl_renderer
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-03-27 14:31:02 -05:00
John Alanbrook
86b21bb6dd inital parseq add
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-03-26 09:42:50 -05:00
John Alanbrook
8cf114cbb4 io actor
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-03-23 04:46:16 -05:00
John Alanbrook
f9100da8a2 -u.unneeded 2025-03-22 22:27:36 -05:00
John Alanbrook
f9c1a3e71a root actor runs only on main thread; restrict ffi main thread functions to it 2025-03-22 20:55:20 -05:00
John Alanbrook
73594c8599 fix memory leaking and thread sync problems 2025-03-22 18:24:18 -05:00
John Alanbrook
239f35389e fix crashing assert on free
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-03-22 11:15:40 -05:00
John Alanbrook
95d3296dd9 wota now encodes at the C level; update dmon for macos 13; clean up many warnings
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m15s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-03-20 17:25:48 -05:00
John Alanbrook
c566f90d16 remove script
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-03-19 17:52:44 -05:00
John Alanbrook
9410af3a69 messages
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m17s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-19 12:40:31 -05:00
John Alanbrook
8627fc52ef actors in C now
Some checks failed
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Successful in 1m15s
Build and Deploy / build-windows (CLANG64) (push) Failing after 11m46s
2025-03-18 18:18:56 -05:00
John Alanbrook
813cc8dbbc make tracy work for multilpe contexts
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-03-15 20:49:53 -05:00
John Alanbrook
d90d81d7ff fixed memory leak on thread exit
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m16s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-15 08:33:37 -05:00
John Alanbrook
b1f62cc58c destroy mailboxes on thread exit
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m42s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m57s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-03-13 17:29:42 -05:00
John Alanbrook
38da997069 use wota for on machine message passing 2025-03-13 17:20:04 -05:00
John Alanbrook
88d5f6455b portal spawning works 2025-03-13 15:21:11 -05:00
John Alanbrook
eb3a41be69 add wota replacer and reviver 2025-03-13 15:21:01 -05:00
John Alanbrook
1332af93ab enet and mailboxes now take strings or array buffers
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m3s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-13 06:28:00 -05:00
John Alanbrook
93adf50498 add nota replacer and reviver options; don't serialize functions 2025-03-13 06:25:15 -05:00
John Alanbrook
291fd9ead0 hide actor data
Some checks failed
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Successful in 1m16s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m57s
2025-03-12 23:09:43 -05:00
John Alanbrook
e86138ec00 multirheading mailboxes fixed
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m20s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m58s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
2025-03-11 20:34:39 -05:00
John Alanbrook
c431f117e9 remove atoms for multithreading
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m42s
Build and Deploy / build-windows (CLANG64) (push) Failing after 6m13s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-11 10:13:15 -05:00
John Alanbrook
847a3ef314 threading
Some checks failed
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Failing after 55s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m50s
2025-03-10 22:49:48 -05:00
John Alanbrook
bab09fed6d add documentation
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m22s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m30s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-09 21:53:25 -05:00
John Alanbrook
d56c983e01 add return to callback send 2025-03-09 10:18:43 -05:00
John Alanbrook
69df7302d5 initial attempt at portal and contact
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 9m19s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-06 21:18:05 -06:00
John Alanbrook
01f7e715a4 parent child handshake
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m45s
Build and Deploy / build-windows (CLANG64) (push) Failing after 8m5s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-06 11:31:37 -06:00
John Alanbrook
e71a823848 add actor clock, random, unneeded
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m45s
Build and Deploy / build-windows (CLANG64) (push) Failing after 9m53s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-05 22:34:08 -06:00
John Alanbrook
a8865594ca coupling
Some checks failed
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Successful in 1m13s
Build and Deploy / build-windows (CLANG64) (push) Failing after 14m3s
2025-03-05 13:03:44 -06:00
John Alanbrook
23d764c534 actor detection
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m42s
Build and Deploy / build-windows (CLANG64) (push) Failing after 8m47s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-05 09:01:29 -06:00
John Alanbrook
c7aee73dcb initial misty implementation
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m41s
Build and Deploy / build-windows (CLANG64) (push) Failing after 10m50s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-04 22:46:10 -06:00
John Alanbrook
925d1fc437 fix various graphics and sound issues
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Failing after 9m56s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-04 22:43:19 -06:00
John Alanbrook
a6dbedb3cd add nota benchmark; builds no longer continue on test fail 2025-03-04 22:41:51 -06:00
John Alanbrook
74a6b9bfe6 Add versioning dropdown to docs 2025-03-04 22:41:51 -06:00
John Alanbrook
40126060fb dramatically improve nota speed for nested arrays and objects
Some checks are pending
Build and Deploy / build-windows (CLANG64) (push) Waiting to run
Build and Deploy / package-dist (push) Blocked by required conditions
Build and Deploy / deploy-itch (push) Blocked by required conditions
Build and Deploy / deploy-gitea (push) Blocked by required conditions
Build and Deploy / build-linux (push) Successful in 1m19s
2025-03-03 18:35:46 -06:00
John Alanbrook
6032c034bc add wota 2025-03-03 18:35:28 -06:00
John Alanbrook
6b4062eee6 add http get
Some checks failed
Build and Deploy / build-linux (push) Failing after 1m3s
Build and Deploy / build-windows (CLANG64) (push) Successful in 9m45s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-03 08:07:16 -06:00
John Alanbrook
0ea21e86eb add qr code encode and decode
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m15s
Build and Deploy / build-windows (CLANG64) (push) Successful in 9m2s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-03-03 08:06:18 -06:00
John Alanbrook
30c5da879b fix various graphics and sound issues 2025-02-27 16:51:48 -06:00
John Alanbrook
1a76081fec add nota benchmark; builds no longer continue on test fail 2025-02-26 11:16:35 -06:00
John Alanbrook
045c4b49ef Add versioning dropdown to docs 2025-02-25 10:14:17 -06:00
John Alanbrook
af0996f6ab nota write decimal numbers via a string in the qjs_nota implementation, solving windows fp error
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Successful in 10m2s
Build and Deploy / package-dist (push) Successful in 8s
Build and Deploy / deploy-gitea (push) Successful in 5s
Build and Deploy / deploy-itch (push) Successful in 9s
2025-02-24 23:15:58 -06:00
John Alanbrook
6c390aeae3 add documentation for dmon, enet, and nota.
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m11s
Build and Deploy / build-windows (CLANG64) (push) Successful in 13m30s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-24 19:04:16 -06:00
John Alanbrook
e9519484cc fix enet; add enet testing
Some checks failed
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
2025-02-24 13:43:01 -06:00
John Alanbrook
b7da920f31 add qjs_soloud to source tree 2025-02-24 13:37:02 -06:00
John Alanbrook
35647a5c5b Minor nota speed improvement; use nota growable array internally so no more fixed size
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m15s
Build and Deploy / build-windows (CLANG64) (push) Successful in 14m57s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-24 11:25:12 -06:00
John Alanbrook
8ea8f7fec7 Add qjs_enet into prosperon source 2025-02-24 11:15:22 -06:00
John Alanbrook
5254b84704 fixed nota encoding/decoding bug with arrays longer than 126 elements 2025-02-23 17:16:00 -06:00
John Alanbrook
f728a217c9 add dmon doc; dmon now dispatches via prosperon.on 2025-02-23 17:15:35 -06:00
John Alanbrook
c27817b73a dmon now only watches top level directory; user must call dmon.watch and supply a dmon watch function
Some checks failed
Build and Deploy / build-linux (push) Successful in 1m7s
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-02-23 16:07:09 -06:00
John Alanbrook
7ea79c8ced Fix nota implementation; add nota test suite 2025-02-23 16:06:40 -06:00
John Alanbrook
fb10c63882 add dmon and nota into source tree, out of subprojects; build on macos
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m9s
Build and Deploy / build-windows (CLANG64) (push) Successful in 33m33s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-23 08:49:49 -06:00
John Alanbrook
96ef8ccba3 Add camera and debug modules
Some checks failed
Build and Deploy / package-dist (push) Has been cancelled
Build and Deploy / deploy-itch (push) Has been cancelled
Build and Deploy / deploy-gitea (push) Has been cancelled
Build and Deploy / build-linux (push) Has been cancelled
Build and Deploy / build-windows (CLANG64) (push) Has been cancelled
2025-02-21 17:15:58 -06:00
John Alanbrook
6148f18340 CLI version ends with a newline 2025-02-21 16:55:45 -06:00
John Alanbrook
867a18e788 Project cleanup. Update stb libraries. Remove unused files. Enable pedantic warning flag and fix all warnings. Fill out spline file. 2025-02-21 16:38:59 -06:00
John Alanbrook
387c4364b5 SDL3 built as a static library as part of build process
All checks were successful
Build and Deploy / build-linux (push) Successful in 1m12s
Build and Deploy / build-windows (CLANG64) (push) Successful in 14m52s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-21 11:48:28 -06:00
John Alanbrook
60dce4a08f imgui is always compiled in, and developer selects to enable or disable its drawing; fix bug with rendering lines that caused prosperon to crash
All checks were successful
Build and Deploy / build-linux (push) Successful in 34s
Build and Deploy / build-windows (CLANG64) (push) Successful in 9m15s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-20 17:28:27 -06:00
John Alanbrook
d2325c20bd Add MSYS2 CI
All checks were successful
Build and Deploy / build-linux (push) Successful in 36s
Build and Deploy / build-windows (CLANG64) (push) Successful in 6m12s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-20 14:31:28 -06:00
John Alanbrook
29295607df Update build action for more useful distribution
All checks were successful
Build and Deploy / build-linux (push) Successful in 41s
Build and Deploy / build-windows (push) Successful in 47s
Build and Deploy / package-dist (push) Has been skipped
Build and Deploy / deploy-itch (push) Has been skipped
Build and Deploy / deploy-gitea (push) Has been skipped
2025-02-19 16:50:25 -06:00
John Alanbrook
dcd767e5f9 all files now have an implicit empty actor, even if there is no actor statement present
All checks were successful
Build / build-linux (push) Successful in 39s
Build / build-linux (release) Successful in 41s
Build / build-windows (release) Successful in 41s
Build / package-dist (release) Successful in 12s
Build / build-windows (push) Successful in 43s
Build / package-dist (push) Has been skipped
2025-02-18 22:44:44 -06:00
John Alanbrook
bff39b0e9f all files now have an implicit empty actor, even if there is no actor statement present
All checks were successful
Build / build-windows (push) Successful in 35s
Build / build-linux (push) Successful in 40s
Build / package-dist (push) Has been skipped
2025-02-18 19:38:24 -06:00
John Alanbrook
1ae73aed06 add testing
Some checks failed
Build / build-windows (push) Successful in 34s
Build / build-linux (push) Failing after 38s
Build / package-dist (push) Has been skipped
2025-02-18 16:55:10 -06:00
John Alanbrook
75c7e304de fix setting console documentation 2025-02-17 21:10:08 -06:00
John Alanbrook
8169e1df34 Fix unable to spawn actors after initialization 2025-02-17 15:37:05 -06:00
John Alanbrook
f10b14afb3 Fix bug by setting default camera configuration before initialization
Set default width and height if none are provided in config.js. This
prevents camera initialization errors when the values are missing.
2025-02-17 15:03:43 -06:00
John Alanbrook
7bafa906cc using containers
All checks were successful
Build / build-linux (push) Successful in 1m2s
Build / build-windows (push) Successful in 1m4s
Build / package-dist (push) Has been skipped
2025-02-17 10:09:43 -06:00
John Alanbrook
8ced43c389 Merge branch 'master' of https://gitea.pockle.world/john/prosperon
Some checks failed
CI / build-package-windows (push) Failing after 1s
CI / build-test-linux (push) Failing after 3s
Build / build-windows (push) Successful in 1m16s
Build / build-linux (push) Successful in 1m26s
Build / package-dist (push) Successful in 6s
2025-02-17 08:12:42 -06:00
John Alanbrook
479ba8f742 revising build
Some checks failed
CI / build-package-windows (push) Failing after 1s
CI / build-test-linux (push) Failing after 3s
2025-02-17 08:06:05 -06:00
John Alanbrook
9badc3bb64 update readme and mkdocs favicon
All checks were successful
CI / build-test-linux (push) Successful in 1m40s
CI / build-package-windows (push) Successful in 1m46s
2025-02-16 23:25:25 -06:00
John Alanbrook
f689c551a5 update readme and mkdocs favicon 2025-02-15 10:05:53 -06:00
John Alanbrook
678a66064b update readme and mkdocs favicon 2025-02-12 19:51:33 -06:00
John Alanbrook
e6cfd88e58 Merge remote-tracking branch 'refs/remotes/origin/master'
Some checks failed
Build / package-dist (push) Has been cancelled
Build / build-macos (push) Waiting to run
Build / build-windows (push) Waiting to run
Build / build-linux (push) Has been cancelled
2025-02-12 17:11:40 -06:00
John Alanbrook
93d5e19302 github build action 2025-02-12 08:50:06 -06:00
John Alanbrook
ae8fcb7157 update docs 2025-02-11 20:44:17 -06:00
John Alanbrook
c25c52faa0 rework guide documentation 2025-02-11 00:18:29 -06:00
John Alanbrook
375a6ad3a4 add core docs 2025-02-10 09:48:59 -06:00
John Alanbrook
7283ced1ca update api documentation index and sort 2025-02-09 13:20:46 -06:00
John Alanbrook
7cffdab28a document c types 2025-02-09 00:07:01 -06:00
John Alanbrook
95c64f51de reorganize api doc 2025-02-08 20:50:25 -06:00
John Alanbrook
4361ad9daa tutorial documentation 2025-02-08 17:09:34 -06:00
John Alanbrook
c389e0744a heavy overhaul of documentation organizaton 2025-02-08 01:45:51 -06:00
John Alanbrook
81b42eec67 update documentation 2025-02-07 23:54:30 -06:00
John Alanbrook
7e098d5869 add js debug functions;remove tracy to hooks 2025-02-06 22:41:52 -06:00
John Alanbrook
499d2d6e63 bunnymark 2025-02-06 11:07:03 -06:00
John Alanbrook
cd6661d239 add input get mouse state; remove various array extensions 2025-02-06 11:05:39 -06:00
John Alanbrook
f472e0bd02 move tracy from quickjs 2025-02-06 09:10:54 -06:00
John Alanbrook
8bd7dd00c7 c type documentation 2025-02-05 17:16:05 -06:00
John Alanbrook
f53e46ee9e documentation update 2025-02-04 22:18:46 -06:00
John Alanbrook
b41f00458b add pong, snake, and tetris examples 2025-02-04 07:38:43 -06:00
John Alanbrook
5e7c946d43 documentation writing and API doc update 2025-02-04 07:37:10 -06:00
John Alanbrook
ede899e9a3 fix camera ortho set to true; fix module loading; remove loop function to loop.js 2025-02-03 17:08:07 -06:00
John Alanbrook
68ccd63ddc shrink core.zip by removing unneeded icons 2025-02-03 08:16:26 -06:00
John Alanbrook
d4d3867b5f pipeline only in render.js 2025-02-02 12:06:43 -06:00
John Alanbrook
14feeb0c16 core.zip is now bundled into prosperon executables 2025-02-01 21:16:38 -06:00
John Alanbrook
8a41899c5d separate input and events; pull camera out of render 2025-01-30 20:25:12 -06:00
John Alanbrook
b8857031f4 move extra modules to modules folder; pull drawing functions into draw2d 2025-01-29 11:53:18 -06:00
John Alanbrook
b561217073 merge math functions 2025-01-28 22:41:00 -06:00
John Alanbrook
9982dadd58 remove half assed code 2025-01-28 16:42:31 -06:00
John Alanbrook
f5d6c071bf doc.js; clean up index 2025-01-28 15:09:37 -06:00
John Alanbrook
e6aac69358 static link physfs 2025-01-28 11:16:00 -06:00
John Alanbrook
de1c9a1485 github workflow 2025-01-27 15:22:29 -06:00
John Alanbrook
56fc25d27d add prosperon use 2025-01-27 15:13:02 -06:00
John Alanbrook
0a69bb96ba fix resource loading 2025-01-25 17:15:25 -06:00
John Alanbrook
612111067b fix emitter 2025-01-24 00:04:55 -06:00
John Alanbrook
d174aa88d6 improve spawn callback; more robust deletion of actors 2025-01-23 15:27:40 -06:00
John Alanbrook
9e6f5e7eb1 pull out many files into separate uses 2025-01-22 17:49:15 -06:00
John Alanbrook
3d7ea7d358 refactor 2025-01-21 16:46:18 -06:00
John Alanbrook
e628256f44 fix actor deletion 2025-01-19 17:20:06 -06:00
John Alanbrook
8a063850a5 sprite 2025-01-19 14:28:23 -06:00
John Alanbrook
8e95fd2355 module misty 2025-01-19 14:28:09 -06:00
John Alanbrook
b4d1277a9d module and program separation 2025-01-18 22:35:54 -06:00
John Alanbrook
a142b6d1f4 actor cleanup 2025-01-18 18:15:15 -06:00
John Alanbrook
aa38fd2c19 test 2025-01-17 16:18:40 -06:00
John Alanbrook
406c7ea590 add uncaught exception handling 2025-01-17 10:44:33 -06:00
John Alanbrook
bae3a94fa1 fixes 2025-01-16 21:02:14 -06:00
John Alanbrook
545e7ccd6c faster sprite render path 2025-01-15 23:53:17 -06:00
John Alanbrook
96096adbc7 in C sprites; transform parent child hooks 2025-01-15 15:18:58 -06:00
John Alanbrook
a24d4da3c2 transform handling 2025-01-15 10:09:35 -06:00
John Alanbrook
aec3656b76 clean up jsffi 2025-01-15 05:38:41 -06:00
John Alanbrook
3f3d2e6b57 remove Quadtree and IntList 2025-01-14 18:18:56 -06:00
John Alanbrook
9ad22df21d quadtrees, rtrees 2025-01-14 18:10:18 -06:00
John Alanbrook
28f0b5478b fast sprite rendering with quadtrees 2025-01-14 13:53:49 -06:00
John Alanbrook
d8cad40c50 add quadtree; add neon to handmademath 2025-01-14 09:36:09 -06:00
John Alanbrook
04273b3d43 optimize makeing sprite queue 2025-01-13 22:11:56 -06:00
John Alanbrook
9a2e897464 fast sprite render 2025-01-13 20:12:59 -06:00
John Alanbrook
dab13a1f54 improve sprite render speed; particle rendering 2025-01-13 15:35:04 -06:00
John Alanbrook
653748363f tile options for slice9 and tile 2025-01-12 14:42:54 -06:00
John Alanbrook
5feacca44c tween callback 2025-01-12 11:56:10 -06:00
John Alanbrook
4524bd4f84 fix 9 slice; add tile command 2025-01-12 10:15:01 -06:00
John Alanbrook
a7f7015212 9 slice 2025-01-12 07:52:13 -06:00
John Alanbrook
58cf983e5e fix texture color issue on macos 2025-01-11 21:07:48 -06:00
John Alanbrook
034ef8ac94 circle shader 2025-01-11 16:43:17 -06:00
John Alanbrook
4753ef3a9b fix render 2025-01-10 20:08:40 -06:00
John Alanbrook
a76b8725cd fix ps1 shader 2025-01-09 23:20:18 -06:00
John Alanbrook
4a7543fa68 rectangle shading 2025-01-09 19:31:08 -06:00
John Alanbrook
b698b1862e shaders cleanup; add imgui sdl3 gpu support 2025-01-09 13:23:18 -06:00
John Alanbrook
0153cfbb68 add sprite 2025-01-08 22:01:41 -06:00
John Alanbrook
293eb509da text rendering 2025-01-08 17:54:25 -06:00
John Alanbrook
9d5243e9c3 fix loop leak 2025-01-08 07:44:10 -06:00
John Alanbrook
996691d66f sdl compute 2025-01-07 20:22:06 -06:00
John Alanbrook
854e3b4c24 sdl gpu wrap 2025-01-07 09:30:01 -06:00
John Alanbrook
cd9bafd1c1 remove assimp dependency 2025-01-06 12:26:58 -06:00
John Alanbrook
246ef7a566 make work on macos 2025-01-06 09:01:09 -06:00
John Alanbrook
d94f9eab59 ops 2025-01-05 16:11:31 -06:00
John Alanbrook
4914af8a45 more sdl gpu work 2024-12-28 17:01:53 -06:00
John Alanbrook
78fb926a5e post shader 2024-12-27 14:08:26 -06:00
John Alanbrook
a0b610d93f shaders 2024-12-24 09:48:52 -06:00
John Alanbrook
f3f0777de6 3d gpu 2024-12-18 15:39:43 -06:00
John Alanbrook
869a4fa999 sdl gpu 2024-12-14 13:25:35 -06:00
John Alanbrook
27ce4cd9e2 windows build 2024-12-13 14:35:46 -06:00
John Alanbrook
ecbab2a2e4 add imgui to editor 2024-12-12 00:50:23 -06:00
John Alanbrook
42cfccfc33 sdl 2024-12-09 16:00:10 -06:00
John Alanbrook
a5b0088695 imrpove cv 2024-12-07 13:55:54 -06:00
John Alanbrook
ac9fd39cf4 use colorf 2024-12-05 12:00:12 -06:00
John Alanbrook
ae39e60095 fix videos, gifs, aseprite 2024-12-04 09:08:44 -06:00
John Alanbrook
92e07b3018 cv 2024-12-03 22:33:30 -06:00
John Alanbrook
edc29cc28c fix layout 2024-12-02 12:57:19 -06:00
John Alanbrook
5e1d37c2b8 remove opengl files; macos cblas 2024-12-02 08:04:12 -06:00
John Alanbrook
166bc48c6b add physfs wrap 2024-12-01 11:23:30 -06:00
John Alanbrook
7748ce521d add surface functions 2024-12-01 11:23:11 -06:00
John Alanbrook
48904b10f0 remove sokol, use sdl3 2024-11-30 12:12:13 -06:00
John Alanbrook
dbb1bf0630 remove centered quad 2024-11-21 18:33:40 -06:00
John Alanbrook
94d0a086c6 massively improve rectangle render time 2024-11-20 14:23:07 -06:00
John Alanbrook
8313a2d33e qjs tracy d3d11 2024-11-20 05:54:09 -06:00
John Alanbrook
cac380e673 glob 2024-11-18 15:55:52 -06:00
John Alanbrook
222e9035c3 faster file handling on windows 2024-11-18 12:31:12 -06:00
John Alanbrook
069c860ae1 tracy 2024-11-17 11:34:35 -06:00
John Alanbrook
0d12002677 add tracy as profiler 2024-11-15 03:00:22 -06:00
John Alanbrook
ce8e553fec add parseq 2024-11-12 23:50:32 -06:00
John Alanbrook
8f983c2b43 refactor; remove many unnecessary files and normalize data ingestion as buffer arrays 2024-11-12 09:12:51 -06:00
John Alanbrook
ba9b1c1c9e rework hot reload 2024-11-09 22:19:37 -06:00
John Alanbrook
be453fdad1 add qjs-dmon wrap 2024-11-09 13:52:39 -06:00
John Alanbrook
d05948be47 offload miniz to quickjs; simplify resources.c so it no longer handles the core db; refactor making textures to use arraybuffers 2024-11-09 13:51:43 -06:00
John Alanbrook
140c61ab9b quicker ls 2024-11-09 07:32:51 -06:00
John Alanbrook
005730938c use zo instead of no so it works across platforms 2024-11-07 17:08:06 -06:00
John Alanbrook
03b4f9b52e particles render without texture filter 2024-11-07 16:24:07 -06:00
John Alanbrook
413812b249 simplify input handling 2024-11-07 10:05:36 -06:00
John Alanbrook
7563cb5d38 restore y axis sprite sort 2024-11-07 03:22:43 -06:00
John Alanbrook
6faa05fc62 fix sprite render 2024-11-06 16:22:23 -06:00
John Alanbrook
b1fb260366 no more scripts subdir 2024-11-05 15:55:18 -06:00
John Alanbrook
75c93b4cf9 remove engine dir 2024-11-05 14:42:21 -06:00
John Alanbrook
a92f34db71 remove globcore.sh 2024-11-05 13:17:16 -06:00
859 changed files with 218256 additions and 259095 deletions

View File

@@ -1,9 +1,20 @@
BasedOnStyle: GNU
Language: C
IndentWidth: 2
TabWidth: 2
UseTab: Never
ContinuationIndentWidth: 2 # Indents continuation lines by 2 spaces
ContinuationIndentWidth: 2
AllowShortFunctionsOnASingleLine: true
AllowShortBlocksOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
BreakBeforeBraces: Attach
ColumnLimit: 0
BreakFunctionDefinitionParameters: false
BinPackParameters: false
BinPackArguments: false
# --- Fix the "static T\nname(...)" style ---
AlwaysBreakAfterDefinitionReturnType: None
BreakAfterReturnType: None

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.mach binary merge=ours

25
.gitignore vendored
View File

@@ -1,30 +1,33 @@
.git/
.obj/
website/public/
website/.hugo_build.lock
bin/
build/
*.zip
*.o
*.a
*.d
tags
Jenkinsfile
*~
*.log
*.gz
*.tar
.nova/
packer*
primum
sokol-shdc*
source/shaders/*.h
core.cdb
primum.exe
core.cdb.h
jsc
.DS_Store
*.html
!website/themes/**/*.html
.vscode
*.icns
game.zip
icon.ico
steam/
steam/
subprojects/*/
build_dbg/
modules/
sdk/
artifacts/
discord_social_sdk/
discord_partner_sdk/
steam_api64.dll
subprojects/.wraplock
.gemini

141
CLAUDE.md Normal file
View File

@@ -0,0 +1,141 @@
# ƿit (pit) Language Project
## Building
Recompile after changes: `make`
Bootstrap from scratch (first time): `make bootstrap`
Run `cell --help` to see all CLI flags.
## Code Style
All code uses 2 spaces for indentation. K&R style for C and Javascript.
## ƿit Script Quick Reference
ƿit script files: `.ce` (actors) and `.cm` (modules). The syntax is similar to JavaScript with important differences listed below.
### Key Differences from JavaScript
- `var` (mutable) and `def` (constant) — no `let` or `const`
- `==` and `!=` are strict (no `===` or `!==`)
- No `undefined` — only `null`
- No classes — only objects and prototypes (`meme()`, `proto()`, `isa()`)
- No `for...in`, `for...of`, spread (`...`), rest params, or default params
- No named function declarations — use `var fn = function() {}` or arrow functions
- Variables must be declared at function body level only (not in if/while/for/blocks)
- All variables must be initialized at declaration (`var x` alone is an error; use `var x = null`)
- No `try`/`catch`/`throw` — use `disrupt`/`disruption`
- No arraybuffers — only `blob` (works with bits; must `stone(blob)` before reading)
- Identifiers can contain `?` and `!` (e.g., `nil?`, `set!`, `is?valid`)
- Prefer backticks for string interpolation; otherwise use `text()` to convert non-strings
- Everything should be lowercase
### Intrinsic Functions (always available, no `use()` needed)
The creator functions are **polymorphic** — behavior depends on argument types:
- `array(number)` — create array of size N filled with null
- `array(number, value_or_fn)` — create array with initial values
- `array(array)` — copy array
- `array(array, fn)` — map
- `array(array, array)` — concatenate
- `array(array, from, to)` — slice
- `array(record)` — get keys as array of text
- **`array(text)` — split text into individual characters** (e.g., `array("hello")``["h","e","l","l","o"]`)
- `array(text, separator)` — split by separator
- `array(text, length)` — split into chunks of length
- `text(array, separator)` — join array into text
- `text(number)` or `text(number, radix)` — number to text
- `text(text, from, to)` — substring
- `number(text)` or `number(text, radix)` — parse text to number
- `number(logical)` — boolean to number
- `record(record)` — copy
- `record(record, another)` — merge
- `record(array_of_keys)` — create record from keys
Other key intrinsics: `length()`, `stone()`, `is_stone()`, `print()`, `filter()`, `find()`, `reduce()`, `sort()`, `reverse()`, `some()`, `every()`, `starts_with()`, `ends_with()`, `meme()`, `proto()`, `isa()`, `splat()`, `apply()`, `extract()`, `replace()`, `search()`, `format()`, `lower()`, `upper()`, `trim()`
Sensory functions: `is_array()`, `is_text()`, `is_number()`, `is_object()`, `is_function()`, `is_null()`, `is_logical()`, `is_integer()`, `is_stone()`, etc.
### Standard Library (loaded with `use()`)
- `blob` — binary data (bits, not bytes)
- `time` — time constants and conversions
- `math` — trig, logarithms, roots (`math/radians`, `math/turns`)
- `json` — JSON encoding/decoding
- `random` — random number generation
### Actor Model
- `.ce` files are actors (independent execution units, don't return values)
- `.cm` files are modules (return a value, cached and frozen)
- Actors never share memory; communicate via `$send()` message passing
- Actor intrinsics start with `$`: `$me`, `$stop()`, `$send()`, `$start()`, `$delay()`, `$receiver()`, `$clock()`, `$portal()`, `$contact()`, `$couple()`, `$unneeded()`, `$connection()`, `$time_limit()`
### Requestors (async composition)
`sequence()`, `parallel()`, `race()`, `fallback()` — compose asynchronous operations. See docs/requestors.md.
### Error Handling
```javascript
var fn = function() {
disrupt // bare keyword, no value
} disruption {
// handle error; can re-raise with disrupt
}
```
### Push/Pop Syntax
```javascript
var a = [1, 2]
a[] = 3 // push: [1, 2, 3]
var v = a[] // pop: v is 3, a is [1, 2]
```
## C Integration
- Declare everything `static` that can be
- Most files don't have headers; files in a package are not shared between packages
- No undefined in C API: use `JS_IsNull` and `JS_NULL` only
- A C file with correct macros (`CELL_USE_FUNCS` etc) is loaded as a module by its name (e.g., `png.c` in a package → `use('<package>/png')`)
- C symbol naming: `js_<pkg>_<file>_use` (e.g., `js_core_math_radians_use` for `core/math/radians`)
- Core is the `core` package — its symbols follow the same `js_core_<name>_use` pattern as all other packages
- Package directories should contain only source files (no `.mach`/`.mcode` alongside source)
- Build cache files in `build/` are bare hashes (no extensions)
- Use `JS_FRAME`/`JS_ROOT`/`JS_RETURN` macros for any C function that allocates multiple heap objects. Any `JS_New*`/`JS_SetProperty*` call can trigger GC.
## Project Layout
- `source/` — C source for the cell runtime and CLI
- `docs/` — master documentation (Markdown), reflected on the website
- `website/` — Hugo site; theme at `website/themes/knr/`
- `internal/` — internal ƿit scripts (engine.cm etc.)
- `packages/` — core packages
- `Makefile` — build system (`make` to rebuild, `make bootstrap` for first build)
## Testing
After any C runtime changes, run all three test suites before considering the work done:
```
make # rebuild
./cell --dev vm_suite # VM-level tests (641 tests)
./cell --dev test suite # language-level tests (493 tests)
./cell --dev fuzz # fuzzer (100 iterations)
```
All three must pass with 0 failures.
## Documentation
The `docs/` folder is the single source of truth. The website at `website/` mounts it via Hugo. Key files:
- `docs/language.md` — language syntax reference
- `docs/functions.md` — all built-in intrinsic functions
- `docs/actors.md` — actor model and actor intrinsics
- `docs/requestors.md` — async requestor pattern
- `docs/library/*.md` — intrinsic type reference (text, number, array, object) and standard library modules

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>Prosperon</string>
<key>CFBundleIdentifier</key>
<string>pockle.world.prosperon</string>
<key>CFBundleName</key>
<string>Prosperon</string>
<key>CFBundleVersion</key>
<string>0.5</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2024 Pockle World. All rights reserved.</string>
</dict>
</plist>

26
LICENSE
View File

@@ -1,26 +0,0 @@
Prosperon Game Engine
Copyright (c) 2019-2024 John Alanbrook
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
(1) The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
(2) Any games or other derivative software must display the "Prosperon" logo
at near the beginning of the software's startup, before the chief purpose
of the software is underway.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

104
Makefile
View File

@@ -1,25 +1,83 @@
debug: FORCE
# Development build: creates libcell_runtime.dylib + thin main wrapper
# This is the default target for working on cell itself
#
# If cell doesn't exist yet, use 'make bootstrap' first (requires meson)
# or manually build with meson once.
#
# The cell shop is at ~/.cell and core scripts are installed to ~/.cell/core
CELL_SHOP = $(HOME)/.cell
CELL_CORE_PACKAGE = $(CELL_SHOP)/packages/core
doit: bootstrap
maker: install
makecell:
cell pack core -o cell
cp cell /opt/homebrew/bin/
# Install core: symlink this directory to ~/.cell/core
install: cell $(CELL_SHOP)
@echo "Linking cell core to $(CELL_CORE_PACKAGE)"
rm -rf $(CELL_CORE_PACKAGE)
ln -s $(PWD) $(CELL_CORE_PACKAGE)
cp cell /opt/homebrew/bin/
cp libcell_runtime.dylib /opt/homebrew/lib/
@echo "Core installed."
cell: libcell_runtime.dylib cell_main
cp cell_main cell
chmod +x cell
cp cell /opt/homebrew/bin/cell
cp libcell_runtime.dylib /opt/homebrew/lib/
# Build the shared runtime library (everything except main.c)
# Uses existing cell to run build -d
libcell_runtime.dylib: $(CELL_SHOP)/build/dynamic
cell build -d
cp $(CELL_SHOP)/build/dynamic/libcell_runtime.dylib .
# Build the thin main wrapper that links to libcell_runtime
cell_main: source/main.c libcell_runtime.dylib
cc -o cell_main source/main.c -L. -lcell_runtime -Wl,-rpath,@loader_path -Wl,-rpath,/opt/homebrew/lib
# Create the cell shop directories
$(CELL_SHOP):
mkdir -p $(CELL_SHOP)
mkdir -p $(CELL_SHOP)/packages
mkdir -p $(CELL_SHOP)/cache
mkdir -p $(CELL_SHOP)/build
$(CELL_CORE):
ln -s $(PWD) $(CELL_CORE)
# Static build: creates a fully static cell binary (for distribution)
static:
cell build
cp $(CELL_SHOP)/build/static/cell .
# Bootstrap: build cell from scratch using meson (only needed once)
# Also installs core scripts to ~/.cell/core
bootstrap:
meson setup build_bootstrap -Dbuildtype=debugoptimized
meson compile -C build_bootstrap
cp build_bootstrap/cell .
cp build_bootstrap/libcell_runtime.dylib .
@echo "Bootstrap complete. Run cell like ./cell --dev to use a local shop at .cell."
# Clean build artifacts
clean:
rm -rf $(CELL_SHOP)/build build_bootstrap
rm -f cell cell_main libcell_runtime.dylib
# Ensure dynamic build directory exists
$(CELL_SHOP)/build/dynamic: $(CELL_SHOP)
mkdir -p $(CELL_SHOP)/build/dynamic
# Legacy meson target
meson:
meson setup build_dbg -Dbuildtype=debugoptimized
meson compile -C build_dbg
meson install -C build_dbg
release: FORCE
meson setup -Dbuildtype=release -Db_lto=true -Db_ndebug=true -Db_pgo=use build_release
meson compile -C build_release
sanitize: FORCE
meson setup -Db_sanitize=address -Db_sanitize=memory -Db_sanitize=leak -Db_sanitize=undefined build_sani
meson compile -C build_sani
small: FORCE
meson setup -Dbuildtype=minsize -Db_lto=true -Db_ndebug=true -Db_pgo=use build_small
meson compile -C build_small
web: FORCE
meson setup -Deditor=false -Dbuildtype=minsize -Db_lto=true -Db_ndebug=true --cross-file emscripten.cross build_web
meson compile -C build_web
crosswin: FORCE
meson setup -Dbuildtype=debugoptimized --cross-file mingw32.cross build_win
meson compile -C build_win
FORCE:
.PHONY: cell static bootstrap clean meson install

View File

@@ -1,13 +1 @@
![alt text](doc/prosperon_orb_horizontal.gif)
The easily moddable, programming minded, 2D-first game engine. The aim is to make the fastest way to make games.
Using ...
* Sokol for rendering
* Chipmunk2D for physics
* imgui for easy editor UI
* Clay for game UI
Includes an implementation for Nota, and Kim.
*Prosperon is useful, but is a work in progress. Breaking changes are frequent.*
Read the docs to get started.

110
add.ce Normal file
View File

@@ -0,0 +1,110 @@
// cell add <locator> [alias] - Add a dependency to the current package
//
// Usage:
// cell add <locator> Add a dependency using default alias
// cell add <locator> <alias> Add a dependency with custom alias
//
// This adds the dependency to cell.toml and installs it to the shop.
var shop = use('internal/shop')
var pkg = use('package')
var build = use('build')
var fd = use('fd')
var locator = null
var alias = null
var resolved = null
var parts = null
var cwd = null
var build_target = null
array(args, function(arg) {
if (arg == '--help' || arg == '-h') {
log.console("Usage: cell add <locator> [alias]")
log.console("")
log.console("Add a dependency to the current package.")
log.console("")
log.console("Examples:")
log.console(" cell add gitea.pockle.world/john/prosperon")
log.console(" cell add gitea.pockle.world/john/cell-image image")
log.console(" cell add ../local-package")
$stop()
} else if (!starts_with(arg, '-')) {
if (!locator) {
locator = arg
} else if (!alias) {
alias = arg
}
}
})
if (!locator) {
log.console("Usage: cell add <locator> [alias]")
$stop()
}
// Resolve relative paths to absolute paths
if (locator == '.' || starts_with(locator, './') || starts_with(locator, '../') || fd.is_dir(locator)) {
resolved = fd.realpath(locator)
if (resolved) {
locator = resolved
}
}
// Generate default alias from locator
if (!alias) {
// Use the last component of the locator as alias
parts = array(locator, '/')
alias = parts[length(parts) - 1]
// Remove any version suffix
if (search(alias, '@') != null) {
alias = array(alias, '@')[0]
}
}
// Check we're in a package directory
cwd = fd.realpath('.')
if (!fd.is_file(cwd + '/cell.toml')) {
log.error("Not in a package directory (no cell.toml found)")
$stop()
}
log.console("Adding " + locator + " as '" + alias + "'...")
// Add to local project's cell.toml
var _add_dep = function() {
pkg.add_dependency(null, locator, alias)
log.console(" Added to cell.toml")
} disruption {
log.error("Failed to update cell.toml")
$stop()
}
_add_dep()
// Install to shop
var _install = function() {
shop.get(locator)
shop.extract(locator)
// Build scripts
shop.build_package_scripts(locator)
// Build C code if any
var _build_c = function() {
build_target = build.detect_host_target()
build.build_dynamic(locator, build_target, 'release')
} disruption {
// Not all packages have C code
}
_build_c()
log.console(" Installed to shop")
} disruption {
log.error("Failed to install")
$stop()
}
_install()
log.console("Added " + alias + " (" + locator + ")")
$stop()

401
archive/miniz.c Normal file
View File

@@ -0,0 +1,401 @@
#include "quickjs.h"
#include "miniz.h"
#include "cell.h"
static JSClassID js_reader_class_id;
static JSClassID js_writer_class_id;
static void js_reader_finalizer(JSRuntime *rt, JSValue val) {
mz_zip_archive *zip = JS_GetOpaque(val, js_reader_class_id);
mz_zip_reader_end(zip);
js_free_rt(zip);
}
static void js_writer_finalizer(JSRuntime *rt, JSValue val) {
mz_zip_archive *zip = JS_GetOpaque(val, js_writer_class_id);
mz_zip_writer_finalize_archive(zip);
mz_zip_writer_end(zip);
js_free_rt(zip);
}
static JSClassDef js_reader_class = {
"zip reader",
.finalizer = js_reader_finalizer,
};
static JSClassDef js_writer_class = {
"zip writer",
.finalizer = js_writer_finalizer,
};
static mz_zip_archive *js2reader(JSContext *js, JSValue v)
{
return JS_GetOpaque(v, js_reader_class_id);
}
static mz_zip_archive *js2writer(JSContext *js, JSValue v)
{
return JS_GetOpaque(v, js_writer_class_id);
}
static JSValue js_miniz_read(JSContext *js, JSValue self, int argc, JSValue *argv)
{
size_t len;
void *data = js_get_blob_data(js, &len, argv[0]);
if (data == -1)
return JS_EXCEPTION;
mz_zip_archive *zip = calloc(sizeof(*zip), 1);
if (!zip)
return JS_ThrowOutOfMemory(js);
mz_bool success = mz_zip_reader_init_mem(zip, data, len, 0);
if (!success) {
int err = mz_zip_get_last_error(zip);
free(zip);
return JS_ThrowInternalError(js, "Failed to initialize zip reader: %s", mz_zip_get_error_string(err));
}
JSValue jszip = JS_NewObjectClass(js, js_reader_class_id);
JS_SetOpaque(jszip, zip);
return jszip;
}
static JSValue js_miniz_write(JSContext *js, JSValue self, int argc, JSValue *argv)
{
const char *file = JS_ToCString(js, argv[0]);
if (!file)
return JS_EXCEPTION;
mz_zip_archive *zip = calloc(sizeof(*zip), 1);
if (!zip) {
JS_FreeCString(js, file);
return JS_ThrowOutOfMemory(js);
}
mz_bool success = mz_zip_writer_init_file(zip, file, 0);
JS_FreeCString(js, file);
if (!success) {
int err = mz_zip_get_last_error(zip);
mz_zip_writer_end(zip);
free(zip);
return JS_ThrowInternalError(js, "Failed to initialize zip writer: %s", mz_zip_get_error_string(err));
}
JSValue jszip = JS_NewObjectClass(js, js_writer_class_id);
JS_SetOpaque(jszip, zip);
return jszip;
}
static JSValue js_miniz_compress(JSContext *js, JSValue this_val,
int argc, JSValueConst *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js,
"compress needs a string or ArrayBuffer");
/* ─── 1. Grab the input data ──────────────────────────────── */
const char *cstring = NULL;
size_t in_len = 0;
const void *in_ptr = NULL;
if (JS_IsText(argv[0])) {
/* String → UTF-8 bytes without the terminating NUL */
cstring = JS_ToCStringLen(js, &in_len, argv[0]);
if (!cstring)
return JS_EXCEPTION;
in_ptr = cstring;
} else {
in_ptr = js_get_blob_data(js, &in_len, argv[0]);
if (in_ptr == -1)
return JS_EXCEPTION;
}
/* ─── 2. Allocate an output buffer big enough ────────────── */
mz_ulong out_len_est = mz_compressBound(in_len);
void *out_buf = js_malloc(js, out_len_est);
if (!out_buf) {
if (cstring) JS_FreeCString(js, cstring);
return JS_EXCEPTION;
}
/* ─── 3. Do the compression (MZ_DEFAULT_COMPRESSION = level 6) */
mz_ulong out_len = out_len_est;
int st = mz_compress2(out_buf, &out_len,
in_ptr, in_len, MZ_DEFAULT_COMPRESSION);
/* clean-up for string input */
if (cstring) JS_FreeCString(js, cstring);
if (st != MZ_OK) {
js_free(js, out_buf);
return JS_ThrowInternalError(js,
"miniz: compression failed (%d)", st);
}
/* ─── 4. Hand JavaScript a copy of the compressed data ────── */
JSValue abuf = js_new_blob_stoned_copy(js, out_buf, out_len);
js_free(js, out_buf);
return abuf;
}
static JSValue js_miniz_decompress(JSContext *js,
JSValueConst this_val,
int argc,
JSValueConst *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js,
"decompress: need compressed ArrayBuffer");
/* grab compressed data */
size_t in_len;
void *in_ptr = js_get_blob_data(js, &in_len, argv[0]);
if (in_ptr == -1)
return JS_EXCEPTION;
/* zlib header present → tell tinfl to parse it */
size_t out_len = 0;
void *out_ptr = tinfl_decompress_mem_to_heap(
in_ptr, in_len, &out_len,
TINFL_FLAG_PARSE_ZLIB_HEADER);
if (!out_ptr)
return JS_ThrowInternalError(js,
"miniz: decompression failed");
JSValue ret;
ret = JS_NewStringLen(js, (const char *)out_ptr, out_len);
#ifdef MZ_FREE
MZ_FREE(out_ptr);
#else
free(out_ptr);
#endif
return ret;
}
static const JSCFunctionListEntry js_miniz_funcs[] = {
JS_CFUNC_DEF("read", 1, js_miniz_read),
JS_CFUNC_DEF("write", 1, js_miniz_write),
JS_CFUNC_DEF("compress", 1, js_miniz_compress),
JS_CFUNC_DEF("decompress", 1, js_miniz_decompress),
};
JSValue js_writer_add_file(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 2)
return JS_ThrowTypeError(js, "add_file requires (path, arrayBuffer)");
mz_zip_archive *zip = js2writer(js, self);
const char *pathInZip = JS_ToCString(js, argv[0]);
if (!pathInZip)
return JS_ThrowTypeError(js, "Could not parse path argument");
size_t dataLen;
void *data = js_get_blob_data(js, &dataLen, argv[1]);
if (data == -1) {
JS_FreeCString(js, pathInZip);
return JS_EXCEPTION;
}
int success = mz_zip_writer_add_mem(zip, pathInZip, data, dataLen, MZ_DEFAULT_COMPRESSION);
JS_FreeCString(js, pathInZip);
if (!success)
return JS_ThrowInternalError(js, "Failed to add memory to zip");
return JS_NULL;
}
static const JSCFunctionListEntry js_writer_funcs[] = {
JS_CFUNC_DEF("add_file", 1, js_writer_add_file),
};
JSValue js_reader_mod(JSContext *js, JSValue self, int argc, JSValue *argv)
{
#ifndef MINIZ_NO_TIME
const char *file = JS_ToCString(js,argv[0]);
if (!file)
return JS_EXCEPTION;
mz_zip_archive *zip = js2reader(js, self);
if (!zip) {
JS_FreeCString(js, file);
return JS_ThrowInternalError(js, "Invalid zip reader");
}
mz_zip_archive_file_stat pstat;
mz_uint index = mz_zip_reader_locate_file(zip, file, NULL, 0);
if (index == (mz_uint)-1) {
JS_FreeCString(js, file);
return JS_ThrowReferenceError(js, "File '%s' not found in archive", file);
}
JS_FreeCString(js, file);
if (!mz_zip_reader_file_stat(zip, index, &pstat)) {
int err = mz_zip_get_last_error(zip);
return JS_ThrowInternalError(js, "Failed to get file stats: %s", mz_zip_get_error_string(err));
}
return JS_NewFloat64(js, pstat.m_time);
#else
return JS_ThrowInternalError(js, "MINIZ_NO_TIME is defined");
#endif
}
JSValue js_reader_exists(JSContext *js, JSValue self, int argc, JSValue *argv)
{
const char *file = JS_ToCString(js,argv[0]);
if (!file)
return JS_EXCEPTION;
mz_zip_archive *zip = js2reader(js, self);
if (!zip) {
JS_FreeCString(js, file);
return JS_ThrowInternalError(js, "Invalid zip reader");
}
mz_uint index = mz_zip_reader_locate_file(zip, file, NULL, 0);
JS_FreeCString(js,file);
if (index == (mz_uint)-1) return JS_NewBool(js, 0);
return JS_NewBool(js, 1);
}
JSValue js_reader_slurp(JSContext *js, JSValue self, int argc, JSValue *argv)
{
const char *file = JS_ToCString(js,argv[0]);
if (!file)
return JS_EXCEPTION;
mz_zip_archive *zip = js2reader(js, self);
if (!zip) {
JS_FreeCString(js, file);
return JS_ThrowInternalError(js, "Invalid zip reader");
}
size_t len;
void *data = mz_zip_reader_extract_file_to_heap(zip, file, &len, 0);
if (!data) {
int err = mz_zip_get_last_error(zip);
const char *filename = file;
JS_FreeCString(js, file);
return JS_ThrowInternalError(js, "Failed to extract file '%s': %s", filename, mz_zip_get_error_string(err));
}
JS_FreeCString(js, file);
JSValue ret = js_new_blob_stoned_copy(js, data, len);
free(data);
return ret;
}
JSValue js_reader_list(JSContext *js, JSValue self, int argc, JSValue *argv)
{
mz_zip_archive *zip = js2reader(js, self);
if (!zip)
return JS_ThrowInternalError(js, "Invalid zip reader");
mz_uint num_files = mz_zip_reader_get_num_files(zip);
JSValue arr = JS_NewArray(js);
if (JS_IsException(arr))
return arr;
mz_uint arr_index = 0;
for (mz_uint i = 0; i < num_files; i++) {
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(zip, i, &file_stat))
continue;
JSValue filename = JS_NewString(js, file_stat.m_filename);
if (JS_IsException(filename)) {
JS_FreeValue(js, arr);
return filename;
}
JS_SetPropertyNumber(js, arr, arr_index++, filename);
}
return arr;
}
JSValue js_reader_is_directory(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js, "is_directory requires a file index");
int32_t index;
if (JS_ToInt32(js, &index, argv[0]))
return JS_EXCEPTION;
mz_zip_archive *zip = js2reader(js, self);
if (!zip)
return JS_ThrowInternalError(js, "Invalid zip reader");
return JS_NewBool(js, mz_zip_reader_is_file_a_directory(zip, index));
}
JSValue js_reader_get_filename(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js, "get_filename requires a file index");
int32_t index;
if (JS_ToInt32(js, &index, argv[0]))
return JS_EXCEPTION;
mz_zip_archive *zip = js2reader(js, self);
if (!zip)
return JS_ThrowInternalError(js, "Invalid zip reader");
mz_zip_archive_file_stat file_stat;
if (!mz_zip_reader_file_stat(zip, index, &file_stat))
return JS_ThrowInternalError(js, "Failed to get file stats");
return JS_NewString(js, file_stat.m_filename);
}
JSValue js_reader_count(JSContext *js, JSValue self, int argc, JSValue *argv)
{
mz_zip_archive *zip = js2reader(js, self);
if (!zip)
return JS_ThrowInternalError(js, "Invalid zip reader");
return JS_NewUint32(js, mz_zip_reader_get_num_files(zip));
}
static const JSCFunctionListEntry js_reader_funcs[] = {
JS_CFUNC_DEF("mod", 1, js_reader_mod),
JS_CFUNC_DEF("exists", 1, js_reader_exists),
JS_CFUNC_DEF("slurp", 1, js_reader_slurp),
JS_CFUNC_DEF("list", 0, js_reader_list),
JS_CFUNC_DEF("is_directory", 1, js_reader_is_directory),
JS_CFUNC_DEF("get_filename", 1, js_reader_get_filename),
JS_CFUNC_DEF("count", 0, js_reader_count),
};
JSValue js_core_miniz_use(JSContext *js)
{
JS_FRAME(js);
JS_NewClassID(&js_reader_class_id);
JS_NewClass(js, js_reader_class_id, &js_reader_class);
JS_ROOT(reader_proto, JS_NewObject(js));
JS_SetPropertyFunctionList(js, reader_proto.val, js_reader_funcs, sizeof(js_reader_funcs) / sizeof(JSCFunctionListEntry));
JS_SetClassProto(js, js_reader_class_id, reader_proto.val);
JS_NewClassID(&js_writer_class_id);
JS_NewClass(js, js_writer_class_id, &js_writer_class);
JS_ROOT(writer_proto, JS_NewObject(js));
JS_SetPropertyFunctionList(js, writer_proto.val, js_writer_funcs, sizeof(js_writer_funcs) / sizeof(JSCFunctionListEntry));
JS_SetClassProto(js, js_writer_class_id, writer_proto.val);
JS_ROOT(export, JS_NewObject(js));
JS_SetPropertyFunctionList(js, export.val, js_miniz_funcs, sizeof(js_miniz_funcs)/sizeof(JSCFunctionListEntry));
JS_RETURN(export.val);
}

591
bench.ce Normal file
View File

@@ -0,0 +1,591 @@
var shop = use('internal/shop')
var pkg = use('package')
var fd = use('fd')
var time = use('time')
var json = use('json')
var blob = use('blob')
var os = use('os')
var testlib = use('internal/testlib')
var math = use('math/radians')
var _args = args == null ? [] : args
var target_pkg = null // null = current package
var target_bench = null // null = all benchmarks, otherwise specific bench file
var all_pkgs = false
// Benchmark configuration
def WARMUP_BATCHES = 3
def SAMPLES = 11 // Number of timing samples to collect
def TARGET_SAMPLE_NS = 20000000 // 20ms per sample (fast mode)
def MIN_SAMPLE_NS = 2000000 // 2ms minimum sample duration
def MIN_BATCH_SIZE = 1
def MAX_BATCH_SIZE = 100000000 // 100M iterations max per batch
// Statistical functions
function median(arr) {
if (length(arr) == 0) return 0
var sorted = sort(arr)
var mid = floor(length(arr) / 2)
if (length(arr) % 2 == 0) {
return (sorted[mid - 1] + sorted[mid]) / 2
}
return sorted[mid]
}
function mean(arr) {
if (length(arr) == 0) return 0
var sum = 0
arrfor(arr, function(val) {
sum += val
})
return sum / length(arr)
}
function stddev(arr, mean_val) {
if (length(arr) < 2) return 0
var sum_sq_diff = 0
arrfor(arr, function(val) {
var diff = val - mean_val
sum_sq_diff += diff * diff
})
return math.sqrt(sum_sq_diff / (length(arr) - 1))
}
function percentile(arr, p) {
if (length(arr) == 0) return 0
var sorted = sort(arr)
var idx = floor(length(arr) * p / 100)
if (idx >= length(arr)) idx = length(arr) - 1
return sorted[idx]
}
// Parse arguments similar to test.ce
function parse_args() {
var name = null
var lock = null
var resolved = null
var bench_path = null
if (length(_args) == 0) {
if (!testlib.is_valid_package('.')) {
log.console('No cell.toml found in current directory')
return false
}
target_pkg = null
return true
}
if (_args[0] == 'all') {
if (!testlib.is_valid_package('.')) {
log.console('No cell.toml found in current directory')
return false
}
target_pkg = null
return true
}
if (_args[0] == 'package') {
if (length(_args) < 2) {
log.console('Usage: cell bench package <name> [bench]')
log.console(' cell bench package all')
return false
}
if (_args[1] == 'all') {
all_pkgs = true
log.console('Benchmarking all packages...')
return true
}
name = _args[1]
lock = shop.load_lock()
if (lock[name]) {
target_pkg = name
} else if (starts_with(name, '/') && testlib.is_valid_package(name)) {
target_pkg = name
} else {
if (testlib.is_valid_package('.')) {
resolved = pkg.alias_to_package(null, name)
if (resolved) {
target_pkg = resolved
} else {
log.console(`Package not found: ${name}`)
return false
}
} else {
log.console(`Package not found: ${name}`)
return false
}
}
if (length(_args) >= 3) {
target_bench = _args[2]
}
log.console(`Benchmarking package: ${target_pkg}`)
return true
}
// cell bench benches/suite or cell bench <path>
bench_path = _args[0]
// Normalize path - add benches/ prefix if not present
if (!starts_with(bench_path, 'benches/') && !starts_with(bench_path, '/')) {
if (!fd.is_file(bench_path + '.cm') && !fd.is_file(bench_path)) {
if (fd.is_file('benches/' + bench_path + '.cm') || fd.is_file('benches/' + bench_path)) {
bench_path = 'benches/' + bench_path
}
}
}
target_bench = bench_path
target_pkg = null
if (!testlib.is_valid_package('.')) {
log.console('No cell.toml found in current directory')
return false
}
return true
}
if (!parse_args()) {
$stop()
return
}
// Collect benchmark files from a package
function collect_benches(package_name, specific_bench) {
var prefix = testlib.get_pkg_dir(package_name)
var benches_dir = prefix + '/benches'
if (!fd.is_dir(benches_dir)) return []
var files = pkg.list_files(package_name)
var bench_files = []
arrfor(files, function(f) {
var bench_name = null
var match_name = null
var match_base = null
if (starts_with(f, "benches/") && ends_with(f, ".cm")) {
if (specific_bench) {
bench_name = text(f, 0, -3)
match_name = specific_bench
if (!starts_with(match_name, 'benches/')) match_name = 'benches/' + match_name
match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (bench_name != match_base) return
}
push(bench_files, f)
}
})
return bench_files
}
// Calibrate batch size for a benchmark
function calibrate_batch_size(bench_fn, is_batch) {
if (!is_batch) return 1
var n = MIN_BATCH_SIZE
var dt = 0
var start = 0
var new_n = 0
var calc = 0
var target_n = 0
// Find a batch size that takes at least MIN_SAMPLE_NS
while (n < MAX_BATCH_SIZE) {
if (!is_number(n) || n < 1) {
n = 1
break
}
start = os.now()
bench_fn(n)
dt = os.now() - start
if (dt >= MIN_SAMPLE_NS) break
new_n = n * 2
if (!is_number(new_n) || new_n > MAX_BATCH_SIZE) {
n = MAX_BATCH_SIZE
break
}
n = new_n
}
// Adjust to target sample duration
if (dt > 0 && dt < TARGET_SAMPLE_NS && is_number(n) && is_number(dt)) {
calc = n * TARGET_SAMPLE_NS / dt
if (is_number(calc) && calc > 0) {
target_n = floor(calc)
if (is_number(target_n) && target_n > 0) {
if (target_n > MAX_BATCH_SIZE) target_n = MAX_BATCH_SIZE
if (target_n < MIN_BATCH_SIZE) target_n = MIN_BATCH_SIZE
n = target_n
}
}
}
if (!is_number(n) || n < 1) {
n = 1
}
return n
}
// Run a single benchmark function
function run_single_bench(bench_fn, bench_name) {
var timings_per_op = []
var is_structured = is_object(bench_fn) && bench_fn.run
var is_batch = false
var batch_size = 1
var setup_fn = null
var run_fn = null
var teardown_fn = null
var calibrate_fn = null
var _detect = null
var i = 0
var state = null
var start = 0
var duration = 0
var ns_per_op = 0
if (is_structured) {
setup_fn = bench_fn.setup || function() { return null }
run_fn = bench_fn.run
teardown_fn = bench_fn.teardown || function(s) {}
// Check if run function accepts batch size
_detect = function() {
var test_state = setup_fn()
run_fn(1, test_state)
is_batch = true
if (teardown_fn) teardown_fn(test_state)
} disruption {
is_batch = false
}
_detect()
calibrate_fn = function(n) {
var s = setup_fn()
run_fn(n, s)
if (teardown_fn) teardown_fn(s)
}
batch_size = calibrate_batch_size(calibrate_fn, is_batch)
if (!is_number(batch_size) || batch_size < 1) {
batch_size = 1
}
} else {
// Simple function format
_detect = function() {
bench_fn(1)
is_batch = true
} disruption {
is_batch = false
}
_detect()
batch_size = calibrate_batch_size(bench_fn, is_batch)
}
if (!batch_size || batch_size < 1) {
batch_size = 1
}
// Warmup phase
for (i = 0; i < WARMUP_BATCHES; i++) {
if (!is_number(batch_size) || batch_size < 1) {
batch_size = 1
}
if (is_structured) {
state = setup_fn()
if (is_batch) {
run_fn(batch_size, state)
} else {
run_fn(state)
}
if (teardown_fn) teardown_fn(state)
} else {
if (is_batch) {
bench_fn(batch_size)
} else {
bench_fn()
}
}
}
// Measurement phase - collect SAMPLES timing samples
for (i = 0; i < SAMPLES; i++) {
if (!is_number(batch_size) || batch_size < 1) {
batch_size = 1
}
if (is_structured) {
state = setup_fn()
start = os.now()
if (is_batch) {
run_fn(batch_size, state)
} else {
run_fn(state)
}
duration = os.now() - start
if (teardown_fn) teardown_fn(state)
ns_per_op = is_batch ? duration / batch_size : duration
push(timings_per_op, ns_per_op)
} else {
start = os.now()
if (is_batch) {
bench_fn(batch_size)
} else {
bench_fn()
}
duration = os.now() - start
ns_per_op = is_batch ? duration / batch_size : duration
push(timings_per_op, ns_per_op)
}
}
// Calculate statistics
var mean_ns = mean(timings_per_op)
var median_ns = median(timings_per_op)
var min_ns = reduce(timings_per_op, min)
var max_ns = reduce(timings_per_op, max)
var stddev_ns = stddev(timings_per_op, mean_ns)
var p95_ns = percentile(timings_per_op, 95)
var p99_ns = percentile(timings_per_op, 99)
var ops_per_sec = 0
if (median_ns > 0) {
ops_per_sec = floor(1000000000 / median_ns)
}
return {
name: bench_name,
batch_size: batch_size,
samples: SAMPLES,
mean_ns: round(mean_ns),
median_ns: round(median_ns),
min_ns: round(min_ns),
max_ns: round(max_ns),
stddev_ns: round(stddev_ns),
p95_ns: round(p95_ns),
p99_ns: round(p99_ns),
ops_per_sec: ops_per_sec
}
}
// Format nanoseconds for display
function format_ns(ns) {
if (ns < 1000) return `${ns}ns`
if (ns < 1000000) return `${round(ns / 1000 * 100) / 100}µs`
if (ns < 1000000000) return `${round(ns / 1000000 * 100) / 100}ms`
return `${round(ns / 1000000000 * 100) / 100}s`
}
// Format ops/sec for display
function format_ops(ops) {
if (ops < 1000) return `${ops} ops/s`
if (ops < 1000000) return `${round(ops / 1000 * 100) / 100}K ops/s`
if (ops < 1000000000) return `${round(ops / 1000000 * 100) / 100}M ops/s`
return `${round(ops / 1000000000 * 100) / 100}G ops/s`
}
// Run benchmarks for a package
function run_benchmarks(package_name, specific_bench) {
var bench_files = collect_benches(package_name, specific_bench)
var pkg_result = {
package: package_name || "local",
files: [],
total: 0
}
if (length(bench_files) == 0) return pkg_result
if (package_name) log.console(`Running benchmarks for ${package_name}`)
else log.console(`Running benchmarks for local package`)
arrfor(bench_files, function(f) {
var mod_path = text(f, 0, -3)
var load_error = false
var bench_mod = null
var use_pkg = null
var benches = []
var error_result = null
var file_result = {
name: f,
benchmarks: []
}
var _load_file = function() {
use_pkg = package_name ? package_name : fd.realpath('.')
bench_mod = shop.use(mod_path, use_pkg)
if (is_function(bench_mod)) {
push(benches, {name: 'main', fn: bench_mod})
} else if (is_object(bench_mod)) {
arrfor(array(bench_mod), function(k) {
if (is_function(bench_mod[k]))
push(benches, {name: k, fn: bench_mod[k]})
})
}
if (length(benches) > 0) {
log.console(` ${f}`)
arrfor(benches, function(b) {
var bench_error = false
var result = null
var _run_bench = function() {
result = run_single_bench(b.fn, b.name)
result.package = pkg_result.package
push(file_result.benchmarks, result)
pkg_result.total++
log.console(` ${result.name}`)
log.console(` ${format_ns(result.median_ns)}/op ${format_ops(result.ops_per_sec)}`)
log.console(` min: ${format_ns(result.min_ns)} max: ${format_ns(result.max_ns)} stddev: ${format_ns(result.stddev_ns)}`)
if (result.batch_size > 1) {
log.console(` batch: ${result.batch_size} samples: ${result.samples}`)
}
} disruption {
bench_error = true
}
_run_bench()
if (bench_error) {
log.console(` ERROR ${b.name}`)
error_result = {
package: pkg_result.package,
name: b.name,
error: "benchmark disrupted"
}
push(file_result.benchmarks, error_result)
pkg_result.total++
}
})
}
} disruption {
load_error = true
}
_load_file()
if (load_error) {
log.console(` Error loading ${f}`)
error_result = {
package: pkg_result.package,
name: "load_module",
error: "error loading module"
}
push(file_result.benchmarks, error_result)
pkg_result.total++
}
if (length(file_result.benchmarks) > 0) {
push(pkg_result.files, file_result)
}
})
return pkg_result
}
// Run all benchmarks
var all_results = []
var packages = null
if (all_pkgs) {
if (testlib.is_valid_package('.')) {
push(all_results, run_benchmarks(null, null))
}
packages = shop.list_packages()
arrfor(packages, function(p) {
push(all_results, run_benchmarks(p, null))
})
} else {
push(all_results, run_benchmarks(target_pkg, target_bench))
}
// Calculate totals
var total_benches = 0
arrfor(all_results, function(result) {
total_benches += result.total
})
log.console(`----------------------------------------`)
log.console(`Benchmarks: ${total_benches} total`)
// Generate reports
function generate_reports() {
var timestamp = text(floor(time.number()))
var report_dir = shop.get_reports_dir() + '/bench_' + timestamp
testlib.ensure_dir(report_dir)
var txt_report = `BENCHMARK REPORT
Date: ${time.text(time.number())}
Total benchmarks: ${total_benches}
=== SUMMARY ===
`
arrfor(all_results, function(pkg_res) {
if (pkg_res.total == 0) return
txt_report += `Package: ${pkg_res.package}\n`
arrfor(pkg_res.files, function(f) {
txt_report += ` ${f.name}\n`
arrfor(f.benchmarks, function(b) {
if (b.error) {
txt_report += ` ERROR ${b.name}: ${b.error}\n`
} else {
txt_report += ` ${b.name}: ${format_ns(b.median_ns)}/op (${format_ops(b.ops_per_sec)})\n`
}
})
})
})
txt_report += `\n=== DETAILED RESULTS ===\n`
arrfor(all_results, function(pkg_res) {
if (pkg_res.total == 0) return
arrfor(pkg_res.files, function(f) {
arrfor(f.benchmarks, function(b) {
if (b.error) return
txt_report += `\n${pkg_res.package}::${b.name}\n`
txt_report += ` batch_size: ${b.batch_size} samples: ${b.samples}\n`
txt_report += ` median: ${format_ns(b.median_ns)}/op\n`
txt_report += ` mean: ${format_ns(b.mean_ns)}/op\n`
txt_report += ` min: ${format_ns(b.min_ns)}\n`
txt_report += ` max: ${format_ns(b.max_ns)}\n`
txt_report += ` stddev: ${format_ns(b.stddev_ns)}\n`
txt_report += ` p95: ${format_ns(b.p95_ns)}\n`
txt_report += ` p99: ${format_ns(b.p99_ns)}\n`
txt_report += ` ops/s: ${format_ops(b.ops_per_sec)}\n`
})
})
})
testlib.ensure_dir(report_dir)
fd.slurpwrite(`${report_dir}/bench.txt`, stone(blob(txt_report)))
log.console(`Report written to ${report_dir}/bench.txt`)
// Generate JSON per package
arrfor(all_results, function(pkg_res) {
if (pkg_res.total == 0) return
var pkg_benches = []
arrfor(pkg_res.files, function(f) {
arrfor(f.benchmarks, function(benchmark) {
push(pkg_benches, benchmark)
})
})
var json_path = `${report_dir}/${replace(pkg_res.package, /\//, '_')}.json`
fd.slurpwrite(json_path, stone(blob(json.encode(pkg_benches))))
})
}
generate_reports()
$stop()

194
bench_native.ce Normal file
View File

@@ -0,0 +1,194 @@
// bench_native.ce — compare VM vs native execution speed
//
// Usage:
// cell --dev bench_native.ce <module.cm> [iterations]
//
// Compiles (if needed) and benchmarks a module via both VM and native dylib.
// Reports median/mean timing per benchmark + speedup ratio.
var os = use('os')
var fd = use('fd')
if (length(args) < 1) {
print('usage: cell --dev bench_native.ce <module.cm> [iterations]')
return
}
var file = args[0]
var name = file
if (ends_with(name, '.cm')) {
name = text(name, 0, length(name) - 3)
}
var iterations = 11
if (length(args) > 1) {
iterations = number(args[1])
}
def WARMUP = 3
var safe = replace(replace(name, '/', '_'), '-', '_')
var symbol = 'js_' + safe + '_use'
var dylib_path = './' + file + '.dylib'
// --- Statistics ---
var stat_sort = function(arr) {
return sort(arr)
}
var stat_median = function(arr) {
if (length(arr) == 0) return 0
var sorted = stat_sort(arr)
var mid = floor(length(arr) / 2)
if (length(arr) % 2 == 0) {
return (sorted[mid - 1] + sorted[mid]) / 2
}
return sorted[mid]
}
var stat_mean = function(arr) {
if (length(arr) == 0) return 0
var sum = reduce(arr, function(a, b) { return a + b })
return sum / length(arr)
}
var format_ns = function(ns) {
if (ns < 1000) return text(round(ns)) + 'ns'
if (ns < 1000000) return text(round(ns / 1000 * 100) / 100) + 'us'
if (ns < 1000000000) return text(round(ns / 1000000 * 100) / 100) + 'ms'
return text(round(ns / 1000000000 * 100) / 100) + 's'
}
// --- Collect benchmarks from module ---
var collect_benches = function(mod) {
var benches = []
var keys = null
var i = 0
var k = null
if (is_function(mod)) {
push(benches, {name: 'main', fn: mod})
} else if (is_object(mod)) {
keys = array(mod)
i = 0
while (i < length(keys)) {
k = keys[i]
if (is_function(mod[k])) {
push(benches, {name: k, fn: mod[k]})
}
i = i + 1
}
}
return benches
}
// --- Run one benchmark function ---
var run_bench = function(fn, label) {
var samples = []
var i = 0
var t1 = 0
var t2 = 0
// warmup
i = 0
while (i < WARMUP) {
fn(1)
i = i + 1
}
// collect samples
i = 0
while (i < iterations) {
t1 = os.now()
fn(1)
t2 = os.now()
push(samples, t2 - t1)
i = i + 1
}
return {
label: label,
median: stat_median(samples),
mean: stat_mean(samples)
}
}
// --- Load VM module ---
print('loading VM module: ' + file)
var vm_mod = use(name)
var vm_benches = collect_benches(vm_mod)
if (length(vm_benches) == 0) {
print('no benchmarkable functions found in ' + file)
return
}
// --- Load native module ---
var native_mod = null
var native_benches = []
var has_native = fd.is_file(dylib_path)
var lib = null
if (has_native) {
print('loading native module: ' + dylib_path)
lib = os.dylib_open(dylib_path)
native_mod = os.dylib_symbol(lib, symbol)
native_benches = collect_benches(native_mod)
} else {
print('no ' + dylib_path + ' found -- VM-only benchmarking')
print(' hint: cell --dev compile.ce ' + file)
}
// --- Run benchmarks ---
print('')
print('samples: ' + text(iterations) + ' (warmup: ' + text(WARMUP) + ')')
print('')
var pad = function(s, n) {
var result = s
while (length(result) < n) result = result + ' '
return result
}
var i = 0
var b = null
var vm_result = null
var j = 0
var found = false
var nat_result = null
var speedup = 0
while (i < length(vm_benches)) {
b = vm_benches[i]
vm_result = run_bench(b.fn, 'vm')
print(pad(b.name, 20) + ' VM: ' + pad(format_ns(vm_result.median), 12) + ' (median) ' + format_ns(vm_result.mean) + ' (mean)')
// find matching native bench
j = 0
found = false
while (j < length(native_benches)) {
if (native_benches[j].name == b.name) {
nat_result = run_bench(native_benches[j].fn, 'native')
print(pad('', 20) + ' NT: ' + pad(format_ns(nat_result.median), 12) + ' (median) ' + format_ns(nat_result.mean) + ' (mean)')
if (nat_result.median > 0) {
speedup = vm_result.median / nat_result.median
print(pad('', 20) + ' speedup: ' + text(round(speedup * 100) / 100) + 'x')
}
found = true
}
j = j + 1
}
if (has_native && !found) {
print(pad('', 20) + ' NT: (no matching function)')
}
print('')
i = i + 1
}

232
benches/actor_patterns.cm Normal file
View File

@@ -0,0 +1,232 @@
// actor_patterns.cm — Actor concurrency benchmarks
// Message passing, fan-out/fan-in, mailbox throughput.
// These use structured benchmarks with setup/run/teardown.
// Note: actor benchmarks are measured differently from pure compute.
// Each iteration sends messages and waits for results, so they're
// inherently slower but test real concurrency costs.
// Simple ping-pong: two actors sending messages back and forth
// Since we can't create real actors from a module, we simulate
// the message-passing patterns with function call overhead that
// mirrors what the actor dispatch does.
// Simulate message dispatch overhead
function make_mailbox() {
return {
queue: [],
delivered: 0
}
}
function send(mailbox, msg) {
push(mailbox.queue, msg)
return null
}
function receive(mailbox) {
if (length(mailbox.queue) == 0) return null
mailbox.delivered++
return pop(mailbox.queue)
}
function drain(mailbox) {
var count = 0
while (length(mailbox.queue) > 0) {
pop(mailbox.queue)
count++
}
return count
}
// Ping-pong: simulate two actors exchanging messages
function ping_pong(rounds) {
var box_a = make_mailbox()
var box_b = make_mailbox()
var i = 0
var msg = null
send(box_a, {type: "ping", val: 0})
for (i = 0; i < rounds; i++) {
// A receives and sends to B
msg = receive(box_a)
if (msg) {
send(box_b, {type: "pong", val: msg.val + 1})
}
// B receives and sends to A
msg = receive(box_b)
if (msg) {
send(box_a, {type: "ping", val: msg.val + 1})
}
}
return box_a.delivered + box_b.delivered
}
// Fan-out: one sender, N receivers
function fan_out(n_receivers, messages_per) {
var receivers = []
var i = 0
var j = 0
for (i = 0; i < n_receivers; i++) {
push(receivers, make_mailbox())
}
// Send messages to all receivers
for (j = 0; j < messages_per; j++) {
for (i = 0; i < n_receivers; i++) {
send(receivers[i], {seq: j, data: j * 17})
}
}
// All receivers drain
var total = 0
for (i = 0; i < n_receivers; i++) {
total += drain(receivers[i])
}
return total
}
// Fan-in: N senders, one receiver
function fan_in(n_senders, messages_per) {
var inbox = make_mailbox()
var i = 0
var j = 0
// Each sender sends messages
for (i = 0; i < n_senders; i++) {
for (j = 0; j < messages_per; j++) {
send(inbox, {sender: i, seq: j, data: i * 100 + j})
}
}
// Receiver processes all
var total = 0
var msg = null
msg = receive(inbox)
while (msg) {
total += msg.data
msg = receive(inbox)
}
return total
}
// Pipeline: chain of processors
function pipeline(stages, items) {
var boxes = []
var i = 0
var j = 0
var msg = null
for (i = 0; i <= stages; i++) {
push(boxes, make_mailbox())
}
// Feed input
for (i = 0; i < items; i++) {
send(boxes[0], {val: i})
}
// Process each stage
for (j = 0; j < stages; j++) {
msg = receive(boxes[j])
while (msg) {
send(boxes[j + 1], {val: msg.val * 2 + 1})
msg = receive(boxes[j])
}
}
// Drain output
var total = 0
msg = receive(boxes[stages])
while (msg) {
total += msg.val
msg = receive(boxes[stages])
}
return total
}
// Request-response pattern (simulate RPC)
function request_response(n_requests) {
var client_box = make_mailbox()
var server_box = make_mailbox()
var i = 0
var req = null
var resp = null
var total = 0
for (i = 0; i < n_requests; i++) {
// Client sends request
send(server_box, {id: i, payload: i * 3, reply_to: client_box})
// Server processes
req = receive(server_box)
if (req) {
send(req.reply_to, {id: req.id, result: req.payload * 2 + 1})
}
// Client receives response
resp = receive(client_box)
if (resp) {
total += resp.result
}
}
return total
}
return {
// Ping-pong: 10K rounds
ping_pong_10k: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += ping_pong(10000)
}
return x
},
// Fan-out: 100 receivers, 100 messages each
fan_out_100x100: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += fan_out(100, 100)
}
return x
},
// Fan-in: 100 senders, 100 messages each
fan_in_100x100: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += fan_in(100, 100)
}
return x
},
// Pipeline: 10 stages, 1000 items
pipeline_10x1k: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += pipeline(10, 1000)
}
return x
},
// Request-response: 5K requests
rpc_5k: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += request_response(5000)
}
return x
}
}

141
benches/cli_tool.cm Normal file
View File

@@ -0,0 +1,141 @@
// cli_tool.cm — CLI tool simulation (macro benchmark)
// Parse args + process data + transform + format output.
// Simulates a realistic small utility program.
var json = use('json')
// Generate fake records
function generate_records(n) {
var records = []
var x = 42
var i = 0
var status_vals = ["active", "inactive", "pending", "archived"]
var dept_vals = ["eng", "sales", "ops", "hr", "marketing"]
for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(records, {
id: i + 1,
name: `user_${i}`,
score: (x % 1000) / 10,
status: status_vals[i % 4],
department: dept_vals[i % 5]
})
}
return records
}
// Filter records by field value
function filter_records(records, field, value) {
var result = []
var i = 0
for (i = 0; i < length(records); i++) {
if (records[i][field] == value) {
push(result, records[i])
}
}
return result
}
// Group by a field
function group_by(records, field) {
var groups = {}
var i = 0
var key = null
for (i = 0; i < length(records); i++) {
key = records[i][field]
if (!key) key = "unknown"
if (!groups[key]) groups[key] = []
push(groups[key], records[i])
}
return groups
}
// Aggregate: compute stats per group
function aggregate(groups) {
var keys = array(groups)
var result = []
var i = 0
var j = 0
var grp = null
var total = 0
var mn = 0
var mx = 0
for (i = 0; i < length(keys); i++) {
grp = groups[keys[i]]
total = 0
mn = 999999
mx = 0
for (j = 0; j < length(grp); j++) {
total += grp[j].score
if (grp[j].score < mn) mn = grp[j].score
if (grp[j].score > mx) mx = grp[j].score
}
push(result, {
group: keys[i],
count: length(grp),
average: total / length(grp),
low: mn,
high: mx
})
}
return result
}
// Full pipeline: load → filter → sort → group → aggregate → encode
function run_pipeline(n_records) {
// Generate data
var records = generate_records(n_records)
// Filter to active records
var filtered = filter_records(records, "status", "active")
// Sort by score
filtered = sort(filtered, "score")
// Limit to first 50
if (length(filtered) > 50) {
filtered = array(filtered, 0, 50)
}
// Group and aggregate
var groups = group_by(filtered, "department")
var stats = aggregate(groups)
stats = sort(stats, "average")
// Encode as JSON
var output = json.encode(stats)
return length(output)
}
return {
// Small dataset (100 records)
cli_pipeline_100: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += run_pipeline(100)
}
return x
},
// Medium dataset (1000 records)
cli_pipeline_1k: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += run_pipeline(1000)
}
return x
},
// Large dataset (10K records)
cli_pipeline_10k: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += run_pipeline(10000)
}
return x
}
}

162
benches/deltablue.cm Normal file
View File

@@ -0,0 +1,162 @@
// deltablue.cm — Constraint solver kernel (DeltaBlue-inspired)
// Dynamic dispatch, pointer chasing, object-heavy workload.
def REQUIRED = 0
def STRONG = 1
def NORMAL = 2
def WEAK = 3
def WEAKEST = 4
function make_variable(name, value) {
return {
name: name,
value: value,
constraints: [],
determined_by: null,
stay: true,
mark: 0
}
}
function make_constraint(strength, variables, satisfy_fn) {
return {
strength: strength,
variables: variables,
satisfy: satisfy_fn,
output: null
}
}
// Constraint propagation: simple forward solver
function propagate(vars, constraints) {
var changed = true
var passes = 0
var max_passes = length(constraints) * 3
var i = 0
var c = null
var old_val = 0
while (changed && passes < max_passes) {
changed = false
passes++
for (i = 0; i < length(constraints); i++) {
c = constraints[i]
old_val = c.output ? c.output.value : null
c.satisfy(c)
if (c.output && c.output.value != old_val) {
changed = true
}
}
}
return passes
}
// Build a chain of equality constraints: v[i] = v[i-1] + 1
function build_chain(n) {
var vars = []
var constraints = []
var i = 0
for (i = 0; i < n; i++) {
push(vars, make_variable(`v${i}`, 0))
}
// Set first variable
vars[0].value = 1
var c = null
for (i = 1; i < n; i++) {
c = make_constraint(NORMAL, [vars[i - 1], vars[i]], function(self) {
self.variables[1].value = self.variables[0].value + 1
self.output = self.variables[1]
})
push(constraints, c)
push(vars[i].constraints, c)
}
return {vars: vars, constraints: constraints}
}
// Build a projection: pairs of variables with scaling constraints
function build_projection(n) {
var src = []
var dst = []
var constraints = []
var i = 0
for (i = 0; i < n; i++) {
push(src, make_variable(`src${i}`, i * 10))
push(dst, make_variable(`dst${i}`, 0))
}
var scale_c = null
for (i = 0; i < n; i++) {
scale_c = make_constraint(STRONG, [src[i], dst[i]], function(self) {
self.variables[1].value = self.variables[0].value * 2 + 1
self.output = self.variables[1]
})
push(constraints, scale_c)
push(dst[i].constraints, scale_c)
}
return {src: src, dst: dst, constraints: constraints}
}
// Edit constraint: change a source, re-propagate
function run_edits(system, edits) {
var i = 0
var total_passes = 0
for (i = 0; i < edits; i++) {
system.vars[0].value = i
total_passes += propagate(system.vars, system.constraints)
}
return total_passes
}
return {
// Chain of 100 variables, propagate
chain_100: function(n) {
var i = 0
var chain = null
var x = 0
for (i = 0; i < n; i++) {
chain = build_chain(100)
x += propagate(chain.vars, chain.constraints)
}
return x
},
// Chain of 500 variables, propagate
chain_500: function(n) {
var i = 0
var chain = null
var x = 0
for (i = 0; i < n; i++) {
chain = build_chain(500)
x += propagate(chain.vars, chain.constraints)
}
return x
},
// Projection of 100 pairs
projection_100: function(n) {
var i = 0
var proj = null
var x = 0
for (i = 0; i < n; i++) {
proj = build_projection(100)
x += propagate(proj.src, proj.constraints)
}
return x
},
// Edit and re-propagate (incremental update)
chain_edit_100: function(n) {
var chain = build_chain(100)
var i = 0
var x = 0
for (i = 0; i < n; i++) {
chain.vars[0].value = i
x += propagate(chain.vars, chain.constraints)
}
return x
}
}

126
benches/fibonacci.cm Normal file
View File

@@ -0,0 +1,126 @@
// fibonacci.cm — Fibonacci variants kernel
// Tests recursion overhead, memoization patterns, iteration vs recursion.
// Naive recursive (exponential) — measures call overhead
function fib_naive(n) {
if (n <= 1) return n
return fib_naive(n - 1) + fib_naive(n - 2)
}
// Iterative (linear)
function fib_iter(n) {
var a = 0
var b = 1
var i = 0
var tmp = 0
for (i = 0; i < n; i++) {
tmp = a + b
a = b
b = tmp
}
return a
}
// Memoized recursive (tests object property lookup + recursion)
function make_memo_fib() {
var cache = {}
var fib = function(n) {
var key = text(n)
if (cache[key]) return cache[key]
var result = null
if (n <= 1) {
result = n
} else {
result = fib(n - 1) + fib(n - 2)
}
cache[key] = result
return result
}
return fib
}
// CPS (continuation passing style) — tests closure creation
function fib_cps(n, cont) {
if (n <= 1) return cont(n)
return fib_cps(n - 1, function(a) {
return fib_cps(n - 2, function(b) {
return cont(a + b)
})
})
}
// Matrix exponentiation style (accumulator)
function fib_matrix(n) {
var a = 1
var b = 0
var c = 0
var d = 1
var ta = 0
var tb = 0
var m = n
while (m > 0) {
if (m % 2 == 1) {
ta = a * d + b * c // wrong but stresses numeric ops
tb = b * d + a * c
a = ta
b = tb
}
ta = c * c + d * d
tb = d * (2 * c + d)
c = ta
d = tb
m = floor(m / 2)
}
return b
}
return {
fib_naive_25: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) x += fib_naive(25)
return x
},
fib_naive_30: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) x += fib_naive(30)
return x
},
fib_iter_80: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) x += fib_iter(80)
return x
},
fib_memo_100: function(n) {
var i = 0
var x = 0
var fib = null
for (i = 0; i < n; i++) {
fib = make_memo_fib()
x += fib(100)
}
return x
},
fib_cps_20: function(n) {
var i = 0
var x = 0
var identity = function(v) { return v }
for (i = 0; i < n; i++) {
x += fib_cps(20, identity)
}
return x
},
fib_matrix_80: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) x += fib_matrix(80)
return x
}
}

159
benches/hash_workload.cm Normal file
View File

@@ -0,0 +1,159 @@
// hash_workload.cm — Hash-heavy / word-count / map-reduce kernel
// Stresses record (object) creation, property access, and string handling.
function make_words(count) {
// Generate a repeating word list to simulate text processing
var base_words = [
"the", "quick", "brown", "fox", "jumps", "over", "lazy", "dog",
"and", "cat", "sat", "on", "mat", "with", "hat", "bat",
"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta",
"hello", "world", "foo", "bar", "baz", "qux", "quux", "corge"
]
var words = []
var i = 0
for (i = 0; i < count; i++) {
push(words, base_words[i % length(base_words)])
}
return words
}
// Word frequency count
function word_count(words) {
var freq = {}
var i = 0
var w = null
for (i = 0; i < length(words); i++) {
w = words[i]
if (freq[w]) {
freq[w] = freq[w] + 1
} else {
freq[w] = 1
}
}
return freq
}
// Find top-N words by frequency
function top_n(freq, n) {
var keys = array(freq)
var pairs = []
var i = 0
for (i = 0; i < length(keys); i++) {
push(pairs, {word: keys[i], count: freq[keys[i]]})
}
var sorted = sort(pairs, "count")
// Return last N (highest counts)
var result = []
var start = length(sorted) - n
if (start < 0) start = 0
for (i = start; i < length(sorted); i++) {
push(result, sorted[i])
}
return result
}
// Histogram: group words by length
function group_by_length(words) {
var groups = {}
var i = 0
var w = null
var k = null
for (i = 0; i < length(words); i++) {
w = words[i]
k = text(length(w))
if (!groups[k]) groups[k] = []
push(groups[k], w)
}
return groups
}
// Simple hash table with chaining (stress property access patterns)
function hash_table_ops(n) {
var table = {}
var i = 0
var k = null
var collisions = 0
// Insert phase
for (i = 0; i < n; i++) {
k = `key_${i % 512}`
if (table[k]) collisions++
table[k] = i
}
// Lookup phase
var found = 0
for (i = 0; i < n; i++) {
k = `key_${i % 512}`
if (table[k]) found++
}
// Delete phase
var deleted = 0
for (i = 0; i < n; i += 3) {
k = `key_${i % 512}`
if (table[k]) {
delete table[k]
deleted++
}
}
return found - deleted + collisions
}
var words_1k = make_words(1000)
var words_10k = make_words(10000)
return {
// Word count on 1K words
wordcount_1k: function(n) {
var i = 0
var freq = null
for (i = 0; i < n; i++) {
freq = word_count(words_1k)
}
return freq
},
// Word count on 10K words
wordcount_10k: function(n) {
var i = 0
var freq = null
for (i = 0; i < n; i++) {
freq = word_count(words_10k)
}
return freq
},
// Word count + top-10 extraction
wordcount_top10: function(n) {
var i = 0
var freq = null
var top = null
for (i = 0; i < n; i++) {
freq = word_count(words_10k)
top = top_n(freq, 10)
}
return top
},
// Group words by length
group_by_len: function(n) {
var i = 0
var groups = null
for (i = 0; i < n; i++) {
groups = group_by_length(words_10k)
}
return groups
},
// Hash table insert/lookup/delete
hash_table: function(n) {
var i = 0
var x = 0
for (i = 0; i < n; i++) {
x += hash_table_ops(2048)
}
return x
}
}

167
benches/json_walk.cm Normal file
View File

@@ -0,0 +1,167 @@
// json_walk.cm — JSON parse + walk + serialize kernel
// Stresses strings, records, arrays, and recursive traversal.
var json = use('json')
function make_nested_object(depth, breadth) {
var obj = {}
var i = 0
var k = null
if (depth <= 0) {
for (i = 0; i < breadth; i++) {
k = `key_${i}`
obj[k] = i * 3.14
}
return obj
}
for (i = 0; i < breadth; i++) {
k = `node_${i}`
obj[k] = make_nested_object(depth - 1, breadth)
}
obj.value = depth
obj.name = `level_${depth}`
return obj
}
function make_array_data(size) {
var arr = []
var i = 0
for (i = 0; i < size; i++) {
push(arr, {
id: i,
name: `item_${i}`,
active: i % 2 == 0,
score: i * 1.5,
tags: [`tag_${i % 5}`, `tag_${(i + 1) % 5}`]
})
}
return arr
}
// Walk an object tree, counting nodes
function walk_count(obj) {
var count = 1
var keys = null
var i = 0
var v = null
if (is_object(obj)) {
keys = array(obj)
for (i = 0; i < length(keys); i++) {
v = obj[keys[i]]
if (is_object(v) || is_array(v)) {
count += walk_count(v)
}
}
} else if (is_array(obj)) {
for (i = 0; i < length(obj); i++) {
v = obj[i]
if (is_object(v) || is_array(v)) {
count += walk_count(v)
}
}
}
return count
}
// Walk and extract all numbers
function walk_sum(obj) {
var sum = 0
var keys = null
var i = 0
var v = null
if (is_object(obj)) {
keys = array(obj)
for (i = 0; i < length(keys); i++) {
v = obj[keys[i]]
if (is_number(v)) {
sum += v
} else if (is_object(v) || is_array(v)) {
sum += walk_sum(v)
}
}
} else if (is_array(obj)) {
for (i = 0; i < length(obj); i++) {
v = obj[i]
if (is_number(v)) {
sum += v
} else if (is_object(v) || is_array(v)) {
sum += walk_sum(v)
}
}
}
return sum
}
// Pre-build test data strings
var nested_obj = make_nested_object(3, 4)
var nested_json = json.encode(nested_obj)
var array_data = make_array_data(200)
var array_json = json.encode(array_data)
return {
// Parse nested JSON
json_parse_nested: function(n) {
var i = 0
var obj = null
for (i = 0; i < n; i++) {
obj = json.decode(nested_json)
}
return obj
},
// Parse array-of-records JSON
json_parse_array: function(n) {
var i = 0
var arr = null
for (i = 0; i < n; i++) {
arr = json.decode(array_json)
}
return arr
},
// Encode nested object to JSON
json_encode_nested: function(n) {
var i = 0
var s = null
for (i = 0; i < n; i++) {
s = json.encode(nested_obj)
}
return s
},
// Encode array to JSON
json_encode_array: function(n) {
var i = 0
var s = null
for (i = 0; i < n; i++) {
s = json.encode(array_data)
}
return s
},
// Parse + walk + count
json_roundtrip_walk: function(n) {
var i = 0
var obj = null
var count = 0
for (i = 0; i < n; i++) {
obj = json.decode(nested_json)
count += walk_count(obj)
}
return count
},
// Parse + sum all numbers + re-encode
json_roundtrip_full: function(n) {
var i = 0
var obj = null
var sum = 0
var out = null
for (i = 0; i < n; i++) {
obj = json.decode(array_json)
sum += walk_sum(obj)
out = json.encode(obj)
}
return sum
}
}

494
benches/micro_ops.cm Normal file
View File

@@ -0,0 +1,494 @@
// micro_ops.cm — microbenchmarks for core operations
function blackhole(sink, x) {
return (sink + (x | 0)) | 0
}
function make_obj_xy(x, y) {
return {x: x, y: y}
}
function make_obj_yx(x, y) {
// Different insertion order to force a different shape
return {y: y, x: x}
}
function make_shapes(n) {
var out = []
var i = 0
var o = null
for (i = 0; i < n; i++) {
o = {a: i}
o[`p${i}`] = i
push(out, o)
}
return out
}
function make_packed_array(n) {
var a = []
var i = 0
for (i = 0; i < n; i++) push(a, i)
return a
}
function make_holey_array(n) {
var a = []
var i = 0
for (i = 0; i < n; i += 2) a[i] = i
return a
}
return {
// 0) Baseline loop cost
loop_empty: function(n) {
var sink = 0
var i = 0
for (i = 0; i < n; i++) {}
return blackhole(sink, n)
},
// 1) Numeric pipelines
i32_add: function(n) {
var sink = 0
var x = 1
var i = 0
for (i = 0; i < n; i++) x = (x + 3) | 0
return blackhole(sink, x)
},
f64_add: function(n) {
var sink = 0
var x = 1.0
var i = 0
for (i = 0; i < n; i++) x = x + 3.14159
return blackhole(sink, x | 0)
},
mixed_add: function(n) {
var sink = 0
var x = 1
var i = 0
for (i = 0; i < n; i++) x = x + 0.25
return blackhole(sink, x | 0)
},
bit_ops: function(n) {
var sink = 0
var x = 0x12345678
var i = 0
for (i = 0; i < n; i++) x = ((x << 5) ^ (x >>> 3)) | 0
return blackhole(sink, x)
},
overflow_path: function(n) {
var sink = 0
var x = 0x70000000
var i = 0
for (i = 0; i < n; i++) x = (x + 0x10000000) | 0
return blackhole(sink, x)
},
// 2) Branching
branch_predictable: function(n) {
var sink = 0
var x = 0
var i = 0
for (i = 0; i < n; i++) {
if ((i & 7) != 0) x++
else x += 2
}
return blackhole(sink, x)
},
branch_alternating: function(n) {
var sink = 0
var x = 0
var i = 0
for (i = 0; i < n; i++) {
if ((i & 1) == 0) x++
else x += 2
}
return blackhole(sink, x)
},
// 3) Calls
call_direct: function(n) {
var sink = 0
var f = function(a) { return (a + 1) | 0 }
var x = 0
var i = 0
for (i = 0; i < n; i++) x = f(x)
return blackhole(sink, x)
},
call_indirect: function(n) {
var sink = 0
var f = function(a) { return (a + 1) | 0 }
var g = f
var x = 0
var i = 0
for (i = 0; i < n; i++) x = g(x)
return blackhole(sink, x)
},
call_closure: function(n) {
var sink = 0
var make_adder = function(k) {
return function(a) { return (a + k) | 0 }
}
var add3 = make_adder(3)
var x = 0
var i = 0
for (i = 0; i < n; i++) x = add3(x)
return blackhole(sink, x)
},
call_multi_arity: function(n) {
var sink = 0
var f0 = function() { return 1 }
var f1 = function(a) { return a + 1 }
var f2 = function(a, b) { return a + b }
var f3 = function(a, b, c) { return a + b + c }
var f4 = function(a, b, c, d) { return a + b + c + d }
var x = 0
var i = 0
for (i = 0; i < n; i++) {
x = (x + f0() + f1(i) + f2(i, 1) + f3(i, 1, 2) + f4(i, 1, 2, 3)) | 0
}
return blackhole(sink, x)
},
// 4) Object props (ICs / shapes)
prop_read_mono: function(n) {
var sink = 0
var o = make_obj_xy(1, 2)
var x = 0
var i = 0
for (i = 0; i < n; i++) x = (x + o.x) | 0
return blackhole(sink, x)
},
prop_read_poly_2: function(n) {
var sink = 0
var a = make_obj_xy(1, 2)
var b = make_obj_yx(1, 2)
var x = 0
var i = 0
var o = null
for (i = 0; i < n; i++) {
o = (i & 1) == 0 ? a : b
x = (x + o.x) | 0
}
return blackhole(sink, x)
},
prop_read_poly_4: function(n) {
var sink = 0
var shapes = [
{x: 1, y: 2},
{y: 2, x: 1},
{x: 1, z: 3, y: 2},
{w: 0, x: 1, y: 2}
]
var x = 0
var i = 0
for (i = 0; i < n; i++) {
x = (x + shapes[i & 3].x) | 0
}
return blackhole(sink, x)
},
prop_read_mega: function(n) {
var sink = 0
var objs = make_shapes(32)
var x = 0
var i = 0
for (i = 0; i < n; i++) {
x = (x + objs[i & 31].a) | 0
}
return blackhole(sink, x)
},
prop_write_mono: function(n) {
var sink = 0
var o = make_obj_xy(1, 2)
var i = 0
for (i = 0; i < n; i++) o.x = (o.x + 1) | 0
return blackhole(sink, o.x)
},
// 5) Arrays
array_read_packed: function(n) {
var sink = 0
var a = make_packed_array(1024)
var x = 0
var i = 0
for (i = 0; i < n; i++) x = (x + a[i & 1023]) | 0
return blackhole(sink, x)
},
array_write_packed: function(n) {
var sink = 0
var a = make_packed_array(1024)
var i = 0
for (i = 0; i < n; i++) a[i & 1023] = i
return blackhole(sink, a[17] | 0)
},
array_read_holey: function(n) {
var sink = 0
var a = make_holey_array(2048)
var x = 0
var i = 0
var v = null
for (i = 0; i < n; i++) {
v = a[(i & 2047)]
if (v) x = (x + v) | 0
}
return blackhole(sink, x)
},
array_push_steady: function(n) {
var sink = 0
var x = 0
var j = 0
var i = 0
var a = null
for (j = 0; j < n; j++) {
a = []
for (i = 0; i < 256; i++) push(a, i)
x = (x + length(a)) | 0
}
return blackhole(sink, x)
},
array_push_pop: function(n) {
var sink = 0
var a = []
var x = 0
var i = 0
var v = 0
for (i = 0; i < n; i++) {
push(a, i)
if (length(a) > 64) {
v = pop(a)
x = (x + v) | 0
}
}
return blackhole(sink, x)
},
array_indexed_sum: function(n) {
var sink = 0
var a = make_packed_array(1024)
var x = 0
var j = 0
var i = 0
for (j = 0; j < n; j++) {
x = 0
for (i = 0; i < 1024; i++) {
x = (x + a[i]) | 0
}
}
return blackhole(sink, x)
},
// 6) Strings
string_concat_small: function(n) {
var sink = 0
var x = 0
var j = 0
var i = 0
var s = null
for (j = 0; j < n; j++) {
s = ""
for (i = 0; i < 16; i++) s = s + "x"
x = (x + length(s)) | 0
}
return blackhole(sink, x)
},
string_concat_medium: function(n) {
var sink = 0
var x = 0
var j = 0
var i = 0
var s = null
for (j = 0; j < n; j++) {
s = ""
for (i = 0; i < 100; i++) s = s + "abcdefghij"
x = (x + length(s)) | 0
}
return blackhole(sink, x)
},
string_interpolation: function(n) {
var sink = 0
var x = 0
var i = 0
var s = null
for (i = 0; i < n; i++) {
s = `item_${i}_value_${i * 2}`
x = (x + length(s)) | 0
}
return blackhole(sink, x)
},
string_slice: function(n) {
var sink = 0
var base = "the quick brown fox jumps over the lazy dog"
var x = 0
var i = 0
var s = null
for (i = 0; i < n; i++) {
s = text(base, i % 10, i % 10 + 10)
x = (x + length(s)) | 0
}
return blackhole(sink, x)
},
// 7) Allocation / GC pressure
alloc_tiny_objects: function(n) {
var sink = 0
var x = 0
var i = 0
var o = null
for (i = 0; i < n; i++) {
o = {a: i, b: i + 1, c: i + 2}
x = (x + o.b) | 0
}
return blackhole(sink, x)
},
alloc_linked_list: function(n) {
var sink = 0
var head = null
var i = 0
var x = 0
var p = null
for (i = 0; i < n; i++) head = {v: i, next: head}
x = 0
p = head
while (p) {
x = (x + p.v) | 0
p = p.next
}
return blackhole(sink, x)
},
alloc_arrays: function(n) {
var sink = 0
var x = 0
var i = 0
var a = null
for (i = 0; i < n; i++) {
a = [i, i + 1, i + 2, i + 3]
x = (x + a[2]) | 0
}
return blackhole(sink, x)
},
alloc_short_lived: function(n) {
var sink = 0
var x = 0
var i = 0
var o = null
// Allocate objects that immediately become garbage
for (i = 0; i < n; i++) {
o = {val: i, data: {inner: i + 1}}
x = (x + o.data.inner) | 0
}
return blackhole(sink, x)
},
alloc_long_lived_pressure: function(n) {
var sink = 0
var store = []
var x = 0
var i = 0
var o = null
// Keep first 1024 objects alive, churn the rest
for (i = 0; i < n; i++) {
o = {val: i, data: i * 2}
if (i < 1024) {
push(store, o)
}
x = (x + o.data) | 0
}
return blackhole(sink, x)
},
// 8) Meme (prototype clone)
meme_clone_read: function(n) {
var sink = 0
var base = {x: 1, y: 2}
var x = 0
var i = 0
var o = null
for (i = 0; i < n; i++) {
o = meme(base)
x = (x + o.x) | 0
}
return blackhole(sink, x)
},
// 9) Guard / type check paths
guard_hot_number: function(n) {
// Monomorphic number path — guards should hoist
var sink = 0
var x = 1
var i = 0
for (i = 0; i < n; i++) x = x + 1
return blackhole(sink, x | 0)
},
guard_mixed_types: function(n) {
// Alternating number/text — guards must stay
var sink = 0
var vals = [1, "a", 2, "b", 3, "c", 4, "d"]
var x = 0
var i = 0
for (i = 0; i < n; i++) {
if (is_number(vals[i & 7])) x = (x + vals[i & 7]) | 0
}
return blackhole(sink, x)
},
// 10) Reduce / higher-order
reduce_sum: function(n) {
var sink = 0
var a = make_packed_array(256)
var x = 0
var i = 0
for (i = 0; i < n; i++) {
x = (x + reduce(a, function(acc, v) { return acc + v }, 0)) | 0
}
return blackhole(sink, x)
},
filter_evens: function(n) {
var sink = 0
var a = make_packed_array(256)
var x = 0
var i = 0
for (i = 0; i < n; i++) {
x = (x + length(filter(a, function(v) { return v % 2 == 0 }))) | 0
}
return blackhole(sink, x)
},
arrfor_sum: function(n) {
var sink = 0
var a = make_packed_array(256)
var x = 0
var i = 0
var sum = 0
for (i = 0; i < n; i++) {
sum = 0
arrfor(a, function(v) { sum += v })
x = (x + sum) | 0
}
return blackhole(sink, x)
}
}

249
benches/module_load.cm Normal file
View File

@@ -0,0 +1,249 @@
// module_load.cm — Module loading simulation (macro benchmark)
// Simulates parsing many small modules, linking, and running.
// Tests the "build scenario" pattern.
var json = use('json')
// Simulate a small module: parse token stream + build AST + evaluate
function tokenize(src) {
var tokens = []
var i = 0
var ch = null
var chars = array(src)
var buf = ""
for (i = 0; i < length(chars); i++) {
ch = chars[i]
if (ch == " " || ch == "\n" || ch == "\t") {
if (length(buf) > 0) {
push(tokens, buf)
buf = ""
}
} else if (ch == "(" || ch == ")" || ch == "+" || ch == "-"
|| ch == "*" || ch == "=" || ch == ";" || ch == ",") {
if (length(buf) > 0) {
push(tokens, buf)
buf = ""
}
push(tokens, ch)
} else {
buf = buf + ch
}
}
if (length(buf) > 0) push(tokens, buf)
return tokens
}
// Build a simple AST from tokens
function parse_tokens(tokens) {
var ast = []
var i = 0
var tok = null
var node = null
for (i = 0; i < length(tokens); i++) {
tok = tokens[i]
if (tok == "var" || tok == "def") {
node = {type: "decl", kind: tok, name: null, value: null}
i++
if (i < length(tokens)) node.name = tokens[i]
i++ // skip =
i++
if (i < length(tokens)) node.value = tokens[i]
push(ast, node)
} else if (tok == "return") {
node = {type: "return", value: null}
i++
if (i < length(tokens)) node.value = tokens[i]
push(ast, node)
} else if (tok == "function") {
node = {type: "func", name: null, body: []}
i++
if (i < length(tokens)) node.name = tokens[i]
// Skip to matching )
while (i < length(tokens) && tokens[i] != ")") i++
push(ast, node)
} else {
push(ast, {type: "expr", value: tok})
}
}
return ast
}
// Evaluate: simple symbol table + resolution
function evaluate(ast, env) {
var result = null
var i = 0
var node = null
for (i = 0; i < length(ast); i++) {
node = ast[i]
if (node.type == "decl") {
env[node.name] = node.value
} else if (node.type == "return") {
result = node.value
if (env[result]) result = env[result]
} else if (node.type == "func") {
env[node.name] = node
}
}
return result
}
// Generate fake module source code
function generate_module(id, dep_count) {
var src = ""
var i = 0
src = src + "var _id = " + text(id) + ";\n"
for (i = 0; i < dep_count; i++) {
src = src + "var dep" + text(i) + " = use(mod_" + text(i) + ");\n"
}
src = src + "var x = " + text(id * 17) + ";\n"
src = src + "var y = " + text(id * 31) + ";\n"
src = src + "function compute(a, b) { return a + b; }\n"
src = src + "var result = compute(x, y);\n"
src = src + "return result;\n"
return src
}
// Simulate loading N modules with dependency chains
function simulate_build(n_modules, deps_per_module) {
var modules = []
var loaded = {}
var i = 0
var j = 0
var src = null
var tokens = null
var ast = null
var env = null
var result = null
var total_tokens = 0
var total_nodes = 0
// Generate all module sources
for (i = 0; i < n_modules; i++) {
src = generate_module(i, deps_per_module)
push(modules, src)
}
// "Load" each module: tokenize → parse → evaluate
for (i = 0; i < n_modules; i++) {
tokens = tokenize(modules[i])
total_tokens += length(tokens)
ast = parse_tokens(tokens)
total_nodes += length(ast)
env = {}
// Resolve dependencies
for (j = 0; j < deps_per_module; j++) {
if (j < i) {
env["dep" + text(j)] = loaded["mod_" + text(j)]
}
}
result = evaluate(ast, env)
loaded["mod_" + text(i)] = result
}
return {
modules: n_modules,
total_tokens: total_tokens,
total_nodes: total_nodes,
last_result: result
}
}
// Dependency graph analysis (topological sort simulation)
function topo_sort(n_modules, deps_per_module) {
// Build adjacency list
var adj = {}
var in_degree = {}
var i = 0
var j = 0
var name = null
var dep = null
for (i = 0; i < n_modules; i++) {
name = "mod_" + text(i)
adj[name] = []
in_degree[name] = 0
}
for (i = 0; i < n_modules; i++) {
name = "mod_" + text(i)
for (j = 0; j < deps_per_module; j++) {
if (j < i) {
dep = "mod_" + text(j)
push(adj[dep], name)
in_degree[name] = in_degree[name] + 1
}
}
}
// Kahn's algorithm
var queue = []
var keys = array(in_degree)
for (i = 0; i < length(keys); i++) {
if (in_degree[keys[i]] == 0) push(queue, keys[i])
}
var order = []
var current = null
var neighbors = null
var qi = 0
while (qi < length(queue)) {
current = queue[qi]
qi++
push(order, current)
neighbors = adj[current]
if (neighbors) {
for (i = 0; i < length(neighbors); i++) {
in_degree[neighbors[i]] = in_degree[neighbors[i]] - 1
if (in_degree[neighbors[i]] == 0) push(queue, neighbors[i])
}
}
}
return order
}
return {
// Small build: 50 modules, 3 deps each
build_50: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = simulate_build(50, 3)
}
return result
},
// Medium build: 200 modules, 5 deps each
build_200: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = simulate_build(200, 5)
}
return result
},
// Large build: 500 modules, 5 deps each
build_500: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = simulate_build(500, 5)
}
return result
},
// Topo sort of 500 module dependency graph
topo_sort_500: function(n) {
var i = 0
var order = null
for (i = 0; i < n; i++) {
order = topo_sort(500, 5)
}
return order
}
}

160
benches/nbody.cm Normal file
View File

@@ -0,0 +1,160 @@
// nbody.cm — N-body gravitational simulation kernel
// Pure numeric + allocation workload. Classic VM benchmark.
var math = use('math/radians')
def PI = 3.141592653589793
def SOLAR_MASS = 4 * PI * PI
def DAYS_PER_YEAR = 365.24
function make_system() {
// Sun + 4 Jovian planets
var sun = {x: 0, y: 0, z: 0, vx: 0, vy: 0, vz: 0, mass: SOLAR_MASS}
var jupiter = {
x: 4.84143144246472090,
y: -1.16032004402742839,
z: -0.103622044471123109,
vx: 0.00166007664274403694 * DAYS_PER_YEAR,
vy: 0.00769901118419740425 * DAYS_PER_YEAR,
vz: -0.0000690460016972063023 * DAYS_PER_YEAR,
mass: 0.000954791938424326609 * SOLAR_MASS
}
var saturn = {
x: 8.34336671824457987,
y: 4.12479856412430479,
z: -0.403523417114321381,
vx: -0.00276742510726862411 * DAYS_PER_YEAR,
vy: 0.00499852801234917238 * DAYS_PER_YEAR,
vz: 0.0000230417297573763929 * DAYS_PER_YEAR,
mass: 0.000285885980666130812 * SOLAR_MASS
}
var uranus = {
x: 12.8943695621391310,
y: -15.1111514016986312,
z: -0.223307578892655734,
vx: 0.00296460137564761618 * DAYS_PER_YEAR,
vy: 0.00237847173959480950 * DAYS_PER_YEAR,
vz: -0.0000296589568540237556 * DAYS_PER_YEAR,
mass: 0.0000436624404335156298 * SOLAR_MASS
}
var neptune = {
x: 15.3796971148509165,
y: -25.9193146099879641,
z: 0.179258772950371181,
vx: 0.00268067772490389322 * DAYS_PER_YEAR,
vy: 0.00162824170038242295 * DAYS_PER_YEAR,
vz: -0.0000951592254519715870 * DAYS_PER_YEAR,
mass: 0.0000515138902046611451 * SOLAR_MASS
}
var bodies = [sun, jupiter, saturn, uranus, neptune]
// Offset momentum
var px = 0
var py = 0
var pz = 0
var i = 0
for (i = 0; i < length(bodies); i++) {
px += bodies[i].vx * bodies[i].mass
py += bodies[i].vy * bodies[i].mass
pz += bodies[i].vz * bodies[i].mass
}
sun.vx = -px / SOLAR_MASS
sun.vy = -py / SOLAR_MASS
sun.vz = -pz / SOLAR_MASS
return bodies
}
function advance(bodies, dt) {
var n = length(bodies)
var i = 0
var j = 0
var bi = null
var bj = null
var dx = 0
var dy = 0
var dz = 0
var dist_sq = 0
var dist = 0
var mag = 0
for (i = 0; i < n; i++) {
bi = bodies[i]
for (j = i + 1; j < n; j++) {
bj = bodies[j]
dx = bi.x - bj.x
dy = bi.y - bj.y
dz = bi.z - bj.z
dist_sq = dx * dx + dy * dy + dz * dz
dist = math.sqrt(dist_sq)
mag = dt / (dist_sq * dist)
bi.vx -= dx * bj.mass * mag
bi.vy -= dy * bj.mass * mag
bi.vz -= dz * bj.mass * mag
bj.vx += dx * bi.mass * mag
bj.vy += dy * bi.mass * mag
bj.vz += dz * bi.mass * mag
}
}
for (i = 0; i < n; i++) {
bi = bodies[i]
bi.x += dt * bi.vx
bi.y += dt * bi.vy
bi.z += dt * bi.vz
}
}
function energy(bodies) {
var e = 0
var n = length(bodies)
var i = 0
var j = 0
var bi = null
var bj = null
var dx = 0
var dy = 0
var dz = 0
for (i = 0; i < n; i++) {
bi = bodies[i]
e += 0.5 * bi.mass * (bi.vx * bi.vx + bi.vy * bi.vy + bi.vz * bi.vz)
for (j = i + 1; j < n; j++) {
bj = bodies[j]
dx = bi.x - bj.x
dy = bi.y - bj.y
dz = bi.z - bj.z
e -= (bi.mass * bj.mass) / math.sqrt(dx * dx + dy * dy + dz * dz)
}
}
return e
}
return {
nbody_1k: function(n) {
var i = 0
var j = 0
var bodies = null
for (i = 0; i < n; i++) {
bodies = make_system()
for (j = 0; j < 1000; j++) advance(bodies, 0.01)
energy(bodies)
}
},
nbody_10k: function(n) {
var i = 0
var j = 0
var bodies = null
for (i = 0; i < n; i++) {
bodies = make_system()
for (j = 0; j < 10000; j++) advance(bodies, 0.01)
energy(bodies)
}
}
}

154
benches/ray_tracer.cm Normal file
View File

@@ -0,0 +1,154 @@
// ray_tracer.cm — Simple ray tracer kernel
// Control flow + numeric + allocation. Classic VM benchmark.
var math = use('math/radians')
function vec(x, y, z) {
return {x: x, y: y, z: z}
}
function vadd(a, b) {
return {x: a.x + b.x, y: a.y + b.y, z: a.z + b.z}
}
function vsub(a, b) {
return {x: a.x - b.x, y: a.y - b.y, z: a.z - b.z}
}
function vmul(v, s) {
return {x: v.x * s, y: v.y * s, z: v.z * s}
}
function vdot(a, b) {
return a.x * b.x + a.y * b.y + a.z * b.z
}
function vnorm(v) {
var len = math.sqrt(vdot(v, v))
if (len == 0) return vec(0, 0, 0)
return vmul(v, 1 / len)
}
function make_sphere(center, radius, color) {
return {
center: center,
radius: radius,
color: color
}
}
function intersect_sphere(origin, dir, sphere) {
var oc = vsub(origin, sphere.center)
var b = vdot(oc, dir)
var c = vdot(oc, oc) - sphere.radius * sphere.radius
var disc = b * b - c
if (disc < 0) return -1
var sq = math.sqrt(disc)
var t1 = -b - sq
var t2 = -b + sq
if (t1 > 0.001) return t1
if (t2 > 0.001) return t2
return -1
}
function make_scene() {
var spheres = [
make_sphere(vec(0, -1, 5), 1, vec(1, 0, 0)),
make_sphere(vec(2, 0, 6), 1, vec(0, 1, 0)),
make_sphere(vec(-2, 0, 4), 1, vec(0, 0, 1)),
make_sphere(vec(0, 1, 4.5), 0.5, vec(1, 1, 0)),
make_sphere(vec(1, -0.5, 3), 0.3, vec(1, 0, 1)),
make_sphere(vec(0, -101, 5), 100, vec(0.5, 0.5, 0.5))
]
var light = vnorm(vec(1, 1, -1))
return {spheres: spheres, light: light}
}
function trace(origin, dir, scene) {
var closest_t = 999999
var closest_sphere = null
var i = 0
var t = 0
for (i = 0; i < length(scene.spheres); i++) {
t = intersect_sphere(origin, dir, scene.spheres[i])
if (t > 0 && t < closest_t) {
closest_t = t
closest_sphere = scene.spheres[i]
}
}
if (!closest_sphere) return vec(0.2, 0.3, 0.5) // sky color
var hit = vadd(origin, vmul(dir, closest_t))
var normal = vnorm(vsub(hit, closest_sphere.center))
var diffuse = vdot(normal, scene.light)
if (diffuse < 0) diffuse = 0
// Shadow check
var shadow_origin = vadd(hit, vmul(normal, 0.001))
var in_shadow = false
for (i = 0; i < length(scene.spheres); i++) {
if (scene.spheres[i] != closest_sphere) {
t = intersect_sphere(shadow_origin, scene.light, scene.spheres[i])
if (t > 0) {
in_shadow = true
break
}
}
}
var ambient = 0.15
var intensity = in_shadow ? ambient : ambient + diffuse * 0.85
return vmul(closest_sphere.color, intensity)
}
function render(width, height, scene) {
var aspect = width / height
var fov = 1.0
var total_r = 0
var total_g = 0
var total_b = 0
var y = 0
var x = 0
var u = 0
var v = 0
var dir = null
var color = null
var origin = vec(0, 0, 0)
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
u = (2 * (x + 0.5) / width - 1) * aspect * fov
v = (1 - 2 * (y + 0.5) / height) * fov
dir = vnorm(vec(u, v, 1))
color = trace(origin, dir, scene)
total_r += color.x
total_g += color.y
total_b += color.z
}
}
return {r: total_r, g: total_g, b: total_b}
}
var scene = make_scene()
return {
raytrace_32x32: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = render(32, 32, scene)
}
return result
},
raytrace_64x64: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = render(64, 64, scene)
}
return result
}
}

251
benches/richards.cm Normal file
View File

@@ -0,0 +1,251 @@
// richards.cm — Richards benchmark (scheduler simulation)
// Object-ish workload: dynamic dispatch, state machines, queuing.
def IDLE = 0
def WORKER = 1
def HANDLER_A = 2
def HANDLER_B = 3
def DEVICE_A = 4
def DEVICE_B = 5
def NUM_TASKS = 6
def TASK_RUNNING = 0
def TASK_WAITING = 1
def TASK_HELD = 2
def TASK_SUSPENDED = 3
function make_packet(link, id, kind) {
return {link: link, id: id, kind: kind, datum: 0, data: array(4, 0)}
}
function scheduler() {
var tasks = array(NUM_TASKS, null)
var current = null
var queue_count = 0
var hold_count = 0
var v1 = 0
var v2 = 0
var w_id = HANDLER_A
var w_datum = 0
var h_a_queue = null
var h_a_count = 0
var h_b_queue = null
var h_b_count = 0
var dev_a_pkt = null
var dev_b_pkt = null
var find_next = function() {
var best = null
var i = 0
for (i = 0; i < NUM_TASKS; i++) {
if (tasks[i] && tasks[i].state == TASK_RUNNING) {
if (!best || tasks[i].priority > best.priority) {
best = tasks[i]
}
}
}
return best
}
var hold_self = function() {
hold_count++
if (current) current.state = TASK_HELD
return find_next()
}
var release = function(id) {
var t = tasks[id]
if (!t) return find_next()
if (t.state == TASK_HELD) t.state = TASK_RUNNING
if (t.priority > (current ? current.priority : -1)) return t
return current
}
var queue_packet = function(pkt) {
var t = tasks[pkt.id]
var p = null
if (!t) return find_next()
queue_count++
pkt.link = null
pkt.id = current ? current.id : 0
if (!t.queue) {
t.queue = pkt
t.state = TASK_RUNNING
if (t.priority > (current ? current.priority : -1)) return t
} else {
p = t.queue
while (p.link) p = p.link
p.link = pkt
}
return current
}
// Idle task
tasks[IDLE] = {id: IDLE, priority: 0, queue: null, state: TASK_RUNNING,
hold_count: 0, queue_count: 0,
fn: function(pkt) {
v1--
if (v1 == 0) return hold_self()
if ((v2 & 1) == 0) {
v2 = v2 >> 1
return release(DEVICE_A)
}
v2 = (v2 >> 1) ^ 0xD008
return release(DEVICE_B)
}
}
// Worker task
tasks[WORKER] = {id: WORKER, priority: 1000, queue: null, state: TASK_SUSPENDED,
hold_count: 0, queue_count: 0,
fn: function(pkt) {
var i = 0
if (!pkt) return hold_self()
w_id = (w_id == HANDLER_A) ? HANDLER_B : HANDLER_A
pkt.id = w_id
pkt.datum = 0
for (i = 0; i < 4; i++) {
w_datum++
if (w_datum > 26) w_datum = 1
pkt.data[i] = 65 + w_datum
}
return queue_packet(pkt)
}
}
// Handler A
tasks[HANDLER_A] = {id: HANDLER_A, priority: 2000, queue: null, state: TASK_SUSPENDED,
hold_count: 0, queue_count: 0,
fn: function(pkt) {
var p = null
if (pkt) { h_a_queue = pkt; h_a_count++ }
if (h_a_queue) {
p = h_a_queue
h_a_queue = p.link
if (h_a_count < 3) return queue_packet(p)
return release(DEVICE_A)
}
return hold_self()
}
}
// Handler B
tasks[HANDLER_B] = {id: HANDLER_B, priority: 3000, queue: null, state: TASK_SUSPENDED,
hold_count: 0, queue_count: 0,
fn: function(pkt) {
var p = null
if (pkt) { h_b_queue = pkt; h_b_count++ }
if (h_b_queue) {
p = h_b_queue
h_b_queue = p.link
if (h_b_count < 3) return queue_packet(p)
return release(DEVICE_B)
}
return hold_self()
}
}
// Device A
tasks[DEVICE_A] = {id: DEVICE_A, priority: 4000, queue: null, state: TASK_SUSPENDED,
hold_count: 0, queue_count: 0,
fn: function(pkt) {
var p = null
if (pkt) { dev_a_pkt = pkt; return hold_self() }
if (dev_a_pkt) {
p = dev_a_pkt
dev_a_pkt = null
return queue_packet(p)
}
return hold_self()
}
}
// Device B
tasks[DEVICE_B] = {id: DEVICE_B, priority: 5000, queue: null, state: TASK_SUSPENDED,
hold_count: 0, queue_count: 0,
fn: function(pkt) {
var p = null
if (pkt) { dev_b_pkt = pkt; return hold_self() }
if (dev_b_pkt) {
p = dev_b_pkt
dev_b_pkt = null
return queue_packet(p)
}
return hold_self()
}
}
var run = function(iterations) {
var i = 0
var pkt1 = null
var pkt2 = null
var steps = 0
var pkt = null
var next = null
v1 = iterations
v2 = 0xBEEF
queue_count = 0
hold_count = 0
w_id = HANDLER_A
w_datum = 0
h_a_queue = null
h_a_count = 0
h_b_queue = null
h_b_count = 0
dev_a_pkt = null
dev_b_pkt = null
for (i = 0; i < NUM_TASKS; i++) {
if (tasks[i]) {
tasks[i].state = (i == IDLE) ? TASK_RUNNING : TASK_SUSPENDED
tasks[i].queue = null
}
}
pkt1 = make_packet(null, WORKER, 1)
pkt2 = make_packet(pkt1, WORKER, 1)
tasks[WORKER].queue = pkt2
tasks[WORKER].state = TASK_RUNNING
current = find_next()
while (current && steps < iterations * 10) {
pkt = current.queue
if (pkt) {
current.queue = pkt.link
current.queue_count++
}
next = current.fn(pkt)
if (next) current = next
else current = find_next()
steps++
}
return {queue_count: queue_count, hold_count: hold_count, steps: steps}
}
return {run: run}
}
return {
richards_100: function(n) {
var i = 0
var s = null
var result = null
for (i = 0; i < n; i++) {
s = scheduler()
result = s.run(100)
}
return result
},
richards_1k: function(n) {
var i = 0
var s = null
var result = null
for (i = 0; i < n; i++) {
s = scheduler()
result = s.run(1000)
}
return result
}
}

180
benches/sorting.cm Normal file
View File

@@ -0,0 +1,180 @@
// sorting.cm — Sorting and searching kernel
// Array manipulation, comparison-heavy, allocation patterns.
function make_random_array(n, seed) {
var a = []
var x = seed
var i = 0
for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(a, x % 10000)
}
return a
}
function make_descending(n) {
var a = []
var i = 0
for (i = n - 1; i >= 0; i--) push(a, i)
return a
}
// Manual quicksort (tests recursion + array mutation)
function qsort(arr, lo, hi) {
var i = lo
var j = hi
var pivot = arr[floor((lo + hi) / 2)]
var tmp = 0
if (lo >= hi) return null
while (i <= j) {
while (arr[i] < pivot) i++
while (arr[j] > pivot) j--
if (i <= j) {
tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
i++
j--
}
}
if (lo < j) qsort(arr, lo, j)
if (i < hi) qsort(arr, i, hi)
return null
}
// Merge sort (tests allocation + array creation)
function msort(arr) {
var n = length(arr)
if (n <= 1) return arr
var mid = floor(n / 2)
var left = msort(array(arr, 0, mid))
var right = msort(array(arr, mid, n))
return merge(left, right)
}
function merge(a, b) {
var result = []
var i = 0
var j = 0
while (i < length(a) && j < length(b)) {
if (a[i] <= b[j]) {
push(result, a[i])
i++
} else {
push(result, b[j])
j++
}
}
while (i < length(a)) {
push(result, a[i])
i++
}
while (j < length(b)) {
push(result, b[j])
j++
}
return result
}
// Binary search
function bsearch(arr, target) {
var lo = 0
var hi = length(arr) - 1
var mid = 0
while (lo <= hi) {
mid = floor((lo + hi) / 2)
if (arr[mid] == target) return mid
if (arr[mid] < target) lo = mid + 1
else hi = mid - 1
}
return -1
}
// Sort objects by field
function sort_records(n) {
var records = []
var x = 42
var i = 0
for (i = 0; i < n; i++) {
x = ((x * 1103515245 + 12345) & 0x7FFFFFFF) | 0
push(records, {id: i, score: x % 10000, name: `item_${i}`})
}
return sort(records, "score")
}
return {
// Quicksort 1K random integers
qsort_1k: function(n) {
var i = 0
var a = null
for (i = 0; i < n; i++) {
a = make_random_array(1000, i)
qsort(a, 0, length(a) - 1)
}
return a
},
// Quicksort 10K random integers
qsort_10k: function(n) {
var i = 0
var a = null
for (i = 0; i < n; i++) {
a = make_random_array(10000, i)
qsort(a, 0, length(a) - 1)
}
return a
},
// Merge sort 1K (allocation heavy)
msort_1k: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = msort(make_random_array(1000, i))
}
return result
},
// Built-in sort 1K
builtin_sort_1k: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = sort(make_random_array(1000, i))
}
return result
},
// Sort worst case (descending → ascending)
sort_worst_case: function(n) {
var i = 0
var a = null
for (i = 0; i < n; i++) {
a = make_descending(1000)
qsort(a, 0, length(a) - 1)
}
return a
},
// Binary search in sorted array
bsearch_1k: function(n) {
var sorted = make_random_array(1000, 42)
sorted = sort(sorted)
var found = 0
var i = 0
for (i = 0; i < n; i++) {
if (bsearch(sorted, sorted[i % 1000]) >= 0) found++
}
return found
},
// Sort records by field
sort_records_500: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = sort_records(500)
}
return result
}
}

82
benches/spectral_norm.cm Normal file
View File

@@ -0,0 +1,82 @@
// spectral_norm.cm — Spectral norm kernel
// Pure numeric, dense array access, mathematical computation.
var math = use('math/radians')
function eval_a(i, j) {
return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1)
}
function eval_a_times_u(n, u, au) {
var i = 0
var j = 0
var sum = 0
for (i = 0; i < n; i++) {
sum = 0
for (j = 0; j < n; j++) {
sum += eval_a(i, j) * u[j]
}
au[i] = sum
}
}
function eval_at_times_u(n, u, atu) {
var i = 0
var j = 0
var sum = 0
for (i = 0; i < n; i++) {
sum = 0
for (j = 0; j < n; j++) {
sum += eval_a(j, i) * u[j]
}
atu[i] = sum
}
}
function eval_ata_times_u(n, u, atau) {
var v = array(n, 0)
eval_a_times_u(n, u, v)
eval_at_times_u(n, v, atau)
}
function spectral_norm(n) {
var u = array(n, 1)
var v = array(n, 0)
var i = 0
var vbv = 0
var vv = 0
for (i = 0; i < 10; i++) {
eval_ata_times_u(n, u, v)
eval_ata_times_u(n, v, u)
}
vbv = 0
vv = 0
for (i = 0; i < n; i++) {
vbv += u[i] * v[i]
vv += v[i] * v[i]
}
return math.sqrt(vbv / vv)
}
return {
spectral_100: function(n) {
var i = 0
var result = 0
for (i = 0; i < n; i++) {
result = spectral_norm(100)
}
return result
},
spectral_200: function(n) {
var i = 0
var result = 0
for (i = 0; i < n; i++) {
result = spectral_norm(200)
}
return result
}
}

View File

@@ -0,0 +1,188 @@
// string_processing.cm — String-heavy kernel
// Concat, split, search, replace, interning path stress.
function make_lorem(paragraphs) {
var base = "Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua Ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat"
var result = ""
var i = 0
for (i = 0; i < paragraphs; i++) {
if (i > 0) result = result + " "
result = result + base
}
return result
}
// Build a lookup table from text
function build_index(txt) {
var words = array(txt, " ")
var index = {}
var i = 0
var w = null
for (i = 0; i < length(words); i++) {
w = words[i]
if (!index[w]) {
index[w] = []
}
push(index[w], i)
}
return index
}
// Levenshtein-like distance (simplified)
function edit_distance(a, b) {
var la = length(a)
var lb = length(b)
if (la == 0) return lb
if (lb == 0) return la
// Use flat array for 2 rows of DP matrix
var prev = array(lb + 1, 0)
var curr = array(lb + 1, 0)
var i = 0
var j = 0
var cost = 0
var del = 0
var ins = 0
var sub = 0
var tmp = null
var ca = array(a)
var cb = array(b)
for (j = 0; j <= lb; j++) prev[j] = j
for (i = 1; i <= la; i++) {
curr[0] = i
for (j = 1; j <= lb; j++) {
cost = ca[i - 1] == cb[j - 1] ? 0 : 1
del = prev[j] + 1
ins = curr[j - 1] + 1
sub = prev[j - 1] + cost
curr[j] = del
if (ins < curr[j]) curr[j] = ins
if (sub < curr[j]) curr[j] = sub
}
tmp = prev
prev = curr
curr = tmp
}
return prev[lb]
}
var lorem_5 = make_lorem(5)
var lorem_20 = make_lorem(20)
return {
// Split text into words and count
string_split_count: function(n) {
var i = 0
var words = null
var count = 0
for (i = 0; i < n; i++) {
words = array(lorem_5, " ")
count += length(words)
}
return count
},
// Build word index (split + hash + array ops)
string_index_build: function(n) {
var i = 0
var idx = null
for (i = 0; i < n; i++) {
idx = build_index(lorem_5)
}
return idx
},
// Search for substrings
string_search: function(n) {
var targets = ["dolor", "minim", "quis", "magna", "ipsum"]
var i = 0
var j = 0
var count = 0
for (i = 0; i < n; i++) {
for (j = 0; j < length(targets); j++) {
if (search(lorem_20, targets[j])) count++
}
}
return count
},
// Replace operations
string_replace: function(n) {
var i = 0
var result = null
for (i = 0; i < n; i++) {
result = replace(lorem_5, "dolor", "DOLOR")
result = replace(result, "ipsum", "IPSUM")
result = replace(result, "amet", "AMET")
}
return result
},
// String concatenation builder
string_builder: function(n) {
var i = 0
var j = 0
var s = null
var total = 0
for (i = 0; i < n; i++) {
s = ""
for (j = 0; j < 50; j++) {
s = s + "key=" + text(j) + "&value=" + text(j * 17) + "&"
}
total += length(s)
}
return total
},
// Edit distance (DP + array + string ops)
edit_distance: function(n) {
var words = ["kitten", "sitting", "saturday", "sunday", "intention", "execution"]
var i = 0
var j = 0
var total = 0
for (i = 0; i < n; i++) {
for (j = 0; j < length(words) - 1; j++) {
total += edit_distance(words[j], words[j + 1])
}
}
return total
},
// Upper/lower/trim chain
string_transforms: function(n) {
var src = " Hello World "
var i = 0
var x = 0
var result = null
for (i = 0; i < n; i++) {
result = trim(src)
result = upper(result)
result = lower(result)
x += length(result)
}
return x
},
// Starts_with / ends_with (interning path)
string_prefix_suffix: function(n) {
var strs = [
"application/json",
"text/html",
"image/png",
"application/xml",
"text/plain"
]
var i = 0
var j = 0
var count = 0
for (i = 0; i < n; i++) {
for (j = 0; j < length(strs); j++) {
if (starts_with(strs[j], "application/")) count++
if (ends_with(strs[j], "/json")) count++
if (starts_with(strs[j], "text/")) count++
}
}
return count
}
}

137
benches/tree_ops.cm Normal file
View File

@@ -0,0 +1,137 @@
// tree_ops.cm — Tree data structure operations kernel
// Pointer chasing, recursion, allocation patterns.
// Binary tree: create, walk, transform, check
function make_tree(depth) {
if (depth <= 0) return {val: 1, left: null, right: null}
return {
val: depth,
left: make_tree(depth - 1),
right: make_tree(depth - 1)
}
}
function tree_check(node) {
if (!node) return 0
if (!node.left) return node.val
return node.val + tree_check(node.left) - tree_check(node.right)
}
function tree_sum(node) {
if (!node) return 0
return node.val + tree_sum(node.left) + tree_sum(node.right)
}
function tree_depth(node) {
if (!node) return 0
var l = tree_depth(node.left)
var r = tree_depth(node.right)
return 1 + (l > r ? l : r)
}
function tree_count(node) {
if (!node) return 0
return 1 + tree_count(node.left) + tree_count(node.right)
}
// Transform tree: map values
function tree_map(node, fn) {
if (!node) return null
return {
val: fn(node.val),
left: tree_map(node.left, fn),
right: tree_map(node.right, fn)
}
}
// Flatten tree to array (in-order)
function tree_flatten(node, result) {
if (!node) return null
tree_flatten(node.left, result)
push(result, node.val)
tree_flatten(node.right, result)
return null
}
// Build sorted tree from array (balanced)
function build_balanced(arr, lo, hi) {
if (lo > hi) return null
var mid = floor((lo + hi) / 2)
return {
val: arr[mid],
left: build_balanced(arr, lo, mid - 1),
right: build_balanced(arr, mid + 1, hi)
}
}
// Find a value in BST
function bst_find(node, val) {
if (!node) return false
if (val == node.val) return true
if (val < node.val) return bst_find(node.left, val)
return bst_find(node.right, val)
}
return {
// Binary tree create + check (allocation heavy)
tree_create_check: function(n) {
var i = 0
var t = null
var x = 0
for (i = 0; i < n; i++) {
t = make_tree(10)
x += tree_check(t)
}
return x
},
// Deep tree traversals
tree_traversal: function(n) {
var t = make_tree(12)
var x = 0
var i = 0
for (i = 0; i < n; i++) {
x += tree_sum(t) + tree_depth(t) + tree_count(t)
}
return x
},
// Tree map (create new tree from old)
tree_transform: function(n) {
var t = make_tree(10)
var i = 0
var mapped = null
for (i = 0; i < n; i++) {
mapped = tree_map(t, function(v) { return v * 2 + 1 })
}
return mapped
},
// Flatten + rebuild (array <-> tree conversion)
tree_flatten_rebuild: function(n) {
var t = make_tree(10)
var i = 0
var flat = null
var rebuilt = null
for (i = 0; i < n; i++) {
flat = []
tree_flatten(t, flat)
rebuilt = build_balanced(flat, 0, length(flat) - 1)
}
return rebuilt
},
// BST search (pointer chasing)
bst_search: function(n) {
// Build a balanced BST of 1024 elements
var data = []
var i = 0
for (i = 0; i < 1024; i++) push(data, i)
var bst = build_balanced(data, 0, 1023)
var found = 0
for (i = 0; i < n; i++) {
if (bst_find(bst, i % 1024)) found++
}
return found
}
}

43
benchmarks/binarytree.ce Normal file
View File

@@ -0,0 +1,43 @@
function mainThread() {
var maxDepth = max(6, Number(arg[0] || 16));
var stretchDepth = maxDepth + 1;
var check = itemCheck(bottomUpTree(stretchDepth));
log.console(`stretch tree of depth ${stretchDepth}\t check: ${check}`);
var longLivedTree = bottomUpTree(maxDepth);
for (var depth = 4; depth <= maxDepth; depth += 2) {
var iterations = 1 << maxDepth - depth + 4;
work(iterations, depth);
}
log.console(`long lived tree of depth ${maxDepth}\t check: ${itemCheck(longLivedTree)}`);
}
function work(iterations, depth) {
var check = 0;
for (var i = 0; i < iterations; i++)
check += itemCheck(bottomUpTree(depth));
log.console(`${iterations}\t trees of depth ${depth}\t check: ${check}`);
}
function TreeNode(left, right) {
return {left, right};
}
function itemCheck(node) {
if (node.left == null)
return 1;
return 1 + itemCheck(node.left) + itemCheck(node.right);
}
function bottomUpTree(depth) {
return depth > 0
? TreeNode(bottomUpTree(depth - 1), bottomUpTree(depth - 1))
: TreeNode(null, null);
}
mainThread()
$stop()

View File

@@ -0,0 +1,25 @@
var blob = use('blob')
var math = use('math/radians')
function eratosthenes (n) {
var sieve = blob(n, true)
var sqrtN = whole(math.sqrt(n));
for (i = 2; i <= sqrtN; i++)
if (sieve.read_logical(i))
for (j = i * i; j <= n; j += i)
sieve.write_bit(j, false);
return sieve;
}
var sieve = eratosthenes(10000000);
stone(sieve)
var c = 0
for (var i = 0; i < length(sieve); i++)
if (sieve.read_logical(i)) c++
log.console(c)
$stop()

58
benchmarks/fannkuch.ce Normal file
View File

@@ -0,0 +1,58 @@
function fannkuch(n) {
var perm1 = [n]
for (var i = 0; i < n; i++) perm1[i] = i
var perm = [n]
var count = [n]
var f = 0, flips = 0, nperm = 0, checksum = 0
var i, k, r
r = n
while (r > 0) {
i = 0
while (r != 1) { count[r-1] = r; r -= 1 }
while (i < n) { perm[i] = perm1[i]; i += 1 }
// Count flips and update max and checksum
f = 0
k = perm[0]
while (k != 0) {
i = 0
while (2*i < k) {
var t = perm[i]; perm[i] = perm[k-i]; perm[k-i] = t
i += 1
}
k = perm[0]
f += 1
}
if (f > flips) flips = f
if ((nperm & 0x1) == 0) checksum += f; else checksum -= f
// Use incremental change to generate another permutation
var more = true
while (more) {
if (r == n) {
log.console( checksum )
return flips
}
var p0 = perm1[0]
i = 0
while (i < r) {
var j = i + 1
perm1[i] = perm1[j]
i = j
}
perm1[r] = p0
count[r] -= 1
if (count[r] > 0) more = false; else r += 1
}
nperm += 1
}
return flips;
}
var n = arg[0] || 10
log.console(`Pfannkuchen(${n}) = ${fannkuch(n)}`)
$stop()

16
benchmarks/fib.ce Normal file
View File

@@ -0,0 +1,16 @@
var time = use('time')
function fib(n) {
if (n<2) return n
return fib(n-1) + fib(n-2)
}
var now = time.number()
var arr = [1,2,3,4,5]
arrfor(arr, function(i) {
log.console(fib(28))
})
log.console(`elapsed: ${time.number()-now}`)
$stop()

View File

@@ -0,0 +1,20 @@
#!/bin/bash
# Run hyperfine with parameter lists
# This will create a cross-product of all libraries × all scenarios
hyperfine \
--warmup 3 \
--runs 20 \
-i \
--export-csv wota_vs_nota_vs_json.csv \
--export-json wota_vs_nota_vs_json.json \
--export-markdown wota_vs_nota_vs_json.md \
--parameter-list lib wota,nota,json \
--parameter-list scen empty,integers,floats,strings,objects,nested,large_array \
'cell benchmarks/wota_nota_json {lib} {scen}'
echo "Benchmark complete! Results saved to:"
echo " - wota_vs_nota_vs_json.csv"
echo " - wota_vs_nota_vs_json.json"
echo " - wota_vs_nota_vs_json.md"

395
benchmarks/js_perf.ce Normal file
View File

@@ -0,0 +1,395 @@
var time = use('time')
var math = use('math/radians')
////////////////////////////////////////////////////////////////////////////////
// JavaScript Performance Benchmark Suite
// Tests core JS operations: property access, function calls, arithmetic, etc.
////////////////////////////////////////////////////////////////////////////////
// Test configurations
def iterations = {
simple: 10000000,
medium: 1000000,
complex: 100000
};
////////////////////////////////////////////////////////////////////////////////
// Utility: measureTime(fn) => how long fn() takes in seconds
////////////////////////////////////////////////////////////////////////////////
function measureTime(fn) {
var start = time.number();
fn();
var end = time.number();
return (end - start);
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Property Access
////////////////////////////////////////////////////////////////////////////////
function benchPropertyAccess() {
var obj = {
a: 1, b: 2, c: 3, d: 4, e: 5,
nested: { x: 10, y: 20, z: 30 }
};
var readTime = measureTime(function() {
var sum = 0;
for (var i = 0; i < iterations.simple; i++) {
sum += obj.a + obj.b + obj.c + obj.d + obj.e;
sum += obj.nested.x + obj.nested.y + obj.nested.z;
}
});
var writeTime = measureTime(function() {
for (var i = 0; i < iterations.simple; i++) {
obj.a = i;
obj.b = i + 1;
obj.c = i + 2;
obj.nested.x = i * 2;
obj.nested.y = i * 3;
}
});
return { readTime: readTime, writeTime: writeTime };
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Function Calls
////////////////////////////////////////////////////////////////////////////////
function benchFunctionCalls() {
function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }
function complexCalc(a, b, c) { return (a + b) * c / 2; }
var obj = {
method: function(x) { return x * 2; },
nested: {
deepMethod: function(x, y) { return x + y; }
}
};
var simpleCallTime = measureTime(function() {
var result = 0;
for (var i = 0; i < iterations.simple; i++) {
result = add(i, 1);
result = multiply(result, 2);
}
});
var methodCallTime = measureTime(function() {
var result = 0;
for (var i = 0; i < iterations.simple; i++) {
result = obj.method(i);
result = obj.nested.deepMethod(result, i);
}
});
var complexCallTime = measureTime(function() {
var result = 0;
for (var i = 0; i < iterations.medium; i++) {
result = complexCalc(i, i + 1, i + 2);
}
});
return {
simpleCallTime: simpleCallTime,
methodCallTime: methodCallTime,
complexCallTime: complexCallTime
};
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Array Operations
////////////////////////////////////////////////////////////////////////////////
function benchArrayOps() {
var pushTime = measureTime(function() {
var arr = [];
for (var i = 0; i < iterations.medium; i++) {
push(arr, i);
}
});
var arr = [];
for (var i = 0; i < 10000; i++) push(arr, i);
var accessTime = measureTime(function() {
var sum = 0;
for (var i = 0; i < iterations.medium; i++) {
sum += arr[i % 10000];
}
});
var iterateTime = measureTime(function() {
var sum = 0;
for (var j = 0; j < 1000; j++) {
for (var i = 0; i < length(arr); i++) {
sum += arr[i];
}
}
});
return {
pushTime: pushTime,
accessTime: accessTime,
iterateTime: iterateTime
};
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Object Creation
////////////////////////////////////////////////////////////////////////////////
function benchObjectCreation() {
var literalTime = measureTime(function() {
for (var i = 0; i < iterations.medium; i++) {
var obj = { x: i, y: i * 2, z: i * 3 };
}
});
function Point(x, y) {
return {x,y}
}
var defructorTime = measureTime(function() {
for (var i = 0; i < iterations.medium; i++) {
var p = Point(i, i * 2);
}
});
var protoObj = {
x: 0,
y: 0,
move: function(dx, dy) {
this.x += dx;
this.y += dy;
}
};
var prototypeTime = measureTime(function() {
for (var i = 0; i < iterations.medium; i++) {
var obj = meme(protoObj);
obj.x = i;
obj.y = i * 2;
}
});
return {
literalTime: literalTime,
defructorTime: defructorTime,
prototypeTime: prototypeTime
};
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: String Operations
////////////////////////////////////////////////////////////////////////////////
function benchStringOps() {
var concatTime = measureTime(function() {
var str = "";
for (var i = 0; i < iterations.complex; i++) {
str = "test" + i + "value";
}
});
var strings = [];
for (var i = 0; i < 1000; i++) {
push(strings, "string" + i);
}
var joinTime = measureTime(function() {
for (var i = 0; i < iterations.complex; i++) {
var result = text(strings, ",");
}
});
var splitTime = measureTime(function() {
var str = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p";
for (var i = 0; i < iterations.medium; i++) {
var parts = array(str, ",");
}
});
return {
concatTime: concatTime,
joinTime: joinTime,
splitTime: splitTime
};
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Arithmetic Operations
////////////////////////////////////////////////////////////////////////////////
function benchArithmetic() {
var intMathTime = measureTime(function() {
var result = 1;
for (var i = 0; i < iterations.simple; i++) {
result = ((result + i) * 2 - 1) / 3;
result = result % 1000 + 1;
}
});
var floatMathTime = measureTime(function() {
var result = 1.5;
for (var i = 0; i < iterations.simple; i++) {
result = math.sine(result) + math.cosine(i * 0.01);
result = math.sqrt(abs(result)) + 0.1;
}
});
var bitwiseTime = measureTime(function() {
var result = 0;
for (var i = 0; i < iterations.simple; i++) {
result = (result ^ i) & 0xFFFF;
result = (result << 1) | (result >> 15);
}
});
return {
intMathTime: intMathTime,
floatMathTime: floatMathTime,
bitwiseTime: bitwiseTime
};
}
////////////////////////////////////////////////////////////////////////////////
// Benchmark: Closure Operations
////////////////////////////////////////////////////////////////////////////////
function benchClosures() {
function makeAdder(x) {
return function(y) { return x + y; };
}
var closureCreateTime = measureTime(function() {
var funcs = [];
for (var i = 0; i < iterations.medium; i++) {
push(funcs, makeAdder(i));
}
});
var adders = [];
for (var i = 0; i < 1000; i++) {
push(adders, makeAdder(i));
}
var closureCallTime = measureTime(function() {
var sum = 0;
for (var i = 0; i < iterations.medium; i++) {
sum += adders[i % 1000](i);
}
});
return {
closureCreateTime: closureCreateTime,
closureCallTime: closureCallTime
};
}
////////////////////////////////////////////////////////////////////////////////
// Main benchmark runner
////////////////////////////////////////////////////////////////////////////////
log.console("JavaScript Performance Benchmark");
log.console("======================\n");
// Property Access
log.console("BENCHMARK: Property Access");
var propResults = benchPropertyAccess();
log.console(" Read time: " + propResults.readTime.toFixed(3) + "s => " +
(iterations.simple / propResults.readTime).toFixed(1) + " reads/sec [" +
(propResults.readTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Write time: " + propResults.writeTime.toFixed(3) + "s => " +
(iterations.simple / propResults.writeTime).toFixed(1) + " writes/sec [" +
(propResults.writeTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console("");
// Function Calls
log.console("BENCHMARK: Function Calls");
var funcResults = benchFunctionCalls();
log.console(" Simple calls: " + funcResults.simpleCallTime.toFixed(3) + "s => " +
(iterations.simple / funcResults.simpleCallTime).toFixed(1) + " calls/sec [" +
(funcResults.simpleCallTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Method calls: " + funcResults.methodCallTime.toFixed(3) + "s => " +
(iterations.simple / funcResults.methodCallTime).toFixed(1) + " calls/sec [" +
(funcResults.methodCallTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Complex calls: " + funcResults.complexCallTime.toFixed(3) + "s => " +
(iterations.medium / funcResults.complexCallTime).toFixed(1) + " calls/sec [" +
(funcResults.complexCallTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console("");
// Array Operations
log.console("BENCHMARK: Array Operations");
var arrayResults = benchArrayOps();
log.console(" Push: " + arrayResults.pushTime.toFixed(3) + "s => " +
(iterations.medium / arrayResults.pushTime).toFixed(1) + " pushes/sec [" +
(arrayResults.pushTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Access: " + arrayResults.accessTime.toFixed(3) + "s => " +
(iterations.medium / arrayResults.accessTime).toFixed(1) + " accesses/sec [" +
(arrayResults.accessTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Iterate: " + arrayResults.iterateTime.toFixed(3) + "s => " +
(1000 / arrayResults.iterateTime).toFixed(1) + " full iterations/sec");
log.console("");
// Object Creation
log.console("BENCHMARK: Object Creation");
var objResults = benchObjectCreation();
log.console(" Literal: " + objResults.literalTime.toFixed(3) + "s => " +
(iterations.medium / objResults.literalTime).toFixed(1) + " creates/sec [" +
(objResults.literalTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Constructor: " + objResults.defructorTime.toFixed(3) + "s => " +
(iterations.medium / objResults.defructorTime).toFixed(1) + " creates/sec [" +
(objResults.defructorTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Prototype: " + objResults.prototypeTime.toFixed(3) + "s => " +
(iterations.medium / objResults.prototypeTime).toFixed(1) + " creates/sec [" +
(objResults.prototypeTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console("");
// String Operations
log.console("BENCHMARK: String Operations");
var strResults = benchStringOps();
log.console(" Concat: " + strResults.concatTime.toFixed(3) + "s => " +
(iterations.complex / strResults.concatTime).toFixed(1) + " concats/sec [" +
(strResults.concatTime / iterations.complex * 1e9).toFixed(1) + " ns/op]");
log.console(" Join: " + strResults.joinTime.toFixed(3) + "s => " +
(iterations.complex / strResults.joinTime).toFixed(1) + " joins/sec [" +
(strResults.joinTime / iterations.complex * 1e9).toFixed(1) + " ns/op]");
log.console(" Split: " + strResults.splitTime.toFixed(3) + "s => " +
(iterations.medium / strResults.splitTime).toFixed(1) + " splits/sec [" +
(strResults.splitTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console("");
// Arithmetic Operations
log.console("BENCHMARK: Arithmetic Operations");
var mathResults = benchArithmetic();
log.console(" Integer math: " + mathResults.intMathTime.toFixed(3) + "s => " +
(iterations.simple / mathResults.intMathTime).toFixed(1) + " ops/sec [" +
(mathResults.intMathTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Float math: " + mathResults.floatMathTime.toFixed(3) + "s => " +
(iterations.simple / mathResults.floatMathTime).toFixed(1) + " ops/sec [" +
(mathResults.floatMathTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console(" Bitwise: " + mathResults.bitwiseTime.toFixed(3) + "s => " +
(iterations.simple / mathResults.bitwiseTime).toFixed(1) + " ops/sec [" +
(mathResults.bitwiseTime / iterations.simple * 1e9).toFixed(1) + " ns/op]");
log.console("");
// Closures
log.console("BENCHMARK: Closures");
var closureResults = benchClosures();
log.console(" Create: " + closureResults.closureCreateTime.toFixed(3) + "s => " +
(iterations.medium / closureResults.closureCreateTime).toFixed(1) + " creates/sec [" +
(closureResults.closureCreateTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console(" Call: " + closureResults.closureCallTime.toFixed(3) + "s => " +
(iterations.medium / closureResults.closureCallTime).toFixed(1) + " calls/sec [" +
(closureResults.closureCallTime / iterations.medium * 1e9).toFixed(1) + " ns/op]");
log.console("");
log.console("---------------------------------------------------------");
log.console("Benchmark complete.\n");
$stop()

40
benchmarks/mandelbrot.ce Normal file
View File

@@ -0,0 +1,40 @@
var blob = use('blob')
var iter = 50, limit = 2.0;
var zr, zi, cr, ci, tr, ti;
var h = Number(arg[0]) || 500
var w = h
log.console(`P4\n${w} ${h}`);
for (var y = 0; y < h; ++y) {
// Create a blob for the row - we need w bits
var row = blob(w);
for (var x = 0; x < w; ++x) {
zr = zi = tr = ti = 0;
cr = 2 * x / w - 1.5;
ci = 2 * y / h - 1;
for (var i = 0; i < iter && (tr + ti <= limit * limit); ++i) {
zi = 2 * zr * zi + ci;
zr = tr - ti + cr;
tr = zr * zr;
ti = zi * zi;
}
// Write a 1 bit if inside the set, 0 if outside
if (tr + ti <= limit * limit)
row.write_bit(1);
else
row.write_bit(0);
}
// Convert the blob to stone (immutable) to prepare for output
stone(row)
// Output the blob data as raw bytes
log.console(text(row, 'b'));
}
$stop()

12
benchmarks/montecarlo.ce Normal file
View File

@@ -0,0 +1,12 @@
var math = use('math/radians')
var N = 1000000;
var num = 0;
for (var i = 0; i < N; i ++) {
var x = 2 * $random();
var y = $random();
if (y < math.sine(x * x))
num++;
}
log.console(2 * num / N);
$stop()

155
benchmarks/nbody.ce Normal file
View File

@@ -0,0 +1,155 @@
var math = use('math/radians')
var SOLAR_MASS = 4 * pi * pi;
var DAYS_PER_YEAR = 365.24;
function Body(x, y, z, vx, vy, vz, mass) {
return {x, y, z, vx, vy, vz, mass};
}
function Jupiter() {
return Body(
4.84143144246472090e+00,
-1.16032004402742839e+00,
-1.03622044471123109e-01,
1.66007664274403694e-03 * DAYS_PER_YEAR,
7.69901118419740425e-03 * DAYS_PER_YEAR,
-6.90460016972063023e-05 * DAYS_PER_YEAR,
9.54791938424326609e-04 * SOLAR_MASS
);
}
function Saturn() {
return Body(
8.34336671824457987e+00,
4.12479856412430479e+00,
-4.03523417114321381e-01,
-2.76742510726862411e-03 * DAYS_PER_YEAR,
4.99852801234917238e-03 * DAYS_PER_YEAR,
2.30417297573763929e-05 * DAYS_PER_YEAR,
2.85885980666130812e-04 * SOLAR_MASS
);
}
function Uranus() {
return Body(
1.28943695621391310e+01,
-1.51111514016986312e+01,
-2.23307578892655734e-01,
2.96460137564761618e-03 * DAYS_PER_YEAR,
2.37847173959480950e-03 * DAYS_PER_YEAR,
-2.96589568540237556e-05 * DAYS_PER_YEAR,
4.36624404335156298e-05 * SOLAR_MASS
);
}
function Neptune() {
return Body(
1.53796971148509165e+01,
-2.59193146099879641e+01,
1.79258772950371181e-01,
2.68067772490389322e-03 * DAYS_PER_YEAR,
1.62824170038242295e-03 * DAYS_PER_YEAR,
-9.51592254519715870e-05 * DAYS_PER_YEAR,
5.15138902046611451e-05 * SOLAR_MASS
);
}
function Sun() {
return Body(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, SOLAR_MASS);
}
var bodies = Array(Sun(), Jupiter(), Saturn(), Uranus(), Neptune());
function offsetMomentum() {
var px = 0;
var py = 0;
var pz = 0;
var size = length(bodies);
for (var i = 0; i < size; i++) {
var body = bodies[i];
var mass = body.mass;
px += body.vx * mass;
py += body.vy * mass;
pz += body.vz * mass;
}
var body = bodies[0];
body.vx = -px / SOLAR_MASS;
body.vy = -py / SOLAR_MASS;
body.vz = -pz / SOLAR_MASS;
}
function advance(dt) {
var size = length(bodies);
for (var i = 0; i < size; i++) {
var bodyi = bodies[i];
var vxi = bodyi.vx;
var vyi = bodyi.vy;
var vzi = bodyi.vz;
for (var j = i + 1; j < size; j++) {
var bodyj = bodies[j];
var dx = bodyi.x - bodyj.x;
var dy = bodyi.y - bodyj.y;
var dz = bodyi.z - bodyj.z;
var d2 = dx * dx + dy * dy + dz * dz;
var mag = dt / (d2 * math.sqrt(d2));
var massj = bodyj.mass;
vxi -= dx * massj * mag;
vyi -= dy * massj * mag;
vzi -= dz * massj * mag;
var massi = bodyi.mass;
bodyj.vx += dx * massi * mag;
bodyj.vy += dy * massi * mag;
bodyj.vz += dz * massi * mag;
}
bodyi.vx = vxi;
bodyi.vy = vyi;
bodyi.vz = vzi;
}
for (var i = 0; i < size; i++) {
var body = bodies[i];
body.x += dt * body.vx;
body.y += dt * body.vy;
body.z += dt * body.vz;
}
}
function energy() {
var e = 0;
var size = length(bodies);
for (var i = 0; i < size; i++) {
var bodyi = bodies[i];
e += 0.5 * bodyi.mass * ( bodyi.vx * bodyi.vx +
bodyi.vy * bodyi.vy + bodyi.vz * bodyi.vz );
for (var j = i + 1; j < size; j++) {
var bodyj = bodies[j];
var dx = bodyi.x - bodyj.x;
var dy = bodyi.y - bodyj.y;
var dz = bodyi.z - bodyj.z;
var distance = math.sqrt(dx * dx + dy * dy + dz * dz);
e -= (bodyi.mass * bodyj.mass) / distance;
}
}
return e;
}
var n = arg[0] || 100000
offsetMomentum();
log.console(`n = ${n}`)
log.console(energy().toFixed(9))
for (var i = 0; i < n; i++)
advance(0.01);
log.console(energy().toFixed(9))
$stop()

78
benchmarks/nota.ce Normal file
View File

@@ -0,0 +1,78 @@
var nota = use('nota')
var os = use('os')
var io = use('fd')
var json = use('json')
var ll = io.slurp('benchmarks/nota.json')
var newarr = []
var accstr = ""
for (var i = 0; i < 10000; i++) {
accstr += i;
newarrpush(i.toString())
}
// Arrays to store timing results
var jsonDecodeTimes = [];
var jsonEncodeTimes = [];
var notaEncodeTimes = [];
var notaDecodeTimes = [];
var notaSizes = [];
// Run 100 tests
for (var i = 0; i < 100; i++) {
// JSON Decode test
var start = os.now();
var jll = json.decode(ll);
jsonDecodeTimespush((os.now() - start) * 1000);
// JSON Encode test
start = os.now();
var jsonStr = JSON.stringify(jll);
jsonEncodeTimespush((os.now() - start) * 1000);
// NOTA Encode test
start = os.now();
var nll = nota.encode(jll);
notaEncodeTimespush((os.now() - start) * 1000);
// NOTA Decode test
start = os.now();
var oll = nota.decode(nll);
notaDecodeTimespush((os.now() - start) * 1000);
}
// Calculate statistics
function getStats(arr) {
return {
avg: reduce(arr, (a,b) => a+b, 0) / length(arr),
min: reduce(arr, min),
max: reduce(arr, max)
};
}
// Pretty print results
log.console("\n== Performance Test Results (100 iterations) ==");
log.console("\nJSON Decoding (ms):");
def jsonDecStats = getStats(jsonDecodeTimes);
log.console(`Average: ${jsonDecStats.avg.toFixed(2)} ms`);
log.console(`Min: ${jsonDecStats.min.toFixed(2)} ms`);
log.console(`Max: ${jsonDecStats.max.toFixed(2)} ms`);
log.console("\nJSON Encoding (ms):");
def jsonEncStats = getStats(jsonEncodeTimes);
log.console(`Average: ${jsonEncStats.avg.toFixed(2)} ms`);
log.console(`Min: ${jsonEncStats.min.toFixed(2)} ms`);
log.console(`Max: ${jsonEncStats.max.toFixed(2)} ms`);
log.console("\nNOTA Encoding (ms):");
def notaEncStats = getStats(notaEncodeTimes);
log.console(`Average: ${notaEncStats.avg.toFixed(2)} ms`);
log.console(`Min: ${notaEncStats.min.toFixed(2)} ms`);
log.console(`Max: ${notaEncStats.max.toFixed(2)} ms`);
log.console("\nNOTA Decoding (ms):");
def notaDecStats = getStats(notaDecodeTimes);
log.console(`Average: ${notaDecStats.avg.toFixed(2)} ms`);
log.console(`Min: ${notaDecStats.min.toFixed(2)} ms`);
log.console(`Max: ${notaDecStats.max.toFixed(2)} ms`);

2132
benchmarks/nota.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
def math = use('math/radians');
function A(i,j) {
return 1/((i+j)*(i+j+1)/2+i+1);
}
function Au(u,v) {
for (var i=0; i<length(u); ++i) {
var t = 0;
for (var j=0; j<length(u); ++j)
t += A(i,j) * u[j];
v[i] = t;
}
}
function Atu(u,v) {
for (var i=0; i<length(u); ++i) {
var t = 0;
for (var j=0; j<length(u); ++j)
t += A(j,i) * u[j];
v[i] = t;
}
}
function AtAu(u,v,w) {
Au(u,w);
Atu(w,v);
}
function spectralnorm(n) {
var i, u=[], v=[], w=[], vv=0, vBv=0;
for (i=0; i<n; ++i)
u[i] = 1; v[i] = w[i] = 0;
for (i=0; i<10; ++i) {
AtAu(u,v,w);
AtAu(v,u,w);
}
for (i=0; i<n; ++i) {
vBv += u[i]*v[i];
vv += v[i]*v[i];
}
return math.sqrt(vBv/vv);
}
log.console(spectralnorm(arg[0]).toFixed(9));
$stop()

95
benchmarks/wota.ce Normal file
View File

@@ -0,0 +1,95 @@
//
// wota_benchmark.js
//
// Usage in QuickJS:
// qjs wota_benchmark.js
//
// Prerequisite:
var wota = use('wota');
var os = use('os');
// or otherwise ensure `wota` and `os` are available.
// Make sure wota_benchmark.js is loaded after wota.js or combined with it.
//
// Helper to run a function repeatedly and measure total time in seconds.
// Returns elapsed time in seconds.
function measureTime(fn, iterations) {
var t1 = os.now();
for (var i = 0; i < iterations; i++) {
fn();
}
var t2 = os.now();
return t2 - t1;
}
// We'll define a function that does `encode -> decode` for a given value:
function roundTripWota(value) {
var encoded = wota.encode(value);
var decoded = wota.decode(encoded);
// Not doing a deep compare here, just measuring performance.
// (We trust the test suite to verify correctness.)
}
// A small suite of data we want to benchmark. Each entry includes:
// name: label for printing
// data: the test value(s) to encode/decode
// iterations: how many times to loop
//
// You can tweak these as you like for heavier or lighter tests.
def benchmarks = [
{
name: "Small Integers",
data: [0, 42, -1, 2023],
iterations: 100000
},
{
name: "Strings (short, emoji)",
data: ["Hello, Wota!", "short", "Emoji: \u{1f600}\u{1f64f}"],
iterations: 100000
},
{
name: "Small Objects",
data: [
{ a:1, b:2.2, c:"3", d:false },
{ x:42, y:null, z:"test" }
],
iterations: 50000
},
{
name: "Nested Arrays",
data: [ [ [ [1,2], [3,4] ] ], [[[]]], [1, [2, [3, [4]]]] ],
iterations: 50000
},
{
name: "Large Array (1k numbers)",
// A thousand random numbers
data: [ array(1000, i => i *0.5) ],
iterations: 1000
},
];
// Print a header
log.console("Wota Encode/Decode Benchmark");
log.console("===================\n");
// We'll run each benchmark scenario in turn.
arrfor(benchmarks, function(bench) {
var totalIterations = bench.iterations * length(bench.data);
// We'll define a function that does a roundTrip for *each* data item in bench.data
// to measure in one loop iteration. Then we multiply by bench.iterations.
function runAllData() {
arrfor(bench.data, roundTripWota)
}
var elapsedSec = measureTime(runAllData, bench.iterations);
var opsPerSec = (totalIterations / elapsedSec).toFixed(1);
log.console(`${bench.name}:`);
log.console(` Iterations: ${bench.iterations} × ${length(bench.data)} data items = ${totalIterations}`);
log.console(` Elapsed: ${elapsedSec.toFixed(3)} s`);
log.console(` Throughput: ${opsPerSec} encode+decode ops/sec\n`);
})
// All done
log.console("Benchmark completed.\n");

View File

@@ -0,0 +1,199 @@
//
// benchmark_wota_nota_json.js
//
// Usage in QuickJS:
// qjs benchmark_wota_nota_json.js <LibraryName> <ScenarioName>
//
// Ensure wota, nota, json, and os are all available, e.g.:
var wota = use('wota');
var nota = use('nota');
var json = use('json');
var jswota = use('jswota')
var os = use('os');
//
// Parse command line arguments
if (length(arg) != 2) {
log.console('Usage: cell benchmark_wota_nota_json.ce <LibraryName> <ScenarioName>');
$stop()
}
var lib_name = arg[0];
var scenario_name = arg[1];
////////////////////////////////////////////////////////////////////////////////
// 1. Setup "libraries" array to easily switch among wota, nota, and json
////////////////////////////////////////////////////////////////////////////////
def libraries = [
{
name: "wota",
encode: wota.encode,
decode: wota.decode,
// wota produces an ArrayBuffer. We'll count `buffer.byteLength` as size.
getSize(encoded) {
return length(encoded);
}
},
{
name: "nota",
encode: nota.encode,
decode: nota.decode,
// nota also produces an ArrayBuffer:
getSize(encoded) {
return length(encoded);
}
},
{
name: "json",
encode: json.encode,
decode: json.decode,
// json produces a JS string. We'll measure its UTF-16 code unit length
// as a rough "size". Alternatively, you could convert to UTF-8 for
getSize(encodedStr) {
return length(encodedStr);
}
}
];
////////////////////////////////////////////////////////////////////////////////
// 2. Test data sets (similar to wota benchmarks).
// Each scenario has { name, data, iterations }
////////////////////////////////////////////////////////////////////////////////
def benchmarks = [
{
name: "empty",
data: [{}, {}, {}, {}],
iterations: 10000
},
{
name: "integers",
data: [0, 42, -1, 2023],
iterations: 100000
},
{
name: "floats",
data: [0.1, 1e-50, 3.14159265359],
iterations: 100000
},
{
name: "strings",
data: ["Hello, wota!", "short", "Emoji: \u{1f600}\u{1f64f}"],
iterations: 100000
},
{
name: "objects",
data: [
{ a:1, b:2.2, c:"3", d:false },
{ x:42, y:null, z:"test" }
],
iterations: 50000
},
{
name: "nested",
data: [ [ [ [1,2], [3,4] ] ], [[[]]], [1, [2, [3, [4]]]] ],
iterations: 50000
},
{
name: "large_array",
data: [ array(1000, i => i) ],
iterations: 1000
},
];
////////////////////////////////////////////////////////////////////////////////
// 3. Utility: measureTime(fn) => how long fn() takes in seconds.
////////////////////////////////////////////////////////////////////////////////
function measureTime(fn) {
var start = os.now();
fn();
var end = os.now();
return (end - start); // in seconds
}
////////////////////////////////////////////////////////////////////////////////
// 4. For each library, we run each benchmark scenario and measure:
// - Encoding time (seconds)
// - Decoding time (seconds)
// - Total encoded size (bytes or code units for json)
//
////////////////////////////////////////////////////////////////////////////////
function runBenchmarkForLibrary(lib, bench) {
// We'll encode and decode each item in `bench.data`.
// We do 'bench.iterations' times. Then sum up total time.
// Pre-store the encoded results for all items so we can measure decode time
// in a separate pass. Also measure total size once.
var encodedList = [];
var totalSize = 0;
// 1) Measure ENCODING
var encodeTime = measureTime(() => {
for (var i = 0; i < bench.iterations; i++) {
// For each data item, encode it
for (var j = 0; j < length(bench.data); j++) {
var e = lib.encode(bench.data[j]);
// store only in the very first iteration, so we can decode them later
// but do not store them every iteration or we blow up memory.
if (i == 0) {
push(encodedList, e);
totalSize += lib.getSize(e);
}
}
}
});
// 2) Measure DECODING
var decodeTime = measureTime(() => {
for (var i = 0; i < bench.iterations; i++) {
arrfor(encodedList, lib.decode)
}
});
return { encodeTime, decodeTime, totalSize };
}
////////////////////////////////////////////////////////////////////////////////
// 5. Main driver: run only the specified library and scenario
////////////////////////////////////////////////////////////////////////////////
// Find the requested library and scenario
var lib = libraries[find(libraries, l => l.name == lib_name)];
var bench = benchmarks[find(benchmarks, b => b.name == scenario_name)];
if (!lib) {
log.console('Unknown library:', lib_name);
log.console('Available libraries:', text(array(libraries, l => l.name), ', '));
$stop()
}
if (!bench) {
log.console('Unknown scenario:', scenario_name);
log.console('Available scenarios:', text(array(benchmarks, b => b.name), ', '));
$stop()
}
// Run the benchmark for this library/scenario combination
var { encodeTime, decodeTime, totalSize } = runBenchmarkForLibrary(lib, bench);
// Output json for easy parsing by hyperfine or other tools
var totalOps = bench.iterations * length(bench.data);
var result = {
lib: lib_name,
scenario: scenario_name,
encodeTime: encodeTime,
decodeTime: decodeTime,
totalSize: totalSize,
totalOps: totalOps,
encodeOpsPerSec: totalOps / encodeTime,
decodeOpsPerSec: totalOps / decodeTime,
encodeNsPerOp: (encodeTime / totalOps) * 1e9,
decodeNsPerOp: (decodeTime / totalOps) * 1e9
};
log.console(result);
$stop()

6200
boot/bootstrap.cm.mcode Normal file

File diff suppressed because it is too large Load Diff

21056
boot/fold.cm.mcode Normal file

File diff suppressed because it is too large Load Diff

24810
boot/mcode.cm.mcode Normal file

File diff suppressed because it is too large Load Diff

29874
boot/parse.cm.mcode Normal file

File diff suppressed because it is too large Load Diff

10436
boot/tokenize.cm.mcode Normal file

File diff suppressed because it is too large Load Diff

134
build.ce Normal file
View File

@@ -0,0 +1,134 @@
// cell build [<locator>] - Build dynamic libraries locally for the current machine
//
// Usage:
// cell build Build dynamic libraries for all packages in shop
// cell build . Build dynamic library for current directory package
// cell build <locator> Build dynamic library for specific package
// cell build -t <target> Cross-compile dynamic libraries for target platform
// cell build -b <type> Build type: release (default), debug, or minsize
var build = use('build')
var shop = use('internal/shop')
var pkg_tools = use('package')
var fd = use('fd')
var target = null
var target_package = null
var buildtype = 'release'
var force_rebuild = false
var dry_run = false
var i = 0
var targets = null
var t = 0
var resolved = null
var lib = null
var results = null
var success = 0
var failed = 0
for (i = 0; i < length(args); i++) {
if (args[i] == '-t' || args[i] == '--target') {
if (i + 1 < length(args)) {
target = args[++i]
} else {
log.error('-t requires a target')
$stop()
}
} else if (args[i] == '-p' || args[i] == '--package') {
// Legacy support for -p flag
if (i + 1 < length(args)) {
target_package = args[++i]
} else {
log.error('-p requires a package name')
$stop()
}
} else if (args[i] == '-b' || args[i] == '--buildtype') {
if (i + 1 < length(args)) {
buildtype = args[++i]
if (buildtype != 'release' && buildtype != 'debug' && buildtype != 'minsize') {
log.error('Invalid buildtype: ' + buildtype + '. Must be release, debug, or minsize')
$stop()
}
} else {
log.error('-b requires a buildtype (release, debug, minsize)')
$stop()
}
} else if (args[i] == '--force') {
force_rebuild = true
} else if (args[i] == '--dry-run') {
dry_run = true
} else if (args[i] == '--list-targets') {
log.console('Available targets:')
targets = build.list_targets()
for (t = 0; t < length(targets); t++) {
log.console(' ' + targets[t])
}
$stop()
} else if (!starts_with(args[i], '-') && !target_package) {
// Positional argument - treat as package locator
target_package = args[i]
}
}
// Resolve local paths to absolute paths
if (target_package) {
if (target_package == '.' || starts_with(target_package, './') || starts_with(target_package, '../') || fd.is_dir(target_package)) {
resolved = fd.realpath(target_package)
if (resolved) {
target_package = resolved
}
}
}
// Detect target if not specified
if (!target) {
target = build.detect_host_target()
if (target) log.console('Target: ' + target)
}
if (target && !build.has_target(target)) {
log.error('Invalid target: ' + target)
log.console('Available targets: ' + text(build.list_targets(), ', '))
$stop()
}
var packages = shop.list_packages()
log.console('Preparing packages...')
arrfor(packages, function(package) {
if (package == 'core') return
shop.extract(package)
})
var _build = null
if (target_package) {
// Build single package
log.console('Building ' + target_package + '...')
_build = function() {
lib = build.build_dynamic(target_package, target, buildtype)
if (lib) {
log.console('Built: ' + lib)
}
} disruption {
log.error('Build failed')
$stop()
}
_build()
} else {
// Build all packages
log.console('Building all packages...')
results = build.build_all_dynamic(target, buildtype)
success = 0
failed = 0
for (i = 0; i < length(results); i++) {
if (results[i].library) {
success++
} else if (results[i].error) {
failed++
}
}
log.console(`Build complete: ${success} libraries built${failed > 0 ? `, ${failed} failed` : ''}`)
}
$stop()

659
build.cm Normal file
View File

@@ -0,0 +1,659 @@
// build.cm - Simplified build utilities for Cell
//
// Key functions:
// Build.compile_file(pkg, file, target) - Compile a C file, returns object path
// Build.build_package(pkg, target) - Build all C files for a package
// Build.build_dynamic(pkg, target) - Build dynamic library for a package
// Build.build_static(packages, target, output) - Build static binary
var fd = use('fd')
var crypto = use('crypto')
var blob = use('blob')
var os = use('os')
var toolchains = use('toolchains')
var shop = use('internal/shop')
var pkg_tools = use('package')
var Build = {}
// ============================================================================
// Sigil replacement
// ============================================================================
// Get the local directory for prebuilt libraries
function get_local_dir() {
return shop.get_local_dir()
}
// Replace sigils in a string
// Currently supports: $LOCAL -> .cell/local full path
function replace_sigils(str) {
return replace(str, '$LOCAL', get_local_dir())
}
// Replace sigils in an array of flags
function replace_sigils_array(flags) {
var result = []
arrfor(flags, function(flag) {
push(result, replace_sigils(flag))
})
return result
}
Build.get_local_dir = get_local_dir
// ============================================================================
// Toolchain helpers
// ============================================================================
Build.list_targets = function() {
return array(toolchains)
}
Build.has_target = function(target) {
return toolchains[target] != null
}
Build.detect_host_target = function() {
var platform = os.platform()
var arch = os.arch ? os.arch() : 'arm64'
if (platform == 'macOS' || platform == 'darwin') {
return arch == 'x86_64' ? 'macos_x86_64' : 'macos_arm64'
} else if (platform == 'Linux' || platform == 'linux') {
return arch == 'x86_64' ? 'linux' : 'linux_arm64'
} else if (platform == 'Windows' || platform == 'windows') {
return 'windows'
}
return null
}
// ============================================================================
// Content-addressed build cache
// ============================================================================
function content_hash(str) {
var bb = stone(blob(str))
return text(crypto.blake2(bb, 32), 'h')
}
function get_build_dir() {
return shop.get_build_dir()
}
function ensure_dir(path) {
if (fd.stat(path).isDirectory) return
var parts = array(path, '/')
var current = starts_with(path, '/') ? '/' : ''
var i = 0
for (i = 0; i < length(parts); i++) {
if (parts[i] == '') continue
current += parts[i] + '/'
if (!fd.stat(current).isDirectory) fd.mkdir(current)
}
}
Build.ensure_dir = ensure_dir
// ============================================================================
// Compilation
// ============================================================================
// Compile a single C file for a package
// Returns the object file path (content-addressed in .cell/build)
Build.compile_file = function(pkg, file, target, buildtype) {
var _buildtype = buildtype || 'release'
var pkg_dir = shop.get_package_dir(pkg)
var src_path = pkg_dir + '/' + file
if (!fd.is_file(src_path)) {
print('Source file not found: ' + src_path); disrupt
}
// Get flags (with sigil replacement)
var cflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'CFLAGS', target))
var target_cflags = toolchains[target].c_args || []
var cc = toolchains[target].c
// Symbol name for this file
var sym_name = shop.c_symbol_for_file(pkg, file)
// Build command
var cmd_parts = [cc, '-c', '-fPIC']
// Add buildtype-specific flags
if (_buildtype == 'release') {
cmd_parts = array(cmd_parts, ['-O3', '-DNDEBUG'])
} else if (_buildtype == 'debug') {
cmd_parts = array(cmd_parts, ['-O2', '-g'])
} else if (_buildtype == 'minsize') {
cmd_parts = array(cmd_parts, ['-Os', '-DNDEBUG'])
}
push(cmd_parts, '-DCELL_USE_NAME=' + sym_name)
push(cmd_parts, '-I"' + pkg_dir + '"')
// Add package CFLAGS (resolve relative -I paths)
arrfor(cflags, function(flag) {
var f = flag
if (starts_with(f, '-I') && !starts_with(f, '-I/')) {
f = '-I"' + pkg_dir + '/' + text(f, 2) + '"'
}
push(cmd_parts, f)
})
// Add target CFLAGS
arrfor(target_cflags, function(flag) {
push(cmd_parts, flag)
})
push(cmd_parts, '"' + src_path + '"')
var cmd_str = text(cmd_parts, ' ')
// Content hash: command + file content
var file_content = fd.slurp(src_path)
var hash_input = cmd_str + '\n' + text(file_content)
var hash = content_hash(hash_input)
var build_dir = get_build_dir()
ensure_dir(build_dir)
var obj_path = build_dir + '/' + hash
// Check if already compiled
if (fd.is_file(obj_path)) {
return obj_path
}
// Compile
var full_cmd = cmd_str + ' -o "' + obj_path + '"'
log.console('Compiling ' + file)
var ret = os.system(full_cmd)
if (ret != 0) {
print('Compilation failed: ' + file); disrupt
}
return obj_path
}
// Build all C files for a package
// Returns array of object file paths
Build.build_package = function(pkg, target, exclude_main, buildtype) {
var _target = target || Build.detect_host_target()
var _buildtype = buildtype || 'release'
var c_files = pkg_tools.get_c_files(pkg, _target, exclude_main)
var objects = []
arrfor(c_files, function(file) {
var obj = Build.compile_file(pkg, file, _target, _buildtype)
push(objects, obj)
})
return objects
}
// ============================================================================
// Dynamic library building
// ============================================================================
// Compute link key from all inputs that affect the dylib output
function compute_link_key(objects, ldflags, target_ldflags, opts) {
// Sort objects for deterministic hash
var sorted_objects = sort(objects)
// Build a string representing all link inputs
var parts = []
push(parts, 'target:' + opts.target)
push(parts, 'cc:' + opts.cc)
arrfor(sorted_objects, function(obj) {
// Object paths are content-addressed, so the path itself is the hash
push(parts, 'obj:' + obj)
})
arrfor(ldflags, function(flag) {
push(parts, 'ldflag:' + flag)
})
arrfor(target_ldflags, function(flag) {
push(parts, 'target_ldflag:' + flag)
})
return content_hash(text(parts, '\n'))
}
// Build a per-module dynamic library for a single C file
// Returns the content-addressed dylib path in .cell/build/<hash>.<target>.dylib
Build.build_module_dylib = function(pkg, file, target, buildtype) {
var _target = target || Build.detect_host_target()
var _buildtype = buildtype || 'release'
var obj = Build.compile_file(pkg, file, _target, _buildtype)
var tc = toolchains[_target]
var dylib_ext = tc.system == 'windows' ? '.dll' : (tc.system == 'darwin' ? '.dylib' : '.so')
var cc = tc.cpp || tc.c
var local_dir = get_local_dir()
var pkg_dir = shop.get_package_dir(pkg)
// Get link flags
var ldflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'LDFLAGS', _target))
var target_ldflags = tc.c_link_args || []
var resolved_ldflags = []
arrfor(ldflags, function(flag) {
var f = flag
if (starts_with(f, '-L') && !starts_with(f, '-L/')) {
f = '-L"' + pkg_dir + '/' + text(f, 2) + '"'
}
push(resolved_ldflags, f)
})
// Content-addressed output: hash of (object + link flags + target)
var link_key = compute_link_key([obj], resolved_ldflags, target_ldflags, {target: _target, cc: cc})
var build_dir = get_build_dir()
ensure_dir(build_dir)
var dylib_path = build_dir + '/' + link_key + '.' + _target + dylib_ext
if (fd.is_file(dylib_path))
return dylib_path
var cmd_parts = [cc, '-shared', '-fPIC']
if (tc.system == 'darwin') {
cmd_parts = array(cmd_parts, [
'-undefined', 'dynamic_lookup',
'-Wl,-dead_strip',
'-Wl,-rpath,@loader_path/../local',
'-Wl,-rpath,' + local_dir
])
} else if (tc.system == 'linux') {
cmd_parts = array(cmd_parts, [
'-Wl,--allow-shlib-undefined',
'-Wl,--gc-sections',
'-Wl,-rpath,$ORIGIN/../local',
'-Wl,-rpath,' + local_dir
])
} else if (tc.system == 'windows') {
push(cmd_parts, '-Wl,--allow-shlib-undefined')
}
push(cmd_parts, '-L"' + local_dir + '"')
push(cmd_parts, '"' + obj + '"')
cmd_parts = array(cmd_parts, resolved_ldflags)
cmd_parts = array(cmd_parts, target_ldflags)
push(cmd_parts, '-o')
push(cmd_parts, '"' + dylib_path + '"')
var cmd_str = text(cmd_parts, ' ')
log.console('Linking module ' + file + ' -> ' + fd.basename(dylib_path))
var ret = os.system(cmd_str)
if (ret != 0) {
print('Linking failed: ' + file); disrupt
}
// Install to deterministic lib/<pkg>/<stem>.dylib
var file_stem = file
var install_dir = shop.get_lib_dir() + '/' + shop.lib_name_for_package(pkg)
var stem_dir = fd.dirname(file_stem)
if (stem_dir && stem_dir != '.') {
install_dir = install_dir + '/' + stem_dir
}
ensure_dir(install_dir)
var install_path = shop.get_lib_dir() + '/' + shop.lib_name_for_package(pkg) + '/' + file_stem + dylib_ext
fd.slurpwrite(install_path, fd.slurp(dylib_path))
return dylib_path
}
// Build a dynamic library for a package (one dylib per C file)
// Returns array of {file, symbol, dylib} for each module
// Also writes a manifest mapping symbols to dylib paths
Build.build_dynamic = function(pkg, target, buildtype) {
var _target = target || Build.detect_host_target()
var _buildtype = buildtype || 'release'
var c_files = pkg_tools.get_c_files(pkg, _target, true)
var results = []
arrfor(c_files, function(file) {
var sym_name = shop.c_symbol_for_file(pkg, file)
var dylib = Build.build_module_dylib(pkg, file, _target, _buildtype)
push(results, {file: file, symbol: sym_name, dylib: dylib})
})
return results
}
// ============================================================================
// Static binary building
// ============================================================================
// Build a static binary from multiple packages
// packages: array of package names
// output: output binary path
Build.build_static = function(packages, target, output, buildtype) {
var _target = target || Build.detect_host_target()
var _buildtype = buildtype || 'release'
var all_objects = []
var all_ldflags = []
var seen_flags = {}
// Compile all packages
arrfor(packages, function(pkg) {
var is_core = (pkg == 'core')
// For core, include main.c; for others, exclude it
var objects = Build.build_package(pkg, _target, !is_core, _buildtype)
arrfor(objects, function(obj) {
push(all_objects, obj)
})
// Collect LDFLAGS (with sigil replacement)
var ldflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'LDFLAGS', _target))
var pkg_dir = shop.get_package_dir(pkg)
// Deduplicate based on the entire LDFLAGS string for this package
var ldflags_key = pkg + ':' + text(ldflags, ' ')
if (!seen_flags[ldflags_key]) {
seen_flags[ldflags_key] = true
arrfor(ldflags, function(flag) {
var f = flag
if (starts_with(f, '-L') && !starts_with(f, '-L/')) {
f = '-L"' + pkg_dir + '/' + text(f, 2) + '"'
}
push(all_ldflags, f)
})
}
})
if (length(all_objects) == 0) {
print('No object files to link'); disrupt
}
// Link
var cc = toolchains[_target].c
var target_ldflags = toolchains[_target].c_link_args || []
var exe_ext = toolchains[_target].system == 'windows' ? '.exe' : ''
var out_path = output
if (!ends_with(out_path, exe_ext) && exe_ext) {
out_path = out_path + exe_ext
}
var cmd_parts = [cc]
arrfor(all_objects, function(obj) {
push(cmd_parts, '"' + obj + '"')
})
arrfor(all_ldflags, function(flag) {
push(cmd_parts, flag)
})
arrfor(target_ldflags, function(flag) {
push(cmd_parts, flag)
})
push(cmd_parts, '-o', '"' + out_path + '"')
var cmd_str = text(cmd_parts, ' ')
log.console('Linking ' + out_path)
var ret = os.system(cmd_str)
if (ret != 0) {
print('Linking failed: ' + cmd_str); disrupt
}
log.console('Built ' + out_path)
return out_path
}
// ============================================================================
// Native .cm compilation (source → mcode → QBE IL → .o → .dylib)
// ============================================================================
// Post-process QBE IL: insert dead labels after ret/jmp (QBE requirement)
function qbe_insert_dead_labels(il_text) {
var lines = array(il_text, "\n")
var result = []
var dead_id = 0
var need_label = false
var i = 0
var line = null
var trimmed = null
while (i < length(lines)) {
line = lines[i]
trimmed = trim(line)
if (need_label && !starts_with(trimmed, '@') && !starts_with(trimmed, '}') && length(trimmed) > 0) {
push(result, "@_dead_" + text(dead_id))
dead_id = dead_id + 1
need_label = false
}
if (starts_with(trimmed, '@') || starts_with(trimmed, '}') || length(trimmed) == 0) {
need_label = false
}
if (starts_with(trimmed, 'ret ') || starts_with(trimmed, 'jmp ')) {
need_label = true
}
push(result, line)
i = i + 1
}
return text(result, "\n")
}
// Compile a .cm source file to a native .dylib via QBE
// Returns the content-addressed dylib path
Build.compile_native = function(src_path, target, buildtype, pkg) {
var _target = target || Build.detect_host_target()
var _buildtype = buildtype || 'release'
var qbe_rt_path = null
var native_stem = null
var native_install_dir = null
var native_install_path = null
if (!fd.is_file(src_path)) {
print('Source file not found: ' + src_path); disrupt
}
var tc = toolchains[_target]
var dylib_ext = tc.system == 'windows' ? '.dll' : (tc.system == 'darwin' ? '.dylib' : '.so')
var cc = tc.c
// Step 1: Read source and compile through pipeline
var content = fd.slurp(src_path)
var src = text(content)
var tokenize = use('tokenize')
var parse = use('parse')
var fold = use('fold')
var mcode_mod = use('mcode')
var streamline_mod = use('streamline')
var qbe_macros = use('qbe')
var qbe_emit = use('qbe_emit')
var tok_result = tokenize(src, src_path)
var ast = parse(tok_result.tokens, src, src_path, tokenize)
var folded = fold(ast)
var compiled = mcode_mod(folded)
var optimized = streamline_mod(compiled)
// Step 2: Generate QBE IL
var sym_name = null
if (pkg) {
sym_name = shop.c_symbol_for_file(pkg, fd.basename(src_path))
}
var il = qbe_emit(optimized, qbe_macros, sym_name)
// Step 3: Post-process (insert dead labels)
il = qbe_insert_dead_labels(il)
// Content hash for cache key
var hash = content_hash(src + '\n' + _target + '\nnative')
var build_dir = get_build_dir()
ensure_dir(build_dir)
var dylib_path = build_dir + '/' + hash + '.' + _target + dylib_ext
if (fd.is_file(dylib_path))
return dylib_path
// Step 4: Write QBE IL to temp file
var tmp = '/tmp/cell_native_' + hash
var ssa_path = tmp + '.ssa'
var s_path = tmp + '.s'
var o_path = tmp + '.o'
var rt_o_path = '/tmp/cell_qbe_rt.o'
fd.slurpwrite(ssa_path, stone(blob(il)))
// Step 5: QBE compile to assembly
var rc = os.system('qbe -o ' + s_path + ' ' + ssa_path)
if (rc != 0) {
print('QBE compilation failed for: ' + src_path); disrupt
}
// Step 6: Assemble
rc = os.system(cc + ' -c ' + s_path + ' -o ' + o_path)
if (rc != 0) {
print('Assembly failed for: ' + src_path); disrupt
}
// Step 7: Compile QBE runtime stubs if needed
if (!fd.is_file(rt_o_path)) {
qbe_rt_path = shop.get_package_dir('core') + '/qbe_rt.c'
rc = os.system(cc + ' -c ' + qbe_rt_path + ' -o ' + rt_o_path + ' -fPIC')
if (rc != 0) {
print('QBE runtime stubs compilation failed'); disrupt
}
}
// Step 8: Link dylib
var link_cmd = cc + ' -shared -fPIC'
if (tc.system == 'darwin') {
link_cmd = link_cmd + ' -undefined dynamic_lookup'
} else if (tc.system == 'linux') {
link_cmd = link_cmd + ' -Wl,--allow-shlib-undefined'
}
link_cmd = link_cmd + ' ' + o_path + ' ' + rt_o_path + ' -o ' + dylib_path
rc = os.system(link_cmd)
if (rc != 0) {
print('Linking native dylib failed for: ' + src_path); disrupt
}
log.console('Built native: ' + fd.basename(dylib_path))
// Install to deterministic lib/<pkg>/<stem>.dylib
if (pkg) {
native_stem = fd.basename(src_path)
native_install_dir = shop.get_lib_dir() + '/' + shop.lib_name_for_package(pkg)
ensure_dir(native_install_dir)
native_install_path = native_install_dir + '/' + native_stem + dylib_ext
fd.slurpwrite(native_install_path, fd.slurp(dylib_path))
}
return dylib_path
}
// ============================================================================
// Module table generation (for static builds)
// ============================================================================
// Compile a .cm module to mach bytecode blob
// Returns the raw mach bytes as a blob
Build.compile_cm_to_mach = function(src_path) {
if (!fd.is_file(src_path)) {
print('Source file not found: ' + src_path); disrupt
}
var src = text(fd.slurp(src_path))
var tokenize = use('tokenize')
var parse = use('parse')
var fold = use('fold')
var mcode_mod = use('mcode')
var streamline_mod = use('streamline')
var json = use('json')
var tok_result = tokenize(src, src_path)
var ast = parse(tok_result.tokens, src, src_path, tokenize)
var folded = fold(ast)
var compiled = mcode_mod(folded)
var optimized = streamline_mod(compiled)
return mach_compile_mcode_bin(src_path, json.encode(optimized))
}
// Generate a module_table.c file that embeds mach bytecode for .cm modules
// modules: array of {name, src_path} — name is the module name, src_path is the .cm file
// output: path to write the generated .c file
Build.generate_module_table = function(modules, output) {
var lines = []
var json = use('json')
push(lines, '/* Generated module table — do not edit */')
push(lines, '#include <stddef.h>')
push(lines, '#include <string.h>')
push(lines, '')
push(lines, 'struct cell_embedded_entry {')
push(lines, ' const char *name;')
push(lines, ' const unsigned char *data;')
push(lines, ' size_t size;')
push(lines, '};')
push(lines, '')
var entries = []
arrfor(modules, function(mod) {
var safe = replace(replace(replace(mod.name, '/', '_'), '.', '_'), '-', '_')
var mach = Build.compile_cm_to_mach(mod.src_path)
var bytes = array(mach)
var hex = []
arrfor(bytes, function(b) {
push(hex, '0x' + text(b, 'h2'))
})
push(lines, 'static const unsigned char mod_' + safe + '_data[] = {')
push(lines, ' ' + text(hex, ', '))
push(lines, '};')
push(lines, '')
push(entries, safe)
log.console('Embedded: ' + mod.name + ' (' + text(length(bytes)) + ' bytes)')
})
// Lookup function
push(lines, 'const struct cell_embedded_entry *cell_embedded_module_lookup(const char *name) {')
arrfor(modules, function(mod, i) {
var safe = entries[i]
push(lines, ' if (strcmp(name, "' + mod.name + '") == 0) {')
push(lines, ' static const struct cell_embedded_entry e = {"' + mod.name + '", mod_' + safe + '_data, sizeof(mod_' + safe + '_data)};')
push(lines, ' return &e;')
push(lines, ' }')
})
push(lines, ' return (void *)0;')
push(lines, '}')
var c_text = text(lines, '\n')
fd.slurpwrite(output, stone(blob(c_text)))
log.console('Generated ' + output)
return output
}
// ============================================================================
// Convenience functions
// ============================================================================
// Build dynamic libraries for all installed packages
Build.build_all_dynamic = function(target, buildtype) {
var _target = target || Build.detect_host_target()
var _buildtype = buildtype || 'release'
var packages = shop.list_packages()
var results = []
var core_mods = null
// Build core first
if (find(packages, function(p) { return p == 'core' }) != null) {
core_mods = Build.build_dynamic('core', _target, _buildtype)
push(results, {package: 'core', modules: core_mods})
}
// Build other packages
arrfor(packages, function(pkg) {
if (pkg == 'core') return
var pkg_mods = Build.build_dynamic(pkg, _target, _buildtype)
push(results, {package: pkg, modules: pkg_mods})
})
return results
}
return Build

1
cake/playdate.cm Normal file
View File

@@ -0,0 +1 @@
// cake file for making a playdate package

13
cell.toml Normal file
View File

@@ -0,0 +1,13 @@
[compilation]
CFLAGS = "-Isource -Wno-incompatible-pointer-types -Wno-missing-braces -Wno-strict-prototypes -Wno-unused-function -Wno-int-conversion"
LDFLAGS = "-lstdc++ -lm"
[compilation.macos_arm64]
CFLAGS = "-x objective-c"
LDFLAGS = "-framework CoreFoundation -framework CFNetwork"
[compilation.playdate]
CFLAGS = "-DMINIZ_NO_TIME -DTARGET_EXTENSION -DTARGET_PLAYDATE -I$LOCAL/PlaydateSDK/C_API"
[compilation.windows]
LDFLAGS = "-lws2_32 -lwinmm -liphlpapi -lbcrypt -lwinhttp -static-libgcc -static-libstdc++"

467
cellfs.cm Normal file
View File

@@ -0,0 +1,467 @@
var cellfs = {}
// CellFS: A filesystem implementation using miniz and raw OS filesystem
// Supports mounting multiple sources (fs, zip) and named mounts (@name)
var fd = use('fd')
var miniz = use('miniz')
var qop = use('qop')
var wildstar = use('wildstar')
// Internal state
var mounts = [] // Array of {source, type, handle, name}
var writepath = "."
// Helper to normalize paths
function normalize_path(path) {
if (!path) return ""
// Remove leading/trailing slashes and normalize
return replace(path, /^\/+|\/+$/, "")
}
// Check if a file exists in a specific mount
function mount_exists(mount, path) {
var result = false
var _check = null
if (mount.type == 'zip') {
_check = function() {
mount.handle.mod(path)
result = true
} disruption {}
_check()
} else if (mount.type == 'qop') {
_check = function() {
result = mount.handle.stat(path) != null
} disruption {}
_check()
} else {
var full_path = fd.join_paths(mount.source, path)
_check = function() {
var st = fd.stat(full_path)
result = st.isFile || st.isDirectory
} disruption {}
_check()
}
return result
}
// Check if a path refers to a directory in a specific mount
function is_directory(path) {
var res = resolve(path)
var mount = res.mount
var result = false
var _check = null
if (mount.type == 'zip') {
_check = function() {
result = mount.handle.is_directory(path)
} disruption {}
_check()
} else if (mount.type == 'qop') {
_check = function() {
result = mount.handle.is_directory(path)
} disruption {}
_check()
} else {
var full_path = fd.join_paths(mount.source, path)
_check = function() {
var st = fd.stat(full_path)
result = st.isDirectory
} disruption {}
_check()
}
return result
}
// Resolve a path to a specific mount and relative path
// Returns { mount, path } or throws/returns null
function resolve(path, must_exist) {
path = normalize_path(path)
// Check for named mount
if (starts_with(path, "@")) {
var idx = search(path, "/")
var mount_name = ""
var rel_path = ""
if (idx == null) {
mount_name = text(path, 1)
rel_path = ""
} else {
mount_name = text(path, 1, idx)
rel_path = text(path, idx + 1)
}
// Find named mount
var mount = null
arrfor(mounts, function(m) {
if (m.name == mount_name) {
mount = m
return true
}
}, false, true)
if (!mount) {
print("Unknown mount point: @" + mount_name); disrupt
}
return { mount: mount, path: rel_path }
}
// Search path
var found_mount = null
arrfor(mounts, function(mount) {
if (mount_exists(mount, path)) {
found_mount = { mount: mount, path: path }
return true
}
}, false, true)
if (found_mount) {
return found_mount
}
if (must_exist) {
print("File not found in any mount: " + path); disrupt
}
}
// Mount a source
function mount(source, name) {
// Check if source exists
var st = fd.stat(source)
var mount_info = {
source: source,
name: name || null,
type: 'fs',
handle: null,
zip_blob: null
}
if (st.isDirectory) {
mount_info.type = 'fs'
} else if (st.isFile) {
var blob = fd.slurp(source)
var qop_archive = null
var _try_qop = function() {
qop_archive = qop.open(blob)
} disruption {}
_try_qop()
if (qop_archive) {
mount_info.type = 'qop'
mount_info.handle = qop_archive
mount_info.zip_blob = blob // keep blob alive
} else {
var zip = miniz.read(blob)
if (!is_object(zip) || !is_function(zip.count)) {
print("Invalid archive file (not zip or qop): " + source); disrupt
}
mount_info.type = 'zip'
mount_info.handle = zip
mount_info.zip_blob = blob // keep blob alive
}
} else {
print("Unsupported mount source type: " + source); disrupt
}
push(mounts, mount_info)
}
// Unmount
function unmount(name_or_source) {
mounts = filter(mounts, function(mount) {
return mount.name != name_or_source && mount.source != name_or_source
})
}
// Read file
function slurp(path) {
var res = resolve(path, true)
if (!res) { print("File not found: " + path); disrupt }
if (res.mount.type == 'zip') {
return res.mount.handle.slurp(res.path)
} else if (res.mount.type == 'qop') {
var data = res.mount.handle.read(res.path)
if (!data) { print("File not found in qop: " + path); disrupt }
return data
} else {
var full_path = fd.join_paths(res.mount.source, res.path)
return fd.slurp(full_path)
}
}
// Write file
function slurpwrite(path, data) {
var full_path = writepath + "/" + path
var f = fd.open(full_path, 'w')
fd.write(f, data)
fd.close(f)
}
// Check existence
function exists(path) {
var res = resolve(path, false)
if (starts_with(path, "@")) {
return mount_exists(res.mount, res.path)
}
return res != null
}
// Stat
function stat(path) {
var res = resolve(path, true)
if (!res) { print("File not found: " + path); disrupt }
if (res.mount.type == 'zip') {
var mod = res.mount.handle.mod(res.path)
return {
filesize: 0,
modtime: mod * 1000,
isDirectory: false
}
} else if (res.mount.type == 'qop') {
var s = res.mount.handle.stat(res.path)
if (!s) { print("File not found in qop: " + path); disrupt }
return {
filesize: s.size,
modtime: s.modtime,
isDirectory: s.isDirectory
}
} else {
var full_path = fd.join_paths(res.mount.source, res.path)
var s = fd.stat(full_path)
return {
filesize: s.size,
modtime: s.mtime,
isDirectory: s.isDirectory
}
}
}
// Get search paths
function searchpath() {
return array(mounts)
}
// Mount a package using the shop system
function mount_package(name) {
if (name == null) {
mount('.', null)
return
}
var shop = use('internal/shop')
var dir = shop.get_package_dir(name)
if (!dir) {
print("Package not found: " + name); disrupt
}
mount(dir, name)
}
// New functions for qjs_io compatibility
function match(str, pattern) {
return wildstar.match(pattern, str, wildstar.WM_PATHNAME | wildstar.WM_PERIOD | wildstar.WM_WILDSTAR)
}
function rm(path) {
var res = resolve(path, true)
if (res.mount.type != 'fs') { print("Cannot delete from non-fs mount"); disrupt }
var full_path = fd.join_paths(res.mount.source, res.path)
var st = fd.stat(full_path)
if (st.isDirectory) fd.rmdir(full_path)
else fd.unlink(full_path)
}
function mkdir(path) {
var full = fd.join_paths(writepath, path)
fd.mkdir(full)
}
function set_writepath(path) {
writepath = path
}
function basedir() {
return fd.getcwd()
}
function prefdir(org, app) {
return "./"
}
function realdir(path) {
var res = resolve(path, false)
if (!res) return null
return fd.join_paths(res.mount.source, res.path)
}
function enumerate(path, recurse) {
if (path == null) path = ""
var res = resolve(path, true)
var results = []
function visit(curr_full, rel_prefix) {
var list = fd.readdir(curr_full)
if (!list) return
arrfor(list, function(item) {
var item_rel = rel_prefix ? rel_prefix + "/" + item : item
push(results, item_rel)
if (recurse) {
var st = fd.stat(fd.join_paths(curr_full, item))
if (st.isDirectory) {
visit(fd.join_paths(curr_full, item), item_rel)
}
}
})
}
if (res.mount.type == 'fs') {
var full = fd.join_paths(res.mount.source, res.path)
var st = fd.stat(full)
if (st && st.isDirectory) {
visit(full, "")
}
} else if (res.mount.type == 'qop') {
var all = res.mount.handle.list()
var prefix = res.path ? res.path + "/" : ""
var prefix_len = length(prefix)
// Use a set to avoid duplicates if we are simulating directories
var seen = {}
arrfor(all, function(p) {
if (starts_with(p, prefix)) {
var rel = text(p, prefix_len)
if (length(rel) == 0) return
if (!recurse) {
var slash = search(rel, '/')
if (slash != null) {
rel = text(rel, 0, slash)
}
}
if (!seen[rel]) {
seen[rel] = true
push(results, rel)
}
}
})
}
return results
}
function globfs(globs, dir) {
if (dir == null) dir = ""
var res = resolve(dir, true)
var results = []
function check_neg(path) {
var result = false
arrfor(globs, function(g) {
if (starts_with(g, "!") && wildstar.match(text(g, 1), path, wildstar.WM_WILDSTAR)) {
result = true
return true
}
}, false, true)
return result
}
function check_pos(path) {
var result = false
arrfor(globs, function(g) {
if (!starts_with(g, "!") && wildstar.match(g, path, wildstar.WM_WILDSTAR)) {
result = true
return true
}
}, false, true)
return result
}
function visit(curr_full, rel_prefix) {
if (rel_prefix && check_neg(rel_prefix)) return
var list = fd.readdir(curr_full)
if (!list) return
arrfor(list, function(item) {
var item_rel = rel_prefix ? rel_prefix + "/" + item : item
var child_full = fd.join_paths(curr_full, item)
var st = fd.stat(child_full)
if (st.isDirectory) {
if (!check_neg(item_rel)) {
visit(child_full, item_rel)
}
} else {
if (!check_neg(item_rel) && check_pos(item_rel)) {
push(results, item_rel)
}
}
})
}
if (res.mount.type == 'fs') {
var full = fd.join_paths(res.mount.source, res.path)
var st = fd.stat(full)
if (st && st.isDirectory) {
visit(full, "")
}
} else if (res.mount.type == 'qop') {
var all = res.mount.handle.list()
var prefix = res.path ? res.path + "/" : ""
var prefix_len = length(prefix)
arrfor(all, function(p) {
if (starts_with(p, prefix)) {
var rel = text(p, prefix_len)
if (length(rel) == 0) return
if (!check_neg(rel) && check_pos(rel)) {
push(results, rel)
}
}
})
}
return results
}
// Exports
cellfs.mount = mount
cellfs.mount_package = mount_package
cellfs.unmount = unmount
cellfs.slurp = slurp
cellfs.slurpwrite = slurpwrite
cellfs.exists = exists
cellfs.is_directory = is_directory
cellfs.stat = stat
cellfs.searchpath = searchpath
cellfs.match = match
cellfs.enumerate = enumerate
cellfs.globfs = globfs
cellfs.rm = rm
cellfs.mkdir = mkdir
cellfs.writepath = set_writepath
cellfs.basedir = basedir
cellfs.prefdir = prefdir
cellfs.realdir = realdir
cellfs.mount('.')
return cellfs

224
clean.ce Normal file
View File

@@ -0,0 +1,224 @@
// cell clean [<scope>] - Remove cached material to force refetch/rebuild
//
// Usage:
// cell clean Clean build outputs for current directory package
// cell clean . Clean build outputs for current directory package
// cell clean <locator> Clean build outputs for specific package
// cell clean shop Clean entire shop
// cell clean world Clean all world packages
//
// Options:
// --build Remove build outputs only (default)
// --fetch Remove fetched sources only
// --all Remove both build outputs and fetched sources
// --deep Apply to full dependency closure
// --dry-run Show what would be deleted
var shop = use('internal/shop')
var pkg = use('package')
var fd = use('fd')
var scope = null
var clean_build = false
var clean_fetch = false
var deep = false
var dry_run = false
var i = 0
var resolved = null
var deps = null
for (i = 0; i < length(args); i++) {
if (args[i] == '--build') {
clean_build = true
} else if (args[i] == '--fetch') {
clean_fetch = true
} else if (args[i] == '--all') {
clean_build = true
clean_fetch = true
} else if (args[i] == '--deep') {
deep = true
} else if (args[i] == '--dry-run') {
dry_run = true
} else if (args[i] == '--help' || args[i] == '-h') {
log.console("Usage: cell clean [<scope>] [options]")
log.console("")
log.console("Remove cached material to force refetch/rebuild.")
log.console("")
log.console("Scopes:")
log.console(" <locator> Clean specific package")
log.console(" shop Clean entire shop")
log.console(" world Clean all world packages")
log.console("")
log.console("Options:")
log.console(" --build Remove build outputs only (default)")
log.console(" --fetch Remove fetched sources only")
log.console(" --all Remove both build outputs and fetched sources")
log.console(" --deep Apply to full dependency closure")
log.console(" --dry-run Show what would be deleted")
$stop()
} else if (!starts_with(args[i], '-')) {
scope = args[i]
}
}
// Default to --build if nothing specified
if (!clean_build && !clean_fetch) {
clean_build = true
}
// Default scope to current directory
if (!scope) {
scope = '.'
}
// Resolve local paths for single package scope
var is_shop_scope = (scope == 'shop')
var is_world_scope = (scope == 'world')
if (!is_shop_scope && !is_world_scope) {
if (scope == '.' || starts_with(scope, './') || starts_with(scope, '../') || fd.is_dir(scope)) {
resolved = fd.realpath(scope)
if (resolved) {
scope = resolved
}
}
}
var files_to_delete = []
var dirs_to_delete = []
// Gather packages to clean
var packages_to_clean = []
var _gather = null
if (is_shop_scope) {
packages_to_clean = shop.list_packages()
} else if (is_world_scope) {
// For now, world is the same as shop
packages_to_clean = shop.list_packages()
} else {
// Single package
push(packages_to_clean, scope)
if (deep) {
_gather = function() {
deps = pkg.gather_dependencies(scope)
arrfor(deps, function(dep) {
push(packages_to_clean, dep)
})
} disruption {
// Skip if can't read dependencies
}
_gather()
}
}
// Gather files to clean
var lib_dir = shop.get_lib_dir()
var build_dir = shop.get_build_dir()
var packages_dir = replace(shop.get_package_dir(''), /\/$/, '') // Get base packages dir
if (clean_build) {
if (is_shop_scope) {
// Clean entire build and lib directories
if (fd.is_dir(build_dir)) {
push(dirs_to_delete, build_dir)
}
if (fd.is_dir(lib_dir)) {
push(dirs_to_delete, lib_dir)
}
} else {
// Clean specific package libraries
arrfor(packages_to_clean, function(p) {
if (p == 'core') return
var lib_name = shop.lib_name_for_package(p)
var dylib_ext = '.dylib'
var lib_path = lib_dir + '/' + lib_name + dylib_ext
if (fd.is_file(lib_path)) {
push(files_to_delete, lib_path)
}
// Also check for .so and .dll
var so_path = lib_dir + '/' + lib_name + '.so'
var dll_path = lib_dir + '/' + lib_name + '.dll'
if (fd.is_file(so_path)) {
push(files_to_delete, so_path)
}
if (fd.is_file(dll_path)) {
push(files_to_delete, dll_path)
}
})
}
}
if (clean_fetch) {
if (is_shop_scope) {
// Clean entire packages directory (dangerous!)
if (fd.is_dir(packages_dir)) {
push(dirs_to_delete, packages_dir)
}
} else {
// Clean specific package directories
arrfor(packages_to_clean, function(p) {
if (p == 'core') return
var pkg_dir = shop.get_package_dir(p)
if (fd.is_dir(pkg_dir) || fd.is_link(pkg_dir)) {
push(dirs_to_delete, pkg_dir)
}
})
}
}
// Execute or report
var deleted_count = 0
if (dry_run) {
log.console("Would delete:")
if (length(files_to_delete) == 0 && length(dirs_to_delete) == 0) {
log.console(" (nothing to clean)")
} else {
arrfor(files_to_delete, function(f) {
log.console(" [file] " + f)
})
arrfor(dirs_to_delete, function(d) {
log.console(" [dir] " + d)
})
}
} else {
arrfor(files_to_delete, function(f) {
var _del = function() {
fd.unlink(f)
log.console("Deleted: " + f)
deleted_count++
} disruption {
log.error("Failed to delete " + f)
}
_del()
})
arrfor(dirs_to_delete, function(d) {
var _del = function() {
if (fd.is_link(d)) {
fd.unlink(d)
} else {
fd.rmdir(d, 1) // recursive
}
log.console("Deleted: " + d)
deleted_count++
} disruption {
log.error("Failed to delete " + d)
}
_del()
})
if (deleted_count == 0) {
log.console("Nothing to clean.")
} else {
log.console("")
log.console("Clean complete: " + text(deleted_count) + " item(s) deleted.")
}
}
$stop()

128
clone.ce Normal file
View File

@@ -0,0 +1,128 @@
// cell clone <origin> <path>
// Clones a cell package <origin> to the local <path>, and links it.
var shop = use('internal/shop')
var link = use('link')
var fd = use('fd')
var http = use('http')
var miniz = use('miniz')
var resolved = null
var cwd = null
var parent = null
if (length(args) < 2) {
log.console("Usage: cell clone <origin> <path>")
log.console("Clones a cell package to a local path and links it.")
$stop()
}
var origin = args[0]
var target_path = args[1]
// Resolve target path to absolute
if (target_path == '.' || starts_with(target_path, './') || starts_with(target_path, '../')) {
resolved = fd.realpath(target_path)
if (resolved) {
target_path = resolved
} else {
// Path doesn't exist yet, resolve relative to cwd
cwd = fd.realpath('.')
if (target_path == '.') {
target_path = cwd
} else if (starts_with(target_path, './')) {
target_path = cwd + text(target_path, 1)
} else if (starts_with(target_path, '../')) {
// Go up one directory from cwd
parent = fd.dirname(cwd)
target_path = parent + text(target_path, 2)
}
}
}
// Check if target already exists
if (fd.is_dir(target_path)) {
log.console("Error: " + target_path + " already exists")
$stop()
}
log.console("Cloning " + origin + " to " + target_path + "...")
// Get the latest commit
var info = shop.resolve_package_info(origin)
if (!info || info == 'local') {
log.console("Error: " + origin + " is not a remote package")
$stop()
}
// Update to get the commit hash
var update_result = shop.update(origin)
if (!update_result) {
log.console("Error: Could not fetch " + origin)
$stop()
}
// Fetch and extract to the target path
var lock = shop.load_lock()
var entry = lock[origin]
if (!entry || !entry.commit) {
log.console("Error: No commit found for " + origin)
$stop()
}
var download_url = shop.get_download_url(origin, entry.commit)
log.console("Downloading from " + download_url)
var zip_blob = null
var zip = null
var count = 0
var i = 0
var filename = null
var first_slash = null
var rel_path = null
var full_path = null
var dir_path = null
var _clone = function() {
zip_blob = http.fetch(download_url)
// Extract zip to target path
zip = miniz.read(zip_blob)
if (!zip) {
log.console("Error: Failed to read zip archive")
$stop()
}
// Create target directory
fd.mkdir(target_path)
count = zip.count()
for (i = 0; i < count; i++) {
if (zip.is_directory(i)) continue
filename = zip.get_filename(i)
first_slash = search(filename, '/')
if (first_slash == null) continue
if (first_slash + 1 >= length(filename)) continue
rel_path = text(filename, first_slash + 1)
full_path = target_path + '/' + rel_path
dir_path = fd.dirname(full_path)
// Ensure directory exists
if (!fd.is_dir(dir_path)) {
fd.mkdir(dir_path)
}
fd.slurpwrite(full_path, zip.slurp(filename))
}
log.console("Extracted to " + target_path)
// Link the origin to the cloned path
link.add(origin, target_path, shop)
log.console("Linked " + origin + " -> " + target_path)
} disruption {
log.console("Error during clone")
}
_clone()
$stop()

92
compare_aot.ce Normal file
View File

@@ -0,0 +1,92 @@
// compare_aot.ce — compile a .cm module via both paths and compare results
//
// Usage:
// cell --dev compare_aot.ce <module.cm>
var build = use('build')
var fd_mod = use('fd')
var os = use('os')
var json = use('json')
var show = function(v) {
return json.encode(v)
}
if (length(args) < 1) {
print('usage: cell --dev compare_aot.ce <module.cm>')
return
}
var file = args[0]
if (!fd_mod.is_file(file)) {
if (!ends_with(file, '.cm') && fd_mod.is_file(file + '.cm'))
file = file + '.cm'
else {
print('file not found: ' + file)
return
}
}
var abs = fd_mod.realpath(file)
// Shared compilation front-end
var tokenize = use('tokenize')
var parse_mod = use('parse')
var fold = use('fold')
var mcode_mod = use('mcode')
var streamline_mod = use('streamline')
var src = text(fd_mod.slurp(abs))
var tok = tokenize(src, abs)
var ast = parse_mod(tok.tokens, src, abs, tokenize)
var folded = fold(ast)
var compiled = mcode_mod(folded)
var optimized = streamline_mod(compiled)
// --- Interpreted (mach VM) ---
print('--- interpreted ---')
var mcode_json = json.encode(optimized)
var mach_blob = mach_compile_mcode_bin(abs, mcode_json)
var result_interp = mach_load(mach_blob, stone({}))
print('result: ' + show(result_interp))
// --- Native (AOT via QBE) ---
print('\n--- native ---')
var dylib_path = build.compile_native(abs, null, null, null)
print('dylib: ' + dylib_path)
var handle = os.dylib_open(dylib_path)
if (!handle) {
print('failed to open dylib')
return
}
// Build env with runtime functions. Must include starts_with etc. because
// the GC can lose global object properties after compaction.
var env = stone({
logical: logical,
some: some,
every: every,
starts_with: starts_with,
ends_with: ends_with,
log: log,
fallback: fallback,
parallel: parallel,
race: race,
sequence: sequence
})
var result_native = os.native_module_load(handle, env)
print('result: ' + show(result_native))
// --- Comparison ---
print('\n--- comparison ---')
var s_interp = show(result_interp)
var s_native = show(result_native)
if (s_interp == s_native) {
print('MATCH')
} else {
print('MISMATCH')
print(' interp: ' + s_interp)
print(' native: ' + s_native)
}

27
compile.ce Normal file
View File

@@ -0,0 +1,27 @@
// compile.ce — compile a .cm or .ce file to native .dylib via QBE
//
// Usage:
// cell compile <file.cm|file.ce>
//
// Installs the dylib to .cell/lib/<pkg>/<stem>.dylib
var shop = use('internal/shop')
var build = use('build')
var fd = use('fd')
if (length(args) < 1) {
print('usage: cell compile <file.cm|file.ce>')
return
}
var file = args[0]
if (!fd.is_file(file)) {
print('file not found: ' + file)
return
}
var abs = fd.realpath(file)
var file_info = shop.file_info(abs)
var pkg = file_info.package
build.compile_native(abs, null, null, pkg)

98
compile_seed.ce Normal file
View File

@@ -0,0 +1,98 @@
// compile_seed.ce — compile a .cm module to native .dylib via QBE (seed mode)
// Usage: ./cell --dev --seed compile_seed <file.cm>
var fd = use("fd")
var os = use("os")
var tokenize = use("tokenize")
var parse = use("parse")
var fold = use("fold")
var mcode = use("mcode")
var streamline = use("streamline")
var qbe_macros = use("qbe")
var qbe_emit = use("qbe_emit")
if (length(args) < 1) {
print("usage: cell --dev --seed compile_seed <file.cm>")
disrupt
}
var file = args[0]
var base = file
if (ends_with(base, ".cm")) {
base = text(base, 0, length(base) - 3)
} else if (ends_with(base, ".ce")) {
base = text(base, 0, length(base) - 3)
}
var safe = replace(replace(replace(base, "/", "_"), "-", "_"), ".", "_")
var symbol = "js_" + safe + "_use"
var tmp = "/tmp/qbe_" + safe
var ssa_path = tmp + ".ssa"
var s_path = tmp + ".s"
var o_path = tmp + ".o"
var rt_o_path = "/tmp/qbe_rt.o"
var dylib_path = file + ".dylib"
var rc = 0
// Step 1: compile to QBE IL
print("compiling " + file + " to QBE IL...")
var src = text(fd.slurp(file))
var result = tokenize(src, file)
var ast = parse(result.tokens, src, file, tokenize)
var folded = fold(ast)
var compiled = mcode(folded)
var optimized = streamline(compiled)
var il = qbe_emit(optimized, qbe_macros)
// Step 2: append wrapper function
var wrapper = `
export function l $${symbol}(l %ctx) {
@entry
%result =l call $cell_rt_module_entry(l %ctx)
ret %result
}
`
il = il + wrapper
// Write IL to file — remove old file first to avoid leftover content
if (fd.is_file(ssa_path)) fd.unlink(ssa_path)
var out_fd = fd.open(ssa_path, 1537, 420)
fd.write(out_fd, il)
fd.close(out_fd)
print("wrote " + ssa_path + " (" + text(length(il)) + " bytes)")
// Step 3: compile QBE IL to assembly
print("qbe compile...")
rc = os.system("qbe -o " + s_path + " " + ssa_path)
if (rc != 0) {
print("qbe compilation failed")
disrupt
}
// Step 4: assemble
print("assemble...")
rc = os.system("cc -c " + s_path + " -o " + o_path)
if (rc != 0) {
print("assembly failed")
disrupt
}
// Step 5: compile runtime stubs
if (!fd.is_file(rt_o_path)) {
print("compile runtime stubs...")
rc = os.system("cc -c source/qbe_helpers.c -o " + rt_o_path + " -fPIC -Isource")
if (rc != 0) {
print("runtime stubs compilation failed")
disrupt
}
}
// Step 6: link dylib
print("link...")
rc = os.system("cc -shared -fPIC -undefined dynamic_lookup " + o_path + " " + rt_o_path + " -o " + dylib_path)
if (rc != 0) {
print("linking failed")
disrupt
}
print("built: " + dylib_path)

222
config.ce Normal file
View File

@@ -0,0 +1,222 @@
// cell config - Manage system and actor configurations
var toml = use('toml')
var pkg = use('package')
function print_help() {
log.console("Usage: cell config <command> [options]")
log.console("")
log.console("Commands:")
log.console(" get <key> Get a configuration value")
log.console(" set <key> <value> Set a configuration value")
log.console(" list List all configurations")
log.console(" actor <name> get <key> Get actor-specific config")
log.console(" actor <name> set <key> <val> Set actor-specific config")
log.console(" actor <name> list List actor configurations")
log.console("")
log.console("Examples:")
log.console(" cell config get system.ar_timer")
log.console(" cell config set system.net_service 0.2")
log.console(" cell config actor prosperon/_sdl_video set resolution 1920x1080")
log.console(" cell config actor extramath/spline set precision high")
log.console("")
log.console("System keys:")
log.console(" system.ar_timer - Seconds before idle actor reclamation")
log.console(" system.actor_memory - MB of memory an actor can use (0=unbounded)")
log.console(" system.net_service - Seconds per network service pull")
log.console(" system.reply_timeout - Seconds to hold callback for replies (0=unbounded)")
log.console(" system.actor_max - Max number of simultaneous actors")
log.console(" system.stack_max - MB of memory each actor's stack can grow to")
}
// Parse a dot-notation key into path segments
function parse_key(key) {
return array(key, '.')
}
// Get a value from nested object using path
function get_nested(obj, path) {
var current = obj
arrfor(path, function(segment) {
if (is_null(current) || !is_object(current)) return null
current = current[segment]
})
return current
}
// Set a value in nested object using path
function set_nested(obj, path, value) {
var current = obj
var i = 0
var segment = null
for (i = 0; i < length(path) - 1; i++) {
segment = path[i]
if (is_null(current[segment]) || !is_object(current[segment])) {
current[segment] = {}
}
current = current[segment]
}
current[path[length(path) - 1]] = value
}
// Parse value string into appropriate type
function parse_value(str) {
var num_str = null
var n = null
// Boolean
if (str == 'true') return true
if (str == 'false') return false
// Number
num_str = replace(str, /_/g, '')
n = number(num_str)
if (n != null) return n
// String
return str
}
// Format value for display
function format_value(val) {
if (is_text(val)) return '"' + val + '"'
return text(val)
}
// Print configuration tree recursively
function print_config(obj, pfx) {
var p = pfx || ''
arrfor(array(obj), function(key) {
var val = obj[key]
var full_key = p ? p + '.' + key : key
if (is_object(val))
print_config(val, full_key)
else if (!is_null(val))
log.console(full_key + ' = ' + format_value(val))
})
}
// Main command handling
if (length(args) == 0) {
print_help()
$stop()
}
var config = pkg.load_config()
if (!config) {
log.error("Failed to load cell.toml")
$stop()
}
var command = args[0]
var key = null
var path = null
var value = null
var value_str = null
var valid_system_keys = null
var actor_name = null
var actor_cmd = null
if (command == 'help' || command == '-h' || command == '--help') {
print_help()
} else if (command == 'list') {
log.console("# Cell Configuration")
log.console("")
print_config(config)
} else if (command == 'get') {
if (length(args) < 2) {
log.error("Usage: cell config get <key>")
$stop()
}
key = args[1]
path = parse_key(key)
value = get_nested(config, path)
if (value == null) {
log.error("Key not found: " + key)
} else if (is_object(value)) {
print_config(value, key)
} else {
log.console(key + ' = ' + format_value(value))
}
} else if (command == 'set') {
if (length(args) < 3) {
log.error("Usage: cell config set <key> <value>")
$stop()
}
key = args[1]
value_str = args[2]
path = parse_key(key)
value = parse_value(value_str)
if (path[0] == 'system') {
valid_system_keys = [
'ar_timer', 'actor_memory', 'net_service',
'reply_timeout', 'actor_max', 'stack_max'
]
if (find(valid_system_keys, path[1]) == null) {
log.error("Invalid system key. Valid keys: " + text(valid_system_keys, ', '))
$stop()
}
}
set_nested(config, path, value)
pkg.save_config(config)
log.console("Set " + key + " = " + format_value(value))
} else if (command == 'actor') {
if (length(args) < 3) {
log.error("Usage: cell config actor <name> <command> [options]")
$stop()
}
actor_name = args[1]
actor_cmd = args[2]
config.actors = config.actors || {}
config.actors[actor_name] = config.actors[actor_name] || {}
if (actor_cmd == 'list') {
if (length(array(config.actors[actor_name])) == 0) {
log.console("No configuration for actor: " + actor_name)
} else {
log.console("# Configuration for actor: " + actor_name)
log.console("")
print_config(config.actors[actor_name], 'actors.' + actor_name)
}
} else if (actor_cmd == 'get') {
if (length(args) < 4) {
log.error("Usage: cell config actor <name> get <key>")
$stop()
}
key = args[3]
path = parse_key(key)
value = get_nested(config.actors[actor_name], path)
if (value == null) {
log.error("Key not found for actor " + actor_name + ": " + key)
} else {
log.console('actors.' + actor_name + '.' + key + ' = ' + format_value(value))
}
} else if (actor_cmd == 'set') {
if (length(args) < 5) {
log.error("Usage: cell config actor <name> set <key> <value>")
$stop()
}
key = args[3]
value_str = args[4]
path = parse_key(key)
value = parse_value(value_str)
set_nested(config.actors[actor_name], path, value)
pkg.save_config(config)
log.console("Set actors." + actor_name + "." + key + " = " + format_value(value))
} else {
log.error("Unknown actor command: " + actor_cmd)
log.console("Valid commands: list, get, set")
}
} else {
log.error("Unknown command: " + command)
print_help()
}
$stop()

247
crypto.c Normal file
View File

@@ -0,0 +1,247 @@
#include "cell.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "monocypher.h"
/*
Crypto Module Documentation
This module provides cryptographic functions using the Monocypher library.
All inputs and outputs are Blobs.
Functions:
- keypair() -> { public: Blob(256 bits), private: Blob(256 bits) }
Generates a new random X25519 keypair.
- shared(public_key, private_key) -> Blob(256 bits)
Computes a shared secret from your private key and another's public key (X25519).
Input keys must be 256 bits (32 bytes).
- blake2(data, [hash_size_bytes=32]) -> Blob
Computes the BLAKE2b hash of the data.
Default hash size is 32 bytes (256 bits). Supports 1-64 bytes.
- sign(secret_key, message) -> Blob(512 bits)
Signs a message using EdDSA.
secret_key must be 512 bits (64 bytes).
(Note: If you have a 32-byte seed, extend it first or use appropriate key generation).
Returns a 64-byte signature.
- verify(signature, public_key, message) -> bool
Verifies an EdDSA signature.
signature: 512 bits (64 bytes).
public_key: 256 bits (32 bytes).
Returns true if valid, false otherwise.
- lock(key, nonce, message, [ad]) -> Blob
Encrypts and authenticates a message using XChaCha20-Poly1305.
key: 256 bits (32 bytes).
nonce: 192 bits (24 bytes).
ad: Optional associated data (Blob).
Returns a blob containing the ciphertext followed by the 16-byte MAC.
- unlock(key, nonce, ciphertext_with_mac, [ad]) -> Blob or null
Decrypts and verifies a message.
key: 256 bits (32 bytes).
nonce: 192 bits (24 bytes).
ciphertext_with_mac: Must include the 16-byte MAC at the end.
ad: Optional associated data (Blob).
Returns the plaintext Blob if successful, or null if verification fails.
*/
// Helper to get blob data and check exact bit length
static void *get_blob_check_bits(JSContext *js, JSValue val, size_t expected_bits, const char *name) {
size_t bits;
void* result = js_get_blob_data_bits(js, &bits, val);
if (result == -1) {
return NULL; // Exception already thrown by js_get_blob_data_bits
}
if (bits != expected_bits) {
JS_ThrowTypeError(js, "%s: expected %zu bits, got %zu", name, expected_bits, bits);
return NULL;
}
return result;
}
// Helper to get any blob data (checking it is a stoned blob)
static void *get_blob_any(JSContext *js, JSValue val, size_t *out_bits, const char *name) {
void *result = js_get_blob_data_bits(js, out_bits, val);
if (result == -1)
return NULL;
return result;
}
JSValue js_crypto_shared(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 2) {
return JS_ThrowTypeError(js, "crypto.shared: expected public_key, private_key");
}
uint8_t *pub = get_blob_check_bits(js, argv[0], 256, "crypto.shared public_key");
if (!pub) return JS_EXCEPTION;
uint8_t *priv = get_blob_check_bits(js, argv[1], 256, "crypto.shared private_key");
if (!priv) return JS_EXCEPTION;
uint8_t shared[32];
crypto_x25519(shared, priv, pub);
return js_new_blob_stoned_copy(js, shared, 32);
}
JSValue js_crypto_blake2(JSContext *js, JSValue self, int argc, JSValue *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js, "crypto.blake2: expected data blob");
size_t data_bits;
uint8_t *data = get_blob_any(js, argv[0], &data_bits, "crypto.blake2 data");
if (!data) return JS_EXCEPTION;
int32_t hash_len = 32;
if (argc > 1) {
if (JS_ToInt32(js, &hash_len, argv[1]))
return JS_EXCEPTION;
if (hash_len < 1 || hash_len > 64)
return JS_ThrowRangeError(js, "crypto.blake2: hash length must be between 1 and 64 bytes");
}
uint8_t hash[64];
// Use (bits + 7) / 8 to get byte length covering all bits
crypto_blake2b(hash, hash_len, data, (data_bits + 7) / 8);
return js_new_blob_stoned_copy(js, hash, hash_len);
}
JSValue js_crypto_sign(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 2) return JS_ThrowTypeError(js, "crypto.sign: expected secret_key, message");
uint8_t *sk = get_blob_check_bits(js, argv[0], 512, "crypto.sign secret_key");
if (!sk) return JS_EXCEPTION;
size_t msg_bits;
uint8_t *msg = get_blob_any(js, argv[1], &msg_bits, "crypto.sign message");
if (!msg) return JS_EXCEPTION;
uint8_t sig[64];
crypto_eddsa_sign(sig, sk, msg, (msg_bits + 7) / 8);
return js_new_blob_stoned_copy(js, sig, 64);
}
JSValue js_crypto_verify(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 3) return JS_ThrowTypeError(js, "crypto.verify: expected signature, public_key, message");
uint8_t *sig = get_blob_check_bits(js, argv[0], 512, "crypto.verify signature");
if (!sig) return JS_EXCEPTION;
uint8_t *pk = get_blob_check_bits(js, argv[1], 256, "crypto.verify public_key");
if (!pk) return JS_EXCEPTION;
size_t msg_bits;
uint8_t *msg = get_blob_any(js, argv[2], &msg_bits, "crypto.verify message");
if (!msg) return JS_EXCEPTION;
int ret = crypto_eddsa_check(sig, pk, msg, (msg_bits + 7) / 8);
return JS_NewBool(js, ret == 0);
}
JSValue js_crypto_lock(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 3) return JS_ThrowTypeError(js, "crypto.lock: expected key, nonce, message, [ad]");
uint8_t *key = get_blob_check_bits(js, argv[0], 256, "crypto.lock key");
if (!key) return JS_EXCEPTION;
uint8_t *nonce = get_blob_check_bits(js, argv[1], 192, "crypto.lock nonce");
if (!nonce) return JS_EXCEPTION;
size_t msg_bits;
uint8_t *msg = get_blob_any(js, argv[2], &msg_bits, "crypto.lock message");
if (!msg) return JS_EXCEPTION;
size_t msg_len = (msg_bits + 7) / 8;
size_t ad_len = 0;
uint8_t *ad = NULL;
if (argc > 3 && !JS_IsNull(argv[3])) {
size_t ad_bits;
ad = get_blob_any(js, argv[3], &ad_bits, "crypto.lock ad");
if (!ad) return JS_EXCEPTION;
ad_len = (ad_bits + 7) / 8;
}
size_t out_len = msg_len + 16;
uint8_t *out = malloc(out_len);
if (!out) return JS_ThrowOutOfMemory(js);
// Output: [Ciphertext (msg_len)] [MAC (16)]
crypto_aead_lock(out, out + msg_len, key, nonce, ad, ad_len, msg, msg_len);
JSValue ret = js_new_blob_stoned_copy(js, out, out_len);
free(out);
return ret;
}
JSValue js_crypto_unlock(JSContext *js, JSValue self, int argc, JSValue *argv) {
if (argc < 3) return JS_ThrowTypeError(js, "crypto.unlock: expected key, nonce, ciphertext, [ad]");
uint8_t *key = get_blob_check_bits(js, argv[0], 256, "crypto.unlock key");
if (!key) return JS_EXCEPTION;
uint8_t *nonce = get_blob_check_bits(js, argv[1], 192, "crypto.unlock nonce");
if (!nonce) return JS_EXCEPTION;
size_t cipher_bits;
uint8_t *cipher = get_blob_any(js, argv[2], &cipher_bits, "crypto.unlock ciphertext");
if (!cipher) return JS_EXCEPTION;
size_t cipher_len = (cipher_bits + 7) / 8;
if (cipher_len < 16) return JS_ThrowTypeError(js, "crypto.unlock: ciphertext too short (min 16 bytes)");
size_t msg_len = cipher_len - 16;
size_t ad_len = 0;
uint8_t *ad = NULL;
if (argc > 3 && !JS_IsNull(argv[3])) {
size_t ad_bits;
ad = get_blob_any(js, argv[3], &ad_bits, "crypto.unlock ad");
if (!ad) return JS_EXCEPTION;
ad_len = (ad_bits + 7) / 8;
}
uint8_t *out = malloc(msg_len > 0 ? msg_len : 1);
if (!out) return JS_ThrowOutOfMemory(js);
// MAC is at cipher + msg_len
const uint8_t *mac = cipher + msg_len;
if (crypto_aead_unlock(out, mac, key, nonce, ad, ad_len, cipher, msg_len) != 0) {
free(out);
return JS_NULL;
}
JSValue ret = js_new_blob_stoned_copy(js, out, msg_len);
free(out);
return ret;
}
static const JSCFunctionListEntry js_crypto_funcs[] = {
JS_CFUNC_DEF("shared", 2, js_crypto_shared),
JS_CFUNC_DEF("blake2", 2, js_crypto_blake2),
JS_CFUNC_DEF("sign", 2, js_crypto_sign),
JS_CFUNC_DEF("verify", 3, js_crypto_verify),
JS_CFUNC_DEF("lock", 3, js_crypto_lock),
JS_CFUNC_DEF("unlock", 3, js_crypto_unlock),
};
JSValue js_core_crypto_use(JSContext *js)
{
JS_FRAME(js);
JS_ROOT(mod, JS_NewObject(js));
JS_SetPropertyFunctionList(js, mod.val, js_crypto_funcs, sizeof(js_crypto_funcs)/sizeof(js_crypto_funcs[0]));
JS_RETURN(mod.val);
}

29
debug/debug.c Normal file
View File

@@ -0,0 +1,29 @@
#include "cell.h"
// TODO: Reimplement stack depth for register VM
JSC_CCALL(debug_stack_depth, return number2js(js, 0))
// TODO: Reimplement debug introspection for register VM
JSC_CCALL(debug_build_backtrace, return JS_NewArray(js))
JSC_CCALL(debug_closure_vars, return JS_NewObject(js))
JSC_CCALL(debug_set_closure_var, return JS_NULL;)
JSC_CCALL(debug_local_vars, return JS_NewObject(js))
JSC_CCALL(debug_fn_info, return JS_NewObject(js))
JSC_CCALL(debug_backtrace_fns, return JS_NewArray(js))
static const JSCFunctionListEntry js_debug_funcs[] = {
MIST_FUNC_DEF(debug, stack_depth, 0),
MIST_FUNC_DEF(debug, build_backtrace, 0),
MIST_FUNC_DEF(debug, closure_vars, 1),
MIST_FUNC_DEF(debug, set_closure_var, 3),
MIST_FUNC_DEF(debug, local_vars, 1),
MIST_FUNC_DEF(debug, fn_info, 1),
MIST_FUNC_DEF(debug, backtrace_fns,0),
};
JSValue js_core_debug_use(JSContext *js) {
JS_FRAME(js);
JS_ROOT(mod, JS_NewObject(js));
JS_SetPropertyFunctionList(js, mod.val, js_debug_funcs, countof(js_debug_funcs));
JS_RETURN(mod.val);
}

28
debug/js.c Normal file
View File

@@ -0,0 +1,28 @@
#include "cell.h"
JSC_CCALL(os_mem_limit, JS_SetMemoryLimit(JS_GetRuntime(js), js2number(js,argv[0])))
JSC_CCALL(os_max_stacksize, JS_SetMaxStackSize(js, js2number(js,argv[0])))
// TODO: Reimplement memory usage reporting for new allocator
JSC_CCALL(os_calc_mem,
ret = JS_NewObject(js);
)
// TODO: Reimplement for register VM
JSC_CCALL(js_disassemble, return JS_NewArray(js);)
JSC_CCALL(js_fn_info, return JS_NewObject(js);)
static const JSCFunctionListEntry js_js_funcs[] = {
MIST_FUNC_DEF(os, calc_mem, 0),
MIST_FUNC_DEF(os, mem_limit, 1),
MIST_FUNC_DEF(os, max_stacksize, 1),
MIST_FUNC_DEF(js, disassemble, 1),
MIST_FUNC_DEF(js, fn_info, 1),
};
JSValue js_core_js_use(JSContext *js) {
JS_FRAME(js);
JS_ROOT(mod, JS_NewObject(js));
JS_SetPropertyFunctionList(js, mod.val, js_js_funcs, countof(js_js_funcs));
JS_RETURN(mod.val);
}

264
diff.ce Normal file
View File

@@ -0,0 +1,264 @@
// diff.ce — differential testing: run tests optimized vs unoptimized, compare results
//
// Usage:
// cell diff - diff all test files in current package
// cell diff suite - diff a specific test file (tests/suite.cm)
// cell diff tests/foo - diff a specific test file by path
var shop = use('internal/shop')
var pkg = use('package')
var fd = use('fd')
var time = use('time')
var _args = args == null ? [] : args
var analyze = use('os').analyze
var run_ast_fn = use('os').run_ast_fn
var run_ast_noopt_fn = use('os').run_ast_noopt_fn
if (!run_ast_noopt_fn) {
log.console("error: run_ast_noopt_fn not available (rebuild bootstrap)")
$stop()
return
}
// Parse arguments: diff [test_path]
var target_test = null
if (length(_args) > 0) {
target_test = _args[0]
}
function is_valid_package(dir) {
var _dir = dir == null ? '.' : dir
return fd.is_file(_dir + '/cell.toml')
}
if (!is_valid_package('.')) {
log.console('No cell.toml found in current directory')
$stop()
return
}
// Collect test files
function collect_tests(specific_test) {
var files = pkg.list_files(null)
var test_files = []
var i = 0
var f = null
var test_name = null
var match_name = null
var match_base = null
for (i = 0; i < length(files); i++) {
f = files[i]
if (starts_with(f, "tests/") && ends_with(f, ".cm")) {
if (specific_test) {
test_name = text(f, 0, -3)
match_name = specific_test
if (!starts_with(match_name, 'tests/')) match_name = 'tests/' + match_name
match_base = ends_with(match_name, '.cm') ? text(match_name, 0, -3) : match_name
if (test_name != match_base) continue
}
push(test_files, f)
}
}
return test_files
}
// Deep comparison of two values
function values_equal(a, b) {
var i = 0
var ka = null
var kb = null
if (a == b) return true
if (is_null(a) && is_null(b)) return true
if (is_null(a) || is_null(b)) return false
if (is_array(a) && is_array(b)) {
if (length(a) != length(b)) return false
i = 0
while (i < length(a)) {
if (!values_equal(a[i], b[i])) return false
i = i + 1
}
return true
}
if (is_object(a) && is_object(b)) {
ka = array(a)
kb = array(b)
if (length(ka) != length(kb)) return false
i = 0
while (i < length(ka)) {
if (!values_equal(a[ka[i]], b[ka[i]])) return false
i = i + 1
}
return true
}
return false
}
function describe(val) {
if (is_null(val)) return "null"
if (is_text(val)) return `"${val}"`
if (is_number(val)) return text(val)
if (is_logical(val)) return text(val)
if (is_function(val)) return "<function>"
if (is_array(val)) return `[array length=${text(length(val))}]`
if (is_object(val)) return `{record keys=${text(length(array(val)))}}`
return "<unknown>"
}
// Run a single test file through both paths
function diff_test_file(file_path) {
var mod_path = text(file_path, 0, -3)
var src_path = fd.realpath('.') + '/' + file_path
var src = null
var ast = null
var mod_opt = null
var mod_noopt = null
var results = {file: file_path, tests: [], passed: 0, failed: 0, errors: []}
var use_pkg = fd.realpath('.')
var opt_error = null
var noopt_error = null
var keys = null
var i = 0
var k = null
var opt_result = null
var noopt_result = null
var opt_err = null
var noopt_err = null
var _run_one_opt = null
var _run_one_noopt = null
// Build env for module loading
var make_env = function() {
return stone({
use: function(path) {
return shop.use(path, use_pkg)
}
})
}
// Read and parse
var _read = function() {
src = text(fd.slurp(src_path))
ast = analyze(src, src_path)
} disruption {
push(results.errors, `failed to parse ${file_path}`)
return results
}
_read()
if (length(results.errors) > 0) return results
// Run optimized
var _run_opt = function() {
mod_opt = run_ast_fn(mod_path, ast, make_env())
} disruption {
opt_error = "disrupted"
}
_run_opt()
// Run unoptimized
var _run_noopt = function() {
mod_noopt = run_ast_noopt_fn(mod_path, ast, make_env())
} disruption {
noopt_error = "disrupted"
}
_run_noopt()
// Compare module-level behavior
if (opt_error != noopt_error) {
push(results.errors, `module load mismatch: opt=${opt_error != null ? opt_error : "ok"} noopt=${noopt_error != null ? noopt_error : "ok"}`)
results.failed = results.failed + 1
return results
}
if (opt_error != null) {
// Both disrupted during load — that's consistent
results.passed = results.passed + 1
push(results.tests, {name: "<module>", status: "passed"})
return results
}
// If module returns a record of functions, test each one
if (is_object(mod_opt) && is_object(mod_noopt)) {
keys = array(mod_opt)
while (i < length(keys)) {
k = keys[i]
if (is_function(mod_opt[k]) && is_function(mod_noopt[k])) {
opt_result = null
noopt_result = null
opt_err = null
noopt_err = null
_run_one_opt = function() {
opt_result = mod_opt[k]()
} disruption {
opt_err = "disrupted"
}
_run_one_opt()
_run_one_noopt = function() {
noopt_result = mod_noopt[k]()
} disruption {
noopt_err = "disrupted"
}
_run_one_noopt()
if (opt_err != noopt_err) {
push(results.tests, {name: k, status: "failed"})
push(results.errors, `${k}: disruption mismatch opt=${opt_err != null ? opt_err : "ok"} noopt=${noopt_err != null ? noopt_err : "ok"}`)
results.failed = results.failed + 1
} else if (!values_equal(opt_result, noopt_result)) {
push(results.tests, {name: k, status: "failed"})
push(results.errors, `${k}: result mismatch opt=${describe(opt_result)} noopt=${describe(noopt_result)}`)
results.failed = results.failed + 1
} else {
push(results.tests, {name: k, status: "passed"})
results.passed = results.passed + 1
}
}
i = i + 1
}
} else {
// Compare direct return values
if (!values_equal(mod_opt, mod_noopt)) {
push(results.tests, {name: "<return>", status: "failed"})
push(results.errors, `return value mismatch: opt=${describe(mod_opt)} noopt=${describe(mod_noopt)}`)
results.failed = results.failed + 1
} else {
push(results.tests, {name: "<return>", status: "passed"})
results.passed = results.passed + 1
}
}
return results
}
// Main
var test_files = collect_tests(target_test)
log.console(`Differential testing: ${text(length(test_files))} file(s)`)
var total_passed = 0
var total_failed = 0
var i = 0
var result = null
var j = 0
while (i < length(test_files)) {
result = diff_test_file(test_files[i])
log.console(` ${result.file}: ${text(result.passed)} passed, ${text(result.failed)} failed`)
j = 0
while (j < length(result.errors)) {
log.console(` MISMATCH: ${result.errors[j]}`)
j = j + 1
}
total_passed = total_passed + result.passed
total_failed = total_failed + result.failed
i = i + 1
}
log.console(`----------------------------------------`)
log.console(`Diff: ${text(total_passed)} passed, ${text(total_failed)} failed, ${text(total_passed + total_failed)} total`)
if (total_failed > 0) {
log.console(`DIFFERENTIAL FAILURES DETECTED`)
}
$stop()

92
docs/_index.md Normal file
View File

@@ -0,0 +1,92 @@
---
title: "Documentation"
description: "ƿit language documentation"
type: "docs"
---
![image](/images/wizard.png)
ƿit is an actor-based scripting language for building concurrent applications. It combines a familiar C-like syntax with the actor model of computation, optimized for low memory usage and simplicity.
## Key Features
- **Actor Model** — isolated memory, message passing, no shared state
- **Immutability** — `stone()` makes values permanently frozen
- **Prototype Inheritance** — objects without classes
- **C Integration** — seamlessly extend with native code
- **Cross-Platform** — deploy to desktop, web, and embedded
## Quick Start
```javascript
// hello.ce - A simple actor
print("Hello, ƿit!")
$stop()
```
```bash
pit hello
```
## Language
- [**ƿit Language**](/docs/language/) — syntax, types, and operators
- [**Actors and Modules**](/docs/actors/) — the execution model
- [**Requestors**](/docs/requestors/) — asynchronous composition
- [**Packages**](/docs/packages/) — code organization and sharing
- [**Shop Architecture**](/docs/shop/) — module resolution, compilation, and caching
## Reference
- [**Built-in Functions**](/docs/functions/) — intrinsics reference
- [text](/docs/library/text/) — text conversion and manipulation
- [number](/docs/library/number/) — numeric conversion and operations
- [array](/docs/library/array/) — array creation and manipulation
- [object](/docs/library/object/) — object creation, prototypes, and serialization
## Standard Library
Modules loaded with `use()`:
- [blob](/docs/library/blob/) — binary data
- [time](/docs/library/time/) — time and dates
- [math](/docs/library/math/) — trigonometry and math
- [json](/docs/library/json/) — JSON encoding/decoding
- [random](/docs/library/random/) — random numbers
## Tools
- [**Command Line**](/docs/cli/) — the `pit` tool
- [**Testing**](/docs/testing/) — writing and running tests
- [**Writing C Modules**](/docs/c-modules/) — native extensions
## Architecture
ƿit programs are organized into **packages**. Each package contains:
- **Modules** (`.cm`) — return a value, cached and frozen
- **Actors** (`.ce`) — run independently, communicate via messages
- **C files** (`.c`) — compiled to native libraries
Actors never share memory. They communicate by sending messages, which are automatically serialized. This makes concurrent programming safe and predictable.
## Installation
```bash
# Clone and bootstrap
git clone https://gitea.pockle.world/john/cell
cd cell
make bootstrap
```
The ƿit shop is stored at `~/.pit/`.
## Development
After making changes, recompile with:
```bash
make
```
Run `cell --help` to see all available CLI flags.

263
docs/actors.md Normal file
View File

@@ -0,0 +1,263 @@
---
title: "Actors and Modules"
description: "The ƿit execution model"
weight: 20
type: "docs"
---
ƿit organizes code into two types of scripts: **modules** (`.cm`) and **actors** (`.ce`).
## The Actor Model
ƿit is built on the actor model of computation. Each actor:
- Has its own **isolated memory** — actors never share state
- Runs to completion each **turn** — no preemption
- Performs its own **garbage collection**
- Communicates only through **message passing**
This isolation makes concurrent programming safer and more predictable.
## Modules (.cm)
A module is a script that **returns a value**. The returned value is cached and frozen (made stone).
```javascript
// math_utils.cm
var math = use('math/radians')
var distance = function(x1, y1, x2, y2) {
var dx = x2 - x1
var dy = y2 - y1
return math.sqrt(dx * dx + dy * dy)
}
var midpoint = function(x1, y1, x2, y2) {
return {
x: (x1 + x2) / 2,
y: (y1 + y2) / 2
}
}
return {
distance: distance,
midpoint: midpoint
}
```
**Key properties:**
- **Must return a value** — it's an error not to
- **Executed once per actor** — subsequent `use()` calls return the cached value
- **Return value is stone** — immutable, safe to share
- Modules can import other modules with `use()`
### Using Modules
```javascript
var utils = use('math_utils')
var d = utils.distance(0, 0, 3, 4) // 5
```
## Actors (.ce)
An actor is a script that **does not return a value**. It runs as an independent unit of execution.
```javascript
// worker.ce
print("Worker started")
$receiver(function(msg, reply) {
print("Received:", msg)
// Process message...
})
```
**Key properties:**
- **Must not return a value** — it's an error to return
- Has access to **actor intrinsics** (functions starting with `$`)
- Runs until explicitly stopped or crashes
## Actor Intrinsics
Actors have access to special functions prefixed with `$`:
### $me
Reference to the current actor.
```javascript
print($me) // actor reference
```
### $stop()
Stop the current actor.
```javascript
$stop()
```
### $send(actor, message, callback)
Send a message to another actor.
```javascript
$send(other_actor, {type: "ping", data: 42}, function(reply) {
print("Got reply:", reply)
})
```
Messages are automatically **splatted** — flattened to plain data without prototypes.
### $start(callback, program)
Start a new actor from a script.
```javascript
$start(function(new_actor) {
print("Started:", new_actor)
}, "worker")
```
### $delay(callback, seconds)
Schedule a callback after a delay.
```javascript
$delay(function() {
print("5 seconds later")
}, 5)
```
### $clock(callback)
Get called every frame/tick.
```javascript
$clock(function(dt) {
// Called each tick with delta time
})
```
### $receiver(callback)
Set up a message receiver.
```javascript
$receiver(function(message, reply) {
// Handle incoming message
reply({status: "ok"})
})
```
### $portal(callback, port)
Open a network port.
```javascript
$portal(function(connection) {
// Handle new connection
}, 8080)
```
### $contact(callback, record)
Connect to a remote address.
```javascript
$contact(function(connection) {
// Connected
}, {host: "example.com", port: 80})
```
### $time_limit(requestor, seconds)
Wrap a requestor with a timeout. See [Requestors](/docs/requestors/) for details.
```javascript
$time_limit(my_requestor, 10) // 10 second timeout
```
### $couple(actor)
Couple the current actor to another actor. When the coupled actor dies, the current actor also dies. Coupling is automatic between an actor and its overling (parent).
```javascript
$couple(other_actor)
```
### $unneeded(callback, seconds)
Schedule the actor for removal after a specified time.
```javascript
$unneeded(function() {
// cleanup before removal
}, 30)
```
### $connection(callback, actor, config)
Get information about the connection to another actor, such as latency, bandwidth, and activity.
```javascript
$connection(function(info) {
print(info.latency)
}, other_actor, {})
```
## Module Resolution
When you call `use('name')`, ƿit searches:
1. **Current package** — files relative to package root
2. **Dependencies** — packages declared in `pit.toml`
3. **Core** — built-in ƿit modules
```javascript
// From within package 'myapp':
use('utils') // myapp/utils.cm
use('helper/math') // myapp/helper/math.cm
use('json') // core json module
use('otherlib/foo') // dependency 'otherlib', file foo.cm
```
Files in the `internal/` directory are private to the package.
## Example: Simple Actor System
```javascript
// main.ce - Entry point
var config = use('config')
print("Starting application...")
$start(function(worker) {
$send(worker, {task: "process", data: [1, 2, 3]})
}, "worker")
$delay(function() {
print("Shutting down")
$stop()
}, 10)
```
```javascript
// worker.ce - Worker actor
$receiver(function(msg, reply) {
if (msg.task == "process") {
var result = array(msg.data, x => x * 2)
reply({result: result})
}
})
```
```javascript
// config.cm - Shared configuration
return {
debug: true,
timeout: 30
}
```

View File

@@ -1,29 +0,0 @@
# Cmdline
#### cmds
**array**
[
{
"flag": "l",
"doc": "Set log level."
}
]
#### orders
**object**
#### register_cmd(flag, fn, doc)
#### register_order(order, fn, doc, usage = "")
#### print_order(fn)

View File

@@ -1,140 +0,0 @@
# Color
#### white
**array**
[
1,
1,
1,
1
]
#### black
**array**
[
0,
0,
0,
1
]
#### blue
**array**
[
0.32941176470588235,
0.43137254901960786,
1,
1
]
#### green
**array**
[
0.47058823529411764,
1,
0.0392156862745098,
1
]
#### yellow
**array**
[
0.984313725490196,
1,
0.16862745098039217,
1
]
#### red
**array**
[
1,
0.1411764705882353,
0.0784313725490196,
1
]
#### teal
**array**
[
0.3764705882352941,
0.9882352941176471,
0.9294117647058824,
1
]
#### gray
**array**
[
0.7098039215686275,
0.7098039215686275,
0.7098039215686275,
1
]
#### cyan
**array**
[
0,
1,
1,
1
]
#### purple
**array**
[
0.6352941176470588,
0.36470588235294116,
0.8901960784313725,
1
]
#### editor
**object**
#### tohtml(v)
#### Arkanoid
**object**
#### Gameboy
**object**
#### Apple
**object**
#### Debug
**object**
#### Editor
**object**
#### normalize(c)

View File

@@ -1,35 +0,0 @@
# ColorMap
#### makemap(map)
#### Jet
**object**
[object Object]
#### BlueRed
**object**
[object Object]
#### Inferno
**object**
[object Object]
#### Bathymetry
**object**
[object Object]
#### Viridis
**object**
[object Object]
#### sample(t, map = this)
Sample a given colormap at the given percentage (0 to 1).

View File

@@ -1,58 +0,0 @@
# Ease
#### linear(t)
#### in(t)
#### out(t)
#### inout(t)
#### quad
**object**
#### cubic
**object**
#### quart
**object**
#### quint
**object**
#### expo
**object**
#### bounce
**object**
#### sine
**object**
#### elastic
**object**

View File

@@ -1,23 +0,0 @@
# Event
#### events
**object**
#### observe(name, obj, fn)
#### unobserve(name, obj)
#### rm_obj(obj)
#### notify(name, ...args)

View File

@@ -1,6 +0,0 @@
# Gizmos
#### pick_gameobject_points(worldpos, gameobject, points)

View File

@@ -1,173 +0,0 @@
# Mum
#### padding
**array**
[
0,
0
]
#### offset
**array**
[
0,
0
]
#### font
**string**
#### selectable
**boolean**
#### selected
**boolean**
#### font_size
**number**
#### text_align
**string**
#### scale
**number**
#### angle
**number**
#### anchor
**array**
[
0,
1
]
#### hovered
**object**
#### text_shadow
**object**
#### text_outline
**number**
#### color
**array**
[
1,
1,
1,
1
]
#### margin
**array**
[
0,
0
]
#### width
**number**
#### height
**number**
#### max_width
**number**
#### max_height
**number**
#### image_repeat
**boolean**
#### image_repeat_offset
**array**
[
0,
0
]
#### debug
**boolean**
#### make(def)
#### prestart()
#### start()
#### extend(def)
#### text(def)
#### button(def)
#### window(def)
#### image(def)
#### column(def)
#### debug_colors
**object**

View File

@@ -1,56 +0,0 @@
# Register
#### registries
**array**
[
{},
{
"doc": "Called once per frame."
},
{},
{},
{},
{},
{}
]
#### add_cb(name)
#### appupdate
**object**
#### update
**object**
Called once per frame.
#### physupdate
**object**
#### gui
**object**
#### debug
**object**
#### draw
**object**
#### screengui
**object**

View File

@@ -1,78 +0,0 @@
# Resources
#### replpath(str, path)
#### replstrs(path)
#### scripts
**array**
[
"jsoc",
"jsc",
"jso",
"js"
]
#### images
**array**
[
"png",
"gif",
"jpg",
"jpeg"
]
#### sounds
**array**
[
"wav",
"flac",
"mp3",
"qoa"
]
#### is_image(path)
#### find_image(file)
#### find_sound(file)
#### find_script(file)
#### is_sound(path)
#### is_animation(path)
#### is_path(str)
#### texture
**object**
#### gif
**object**

View File

@@ -1,67 +0,0 @@
# Spline
#### sample_angle(type, points, angle)
#### bezier_loop(cp)
#### bezier_node_count(cp)
#### is_bezier(t)
#### is_catmull(t)
#### bezier2catmull(b)
#### catmull2bezier(c)
Given a set of control points C for a camtull-rom type curve, return a set of cubic bezier points to give the same curve.
#### catmull_loop(cp)
#### catmull_caps(cp)
Given a set of control points cp, return the necessary caps added to the spline.
#### type
**object**
#### bezier_tan_partner(points, i)
#### bezier_cp_mirror(points, i)
#### bezier_point_handles(points, i)
#### bezier_nodes(points)
#### bezier_is_node(points, i)
#### bezier_is_handle(points, i)

View File

@@ -1,27 +0,0 @@
# SpriteAnim
Functions to create Primum animations from varying sources.
#### make(path)
#### gif(path)
Convert a gif.
#### strip(path, frames, time=0.05)
Given a path and number of frames, converts a horizontal strip animation, where each cell is the same width.
#### aseprite(path)
Given an aseprite json metadata, returns an object of animations defined in the aseprite file.
#### validate(anim)
#### find(path)
Given a path, find the relevant animation for the file.

View File

@@ -1,15 +0,0 @@
# Tween
#### default
**object**
#### start(obj, target, tvals, options)
#### make(obj, target, tvals, options)

View File

@@ -1,46 +0,0 @@
# Vector
#### length(v)
#### norm(v)
#### project(a, b)
#### dot(a, b)
#### random()
#### angle_between(a,b)
#### angle(v)
#### rotate(v,angle)
#### equal(v1, v2, tol)
#### reflect(vec, plane)
#### reflect_point(vec, point)

View File

@@ -1,34 +0,0 @@
# actor
#### spawn(script, config, callback)
Create a new actor, using this actor as the master, initializing it with 'script' and with data (as a JSON or Nota file) from 'config'.
#### rm_pawn(pawn)
#### timers
**array**
[]
#### kill()
Remove this actor and all its padawans from existence.
#### interval(fn, seconds)
#### delay(fn, seconds)
Call 'fn' after 'seconds' with 'this' set to the actor.
#### padawans
**array**
[
{}
]

View File

@@ -1,22 +0,0 @@
# ai
#### race(list)
#### sequence(list)
#### parallel(list)
#### dofor(secs, fn)
#### wait(secs = 1)

View File

@@ -1,2 +0,0 @@
# allsprites

View File

@@ -1,6 +0,0 @@
# app
#### die()

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1,17 +0,0 @@
# audio
#### channels
**number**
#### buffer_frames
**number**
#### samplerate
**number**

View File

@@ -1,46 +0,0 @@
# bbox
#### overlap(box1, box2)
#### fromcwh(c, wh)
#### frompoints(points)
#### topoints(bb)
#### tocwh(bb)
#### towh(bb)
#### pointin(bb, p)
#### move(bb, pos)
#### expand(oldbb, x)
#### blwh(bl,wh)
Bounding box from (bottom left, width height)
#### fromobjs(objs)

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1,22 +0,0 @@
# component
#### sprite(obj)
#### edge2d(obj)
#### circle2d(obj)
#### poly2d(obj)
#### seg2d(obj)

View File

@@ -1,68 +0,0 @@
# console
#### print()
#### rec()
#### stdout_lvl
**number**
#### transcript
**string**
#### say(msg)
Write raw text to console, plus a newline.
#### log(msg)
#### pprint(msg, lvl = 0)
#### spam(msg)
#### debug(msg)
#### info(msg)
Output info level message.
#### warn(msg)
Output warn level message.
#### error(msg)
Output error level message, and print stacktrace.
#### panic(msg)
#### stackstr(skip = 0)
#### stack(skip = 0)
Output a stacktrace to console.
#### trace(skip = 0)

View File

@@ -1,14 +0,0 @@
# convert
#### romanize(num)
#### deromanize(str)
#### buf2hex(buffer)

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1,50 +0,0 @@
# debug
#### fn_break(fn,obj = globalThis)
#### draw_phys
**boolean**
#### draw_bb
**boolean**
#### draw_gizmos
**boolean**
#### draw_names
**boolean**
#### draw()
#### inputs
**object**
#### gif
**object**
#### api
**object**
#### log
**object**

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1,74 +0,0 @@
# dspsound
#### noise()
#### pink()
#### red()
#### pitchshift()
#### noise_gate()
#### limiter()
#### compressor()
#### crush()
#### lpf()
#### hpf()
#### delay()
#### fwd_delay()
#### source()
#### mix()
#### master()
#### plugin_node()
#### midi()
#### mod()

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:10] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1,33 +0,0 @@
script:0: [2024-07-03 12:05:54] error, script: ReferenceError :: 'editor' is not defined
at <eval> (<input>)
at <anonymous> (scripts/debug.js:193)
at <anonymous> (scripts/std.js:385)
at cmd_args (scripts/std.js:458)
at <eval> (C eval)
Initializing cpSpace - Chipmunk v7.0.3 (Debug Enabled)
Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks
USE REPORT
scripts/base.js 5.142 ms
scripts/render.js 1.197 ms
scripts/debug.js 521.4 us
scripts/input.js 1.055 ms
scripts/std.js 1.175 ms
scripts/diff.js 194.4 us
scripts/color.js 856.8 us
scripts/gui.js 597.1 us
scripts/tween.js 516.6 us
scripts/ai.js 128.0 us
scripts/physics.js 94.48 us
scripts/geometry.js 189.4 us
scripts/spline.js 253.1 us
scripts/components.js 1.761 ms
scripts/actor.js 185.2 us
scripts/entity.js 2.157 ms
scripts/widget.js 444.3 us
scripts/mum.js 76.63 us
scripts/editor.js 16.03 ms
ENTITY REPORT
scripts/engine.js:501: [2024-07-03 12:05:56] info, script: QUITTING

View File

@@ -1,33 +0,0 @@
script:0: [2024-07-03 12:13:12] error, script: TypeError :: cannot read property 'doc' of undefined
at <anonymous> (scripts/debug.js:179)
at <anonymous> (scripts/debug.js:223)
at <anonymous> (scripts/std.js:385)
at cmd_args (scripts/std.js:458)
at <eval> (C eval)
Initializing cpSpace - Chipmunk v7.0.3 (Debug Enabled)
Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks
USE REPORT
scripts/base.js 5.200 ms
scripts/render.js 1.284 ms
scripts/debug.js 516.9 us
scripts/input.js 970.4 us
scripts/std.js 1.103 ms
scripts/diff.js 230.1 us
scripts/color.js 1.148 ms
scripts/gui.js 665.1 us
scripts/tween.js 498.5 us
scripts/ai.js 125.5 us
scripts/physics.js 93.55 us
scripts/geometry.js 212.2 us
scripts/spline.js 252.9 us
scripts/components.js 1.780 ms
scripts/actor.js 188.5 us
scripts/entity.js 2.101 ms
scripts/widget.js 452.2 us
scripts/mum.js 70.77 us
scripts/editor.js 17.66 ms
ENTITY REPORT
scripts/engine.js:501: [2024-07-03 12:13:13] info, script: QUITTING

View File

@@ -1,2 +0,0 @@
# entityreport

View File

@@ -1,12 +0,0 @@
# esc
Functions and constants for ANSI escape sequences.
#### reset
**string**
#### color(v)

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:10] warn, script: Cannot print the API of something that isn't an object.

View File

@@ -1 +0,0 @@
scripts/debug.js:205: [2024-07-03 12:13:11] warn, script: Cannot print the API of something that isn't an object.

Some files were not shown because too many files have changed in this diff Show More