substrate-lang 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/build/compiler/{binary.5d81a93450b2@0+0.wasm → binary.3823f89ce414@0+0.wasm} +0 -0
  2. package/build/compiler/{checker.343075746d8c@0+0.wasm → checker.592d37dcbec9@0+0.wasm} +0 -0
  3. package/build/compiler/{compile.2db0f824839f@0+0.wasm → compile.86a2b03b0c9b@0+0.wasm} +0 -0
  4. package/build/compiler/{core.11abd90bead5@0+0.wasm → core.fc3dab9d1846@0+0.wasm} +0 -0
  5. package/build/compiler/expander.689d326e5a1b@0+0.wasm +0 -0
  6. package/build/compiler/{fs.3f7cf768e7ed@0+0.wasm → fs.563034be70c3@0+0.wasm} +0 -0
  7. package/build/compiler/{leb128.0d2a247f239f@0+0.wasm → leb128.748b1c37277a@0+0.wasm} +0 -0
  8. package/build/compiler/{link.3c4158bb6ba3@0+0.wasm → link.11b643d35670@0+0.wasm} +0 -0
  9. package/build/compiler/{macros.6f0e1a78d640@0+0.wasm → macros.4083601c00db@0+0.wasm} +0 -0
  10. package/build/compiler/main.ed62cce43000@0+0.wasm +0 -0
  11. package/build/compiler/{ops.a5b9269c5240@0+0.wasm → ops.b361e858d8e1@0+0.wasm} +0 -0
  12. package/build/compiler/{path.ec5532669c81@0+0.wasm → path.dcc4712bcc7b@0+0.wasm} +0 -0
  13. package/build/compiler/program +21 -20
  14. package/build/compiler/{prune.f800615ca8cc@0+0.wasm → prune.d4a3f9834095@0+0.wasm} +0 -0
  15. package/build/compiler/{reader.f4378a1f91d1@0+0.wasm → reader.b535e61f99f4@0+0.wasm} +0 -0
  16. package/build/compiler/roots.6d2942578055@0+0.wasm +0 -0
  17. package/build/compiler/{running.7f03ff780e03@0+0.wasm → running.d73f7826cb74@0+0.wasm} +0 -0
  18. package/build/compiler/{serialize.f4354af92feb@0+0.wasm → serialize.b2196de75bc8@0+0.wasm} +0 -0
  19. package/build/compiler/sha256.5fc9d60f8bb2@0+0.wasm +0 -0
  20. package/build/compiler/substrate.4c780d6dd6d4@0+0.wasm +0 -0
  21. package/build/compiler/{syntax.500cf1bcecd4@0+0.wasm → syntax.9857f6784d63@0+0.wasm} +0 -0
  22. package/build/compiler/{writer.b698107b491f@0+0.wasm → writer.806bc85aa684@0+0.wasm} +0 -0
  23. package/build/sub/{base64.fc39f9b2a664@0+0.wasm → base64.8fba03e1be0a@0+0.wasm} +0 -0
  24. package/build/sub/{build.3a016536f5a5@0+0.wasm → build.84ac996eda63@0+0.wasm} +0 -0
  25. package/build/sub/{chromium.0cdcaad35704@0+0.wasm → chromium.e4db7d29897c@0+0.wasm} +0 -0
  26. package/build/sub/{common.9ea008df47e6@0+0.wasm → common.91ddee6b7a67@0+0.wasm} +0 -0
  27. package/build/sub/deflate.fc8075e3aed1@0+0.wasm +0 -0
  28. package/build/sub/{doc.e0af22e9d586@0+0.wasm → doc.0b48bbac404b@0+0.wasm} +0 -0
  29. package/build/sub/{doc.49b234ac4521@0+0.wasm → doc.566f9861828e@0+0.wasm} +0 -0
  30. package/build/sub/env.f051f8166526@0+0.wasm +0 -0
  31. package/build/sub/events.f952172735e0@0+0.wasm +0 -0
  32. package/build/sub/fetch.097f1cc9502d@0+0.wasm +0 -0
  33. package/build/sub/{fetch.59ad8bf17eeb@0+0.wasm → fetch.5d2f427c995e@0+0.wasm} +0 -0
  34. package/build/sub/{files.25d3fe28ff57@0+0.wasm → files.30e55182c5df@0+0.wasm} +0 -0
  35. package/build/sub/{fs.3f7cf768e7ed@0+0.wasm → fs.563034be70c3@0+0.wasm} +0 -0
  36. package/build/sub/{git.c47e41fed371@0+0.wasm → git.48aefa1644be@0+0.wasm} +0 -0
  37. package/build/sub/{grants.e7dc20c93375@0+0.wasm → grants.5bf25700d47c@0+0.wasm} +0 -0
  38. package/build/sub/{gzip.0bacbb40f6e2@0+0.wasm → gzip.69588e97c35a@0+0.wasm} +0 -0
  39. package/build/sub/{hash.75dc86b3dd19@0+0.wasm → hash.3f0d118da63f@0+0.wasm} +0 -0
  40. package/build/sub/{html.1ab670c5f861@0+0.wasm → html.20baa1dc7ca6@0+0.wasm} +0 -0
  41. package/build/sub/{html.a860b2ff2c4e@0+0.wasm → html.c1671a102b4d@0+0.wasm} +0 -0
  42. package/build/sub/{inflate.16c735654147@0+0.wasm → inflate.8899e0933792@0+0.wasm} +0 -0
  43. package/build/sub/{json.74966c67a96d@0+0.wasm → json.f15a29d99d8d@0+0.wasm} +0 -0
  44. package/build/sub/{manifest.0c0fe02b1e58@0+0.wasm → manifest.cf7471880377@0+0.wasm} +0 -0
  45. package/build/sub/{map.b767b94ffe7f@0+0.wasm → map.dc516eec27ff@0+0.wasm} +0 -0
  46. package/build/sub/{pack.a62f186e997c@0+0.wasm → pack.55992e8cc09c@0+0.wasm} +0 -0
  47. package/build/sub/path.b7a8e1cf3aaa@0+0.wasm +0 -0
  48. package/build/sub/{path.ec5532669c81@0+0.wasm → path.dcc4712bcc7b@0+0.wasm} +0 -0
  49. package/build/sub/{process.94378bb2ecf2@0+0.wasm → process.aea2c88cb7a0@0+0.wasm} +0 -0
  50. package/build/sub/program +48 -48
  51. package/build/sub/{read.4b71de2f3337@0+0.wasm → read.cd1e693f4fb4@0+0.wasm} +0 -0
  52. package/build/sub/{reader.f4378a1f91d1@0+0.wasm → reader.b535e61f99f4@0+0.wasm} +0 -0
  53. package/build/sub/{root.5a3e4a594d25@0+0.wasm → root.9b713ec588c1@0+0.wasm} +0 -0
  54. package/build/sub/roots.6d2942578055@0+0.wasm +0 -0
  55. package/build/sub/{sha256.92185201fb4b@0+0.wasm → sha256.5fc9d60f8bb2@0+0.wasm} +0 -0
  56. package/build/sub/{sha512.bf0d4c469a96@0+0.wasm → sha512.b988b9dc6114@0+0.wasm} +0 -0
  57. package/build/sub/{site.81b7f3938874@0+0.wasm → site.7c6d8c7747af@0+0.wasm} +0 -0
  58. package/build/sub/site.81548474c323@0+0.wasm +0 -0
  59. package/build/sub/{store.128b4d772823@0+0.wasm → store.d4e845ff24ac@0+0.wasm} +0 -0
  60. package/build/sub/{stream.d95d09173ea2@0+0.wasm → stream.4c07247477f7@0+0.wasm} +0 -0
  61. package/build/sub/{sub.84126bd636af@0+0.wasm → sub.b57e17b6876b@0+0.wasm} +0 -0
  62. package/build/sub/{substrate.b31300129ffb@0+0.wasm → substrate.4c780d6dd6d4@0+0.wasm} +0 -0
  63. package/build/sub/{syntax.500cf1bcecd4@0+0.wasm → syntax.9857f6784d63@0+0.wasm} +0 -0
  64. package/build/sub/{tar.9c01735ea170@0+0.wasm → tar.e482cf873cfc@0+0.wasm} +0 -0
  65. package/build/sub/{test.eed7cfa3264c@0+0.wasm → test.0d9c079bb309@0+0.wasm} +0 -0
  66. package/build/sub/{text.ca2b0668e319@0+0.wasm → text.4ab70ac35b5a@0+0.wasm} +0 -0
  67. package/build/sub/{timer.21d74714d40b@0+0.wasm → timer.3809bb17a7a1@0+0.wasm} +0 -0
  68. package/build/sub/{upgrade.61c36d2a50cf@0+0.wasm → upgrade.18a5aa0dae89@0+0.wasm} +0 -0
  69. package/build/sub/{utf8.b61525c6fb12@0+0.wasm → utf8.524c475ecd40@0+0.wasm} +0 -0
  70. package/build/sub/worker.f1190de21b21@0+0.wasm +0 -0
  71. package/build/sub/writer.806bc85aa684@0+0.wasm +0 -0
  72. package/package.json +1 -1
  73. package/std/crypto/sha256.sub +3 -109
  74. package/std/test/session.sub +0 -1
  75. package/substrate/VERSION +1 -1
  76. package/substrate/compiler/expander.sub +187 -55
  77. package/substrate/compiler/main.sub +15 -2
  78. package/substrate/compiler/roots.sub +90 -24
  79. package/substrate/compiler/sha256.sub +110 -0
  80. package/substrate/compiler/substrate.sub +6 -1
  81. package/substrate/host/node/worker-thread.mjs +1 -1
  82. package/substrate/host/node/worker.mjs +1 -0
  83. package/substrate/host/subhost-core.mjs +10 -3
  84. package/substrate/host/subhost.mjs +13 -1
  85. package/substrate/host/web/subhost-web.mjs +13 -2
  86. package/substrate/host/web/worker-script.mjs +1 -0
  87. package/substrate/host/web/worker.mjs +1 -0
  88. package/substrate/host/worker.mjs +3 -1
  89. package/build/compiler/expander.c0f36d0bd5fc@0+0.wasm +0 -0
  90. package/build/compiler/main.cf521803fc5e@0+0.wasm +0 -0
  91. package/build/compiler/roots.02808ca2c6a7@0+0.wasm +0 -0
  92. package/build/compiler/substrate.b31300129ffb@0+0.wasm +0 -0
  93. package/build/sub/deflate.67457f2269ae@0+0.wasm +0 -0
  94. package/build/sub/env.d4a2d3ca5408@0+0.wasm +0 -0
  95. package/build/sub/events.ee8945a7ea00@0+0.wasm +0 -0
  96. package/build/sub/fetch.22f5c88f8a7b@0+0.wasm +0 -0
  97. package/build/sub/path.b98f74b36b19@0+0.wasm +0 -0
  98. package/build/sub/roots.02808ca2c6a7@0+0.wasm +0 -0
  99. package/build/sub/site.b678ce0b53b9@0+0.wasm +0 -0
  100. package/build/sub/worker.5ced1d8ab0d4@0+0.wasm +0 -0
  101. package/build/sub/writer.b698107b491f@0+0.wasm +0 -0
@@ -11,18 +11,19 @@
11
11
  (require-unqualified "checker.sub")
12
12
  (require-unqualified "link.sub")
13
13
  (require-unqualified "roots.sub")
14
+ (require-unqualified "sha256.sub")
14
15
 
15
16
  (provide install-core!
16
17
  compile-module-file
17
18
  expand-module-file
18
- content-hash wasm-module program-wasm-modules trap-report
19
+ wasm-module program-wasm-modules program-compiled-modules trap-report
19
20
  set-cache-directory!
20
- session-open! session-eval! session-eval-text! session-eval-file! session-error session-recover!)
21
+ session-open! session-eval! session-eval-text! session-eval-file! session-error)
21
22
 
22
23
  (define core-forms datum
23
24
  '(func global import supply memory table tag define-syntax begin-for-syntax
24
- begin require require-unqualified language provide set! let let* if block loop br br-if br-table
25
- return
25
+ begin require require-unqualified runtime-require language provide set! let let* if block loop br br-if
26
+ br-table return
26
27
  call-indirect func-index select drop values unreachable nop
27
28
  throw throw-ref try
28
29
  i32.const i64.const f32.const f64.const
@@ -30,7 +31,7 @@
30
31
  #%app #%datum #%fact #%checked))
31
32
 
32
33
  (define visible-core-forms datum
33
- '(define-syntax begin-for-syntax begin require require-unqualified language provide
34
+ '(define-syntax begin-for-syntax begin require require-unqualified runtime-require language provide
34
35
  quote quote-syntax include-text #%app #%datum #%fact))
35
36
 
36
37
  (define wasm-forms datum
@@ -72,12 +73,14 @@
72
73
  (define scope-counter u32 2)
73
74
  (define registry hash-table)
74
75
  (define units-by-hash hash-table)
76
+ (define units-by-name hash-table)
75
77
 
76
78
  (struct wasm-module [phase i32] [bytes datum] [imports datum] [scopes datum] [next (ptr wasm-module)])
77
79
 
78
80
  (struct unit [self datum] [path datum] [name datum] [hash datum] [state datum] [requires datum] [provides datum]
79
81
  [entries (ptr module-entry)] [code datum] [scope u32] [infos datum] [facts datum]
80
- [wasm-modules (ptr wasm-module)] [scope-count u32] [memories datum] [resolved datum] [included datum])
82
+ [wasm-modules (ptr wasm-module)] [scope-count u32] [memories datum] [resolved datum] [included datum]
83
+ [runtime-requires datum])
81
84
 
82
85
  (struct module-entry [symbol datum] [scopes (ptr scope-set)] [phase i32] [binding (ptr binding)] [next (ptr module-entry)])
83
86
 
@@ -102,6 +105,7 @@
102
105
  (set! (-> m scope-count) 0)
103
106
  (set! (-> m resolved) nil)
104
107
  (set! (-> m included) nil)
108
+ (set! (-> m runtime-requires) nil)
105
109
  (-> m self)))
106
110
 
107
111
  (define (unit-of [m datum]) -> (ptr unit) (cast (ptr unit) (record-pointer m)))
@@ -224,16 +228,14 @@
224
228
  out))
225
229
 
226
230
  (define (group-instance [name datum]) -> datum
227
- (let* ([b (datum->string name)] [n (-> b length)] [i u32 0] [dot u32 0] [l running-group] [m datum 0])
231
+ (let* ([b (datum->string name)] [n (-> b length)] [i u32 0] [l running-group] [m datum 0])
228
232
  (while (and (< i n) (!= (@ b i) #\@)) (+= i 1))
229
233
  (unless (and (< (+ i 2) n) (== (@ b (+ i 1)) #\0) (== (@ b (+ i 2)) #\+)) (return 0))
230
234
  (while (pair? l)
231
235
  (let ([g (datum->string (car l))])
232
236
  (when (and (== (-> g length) (+ i 4)) (== (slice g 0 (+ i 1)) (slice b 0 (+ i 1)))) (return (car l))))
233
237
  (set! l (cdr l)))
234
- (while (and (< dot i) (!= (@ b dot) #\.)) (+= dot 1))
235
- (when (>= dot i) (return 0))
236
- (set! m (cast datum (hash-ref (& units-by-hash) (cast u64 (string->symbol (slice b (+ dot 1) i))))))
238
+ (set! m (cast datum (hash-ref (& units-by-name) (cast u64 (string->symbol (slice b 0 i))))))
237
239
  (if (== m 0) 0 (agreeing-instance name m))))
238
240
 
239
241
  (define agreements hash-table)
@@ -262,7 +264,9 @@
262
264
  ;; Keeps macros.sub in the compiler's program.
263
265
  (define macro-tools (fn (datum datum) -> datum) syntax-match-expansion)
264
266
 
267
+ ;; install-core! sets up the compiler in the running program. Calling it again does nothing.
265
268
  (define (install-core!)
269
+ (unless (== running-syntax 0) (return))
266
270
  (for-each (lambda ([name datum])
267
271
  (bind-raw! name (if (memq name visible-core-forms) visible-scopes wasm-scopes) all-phases `(core ,name)))
268
272
  core-forms)
@@ -275,7 +279,7 @@
275
279
  (let* ([names (running-module-names)] [name (running-module-named names "syntax.")] [tools (running-module-named names "macros.")])
276
280
  (when (== name 0) (fail-at 0 "the running program has no syntax module" nil))
277
281
  (set! running-names (keep names))
278
- (set! compiler-hash (keep (content-hash (compiler-names names))))
282
+ (set! compiler-hash (keep (digest (compiler-names names))))
279
283
  (set! syntax-instance (keep name))
280
284
  (set! running-group (keep (group-of (if (!= tools 0) tools name))))
281
285
  (set! running-syntax (running-unit name '"syntax"))
@@ -582,18 +586,28 @@
582
586
  (buffer-free! (& out))
583
587
  s))
584
588
 
585
- (define (content-hash [ss datum]) -> datum
586
- (let ([h u64 14695981039346656037] [digits (array u8 12)])
589
+ ;; digest is the SHA-256, in hex, of a list of strings, each preceded by its length.
590
+ (define (digest [ss datum]) -> datum
591
+ (let ([s sha256] [n (array u8 8)] [out (array u8 32)])
592
+ (sha256-init! (& s))
587
593
  (while (pair? ss)
588
- (let* ([s (datum->string (car ss))] [p (-> s bytes)])
589
- (for ([i u32 0]) (< i (-> s length)) (+= i 1)
590
- (set! h (* (bit-xor h (@ p i)) 1099511628211))))
591
- (set! h (* h 1099511628211))
594
+ (let ([b (cast (slice u8) (datum->string (car ss)))])
595
+ (for ([i u32 0]) (< i 8) (+= i 1) (set! (@ n i) (cast u8 (>> (cast u64 (-> b length)) (* 8 i)))))
596
+ (sha256-add! (& s) (slice n))
597
+ (sha256-add! (& s) b))
592
598
  (set! ss (cdr ss)))
593
- (for ([k 0]) (< k 12) (+= k 1)
594
- (let ([d (cast i32 (bit-and (>> h (- 60 (* k 4))) 15))])
595
- (set! (@ digits k) (if (< d 10) (+ 48 d) (+ 87 d)))))
596
- (string->datum (cast string (slice digits)))))
599
+ (sha256-end! (& s) (slice out))
600
+ (hex-of (slice out))))
601
+
602
+ (define (bytes-digest [b (slice u8)]) -> datum
603
+ (let ([out (array u8 32)]) (sha256-of b (slice out)) (hex-of (slice out))))
604
+
605
+ (define (hex-of [b (slice u8)]) -> datum
606
+ (let ([hex (array u8 64)])
607
+ (for ([i u32 0]) (< i 64) (+= i 1)
608
+ (let* ([x (cast i32 (@ b (/ i 2)))] [d (if (== (% i 2) 0) (>> x 4) (bit-and x 15))])
609
+ (set! (@ hex i) (if (< d 10) (+ 48 d) (+ 87 d)))))
610
+ (string->datum (cast string (slice hex)))))
597
611
 
598
612
  (define (module-hash [path datum] [text datum] [requires datum] [included datum]) -> datum
599
613
  (let ([parts (if (root-under-test? (identity-label path)) `(,path ,text "test") `(,path ,text))])
@@ -604,7 +618,12 @@
604
618
  (while (pair? included)
605
619
  (set! parts (append parts `(,(car (car included)) ,(cdr (car included)))))
606
620
  (set! included (cdr included)))
607
- (content-hash parts)))
621
+ (digest parts)))
622
+
623
+ ;; A module's name is its file name without the extension, a dot, and the first 12 digits of its hash, as in
624
+ ;; counter.f745d27a5fbc.
625
+ (define (module-name [path datum] [hash datum]) -> datum
626
+ (format "~a.~a" `(,(file-stem path) ,(substring hash 0 12))))
608
627
 
609
628
  (define (source-text [id datum]) -> datum (file-text (host-file id)))
610
629
 
@@ -623,6 +642,11 @@
623
642
  (cond [(and (!= known 0) (== (-> (unit-of known) state) 'done)) known]
624
643
  [(!= known 0) (fail-at 0 "cyclic require: ~a requires itself" (list1 path))]
625
644
  [(begin (set! cached (load-cached path)) (!= cached 0)) cached]
645
+ [(compiled-root? path)
646
+ (fail-at where (if (== (compiled-module path) 0)
647
+ "~a is not available to this program's sessions; list it in runtime-require"
648
+ "the program's compiled ~a is inconsistent with its other compiled modules")
649
+ (list1 path))]
626
650
  [(wasm-file? path) (wasm-file-unit path key)]
627
651
  [else
628
652
  (let* ([text (source-text path)] [m (new-unit path (provisional-name path))] [saved current])
@@ -661,7 +685,7 @@
661
685
  (set! (-> u requires) (keep (list1 (cons prelude (make-integer 0)))))
662
686
  (set! (-> u hash) (keep (module-hash path (string->datum (cast string (datum->bytes bytes)))
663
687
  (list1 `(,(-> (unit-of prelude) hash) ,(make-integer 0))) nil)))
664
- (set! (-> u name) (keep (format "~a.~a" `(,(file-stem path) ,(-> u hash)))))
688
+ (set! (-> u name) (keep (module-name path (-> u hash))))
665
689
  (note-hash! m)
666
690
  (set! instance (wasm-module-name m 0 0))
667
691
  (set! linked (link-side-module path bytes (wasm-module-name prelude 0 0)))
@@ -760,7 +784,7 @@
760
784
  (map (lambda ([r datum]) -> datum `(,(-> (unit-of (car r)) hash) ,(cdr r)))
761
785
  (-> m requires))
762
786
  (-> m included))))
763
- (set! (-> m name) (keep (format "~a.~a" `(,(file-stem (-> m path)) ,(-> m hash)))))
787
+ (set! (-> m name) (keep (module-name (-> m path) (-> m hash))))
764
788
  (note-hash! (-> m self))
765
789
  (compile-wasm-modules!)))
766
790
 
@@ -850,7 +874,7 @@
850
874
  (for-each (lambda ([p datum])
851
875
  (let* ([meaning (cdr p)] [base (definition-of meaning)]
852
876
  [d (if (and (!= base 0) (== (definition-module base) m)) (meaning-description meaning) 0)])
853
- (when (!= d 0) (set! out (cons (cons (car p) (content-hash (list1 (format "~s" (list1 d))))) out)))))
877
+ (when (!= d 0) (set! out (cons (cons (car p) (digest (list1 (format "~s" (list1 d))))) out)))))
854
878
  (-> (unit-of m) provides))
855
879
  (reverse out)))
856
880
 
@@ -906,6 +930,29 @@
906
930
  (set! out (visit-wasm-modules m seen out))
907
931
  (reverse out)))
908
932
 
933
+ ;; program-compiled-modules returns the compiled modules that the program's sessions can load: those named in
934
+ ;; runtime-require forms, and everything they require. Each is (identity hash bytes), where bytes is the module's cache
935
+ ;; entry and hash is the SHA-256 of bytes.
936
+ (define (program-compiled-modules [m datum]) -> datum
937
+ (let ([todo nil] [seen nil] [out nil])
938
+ (for-each (lambda ([l datum])
939
+ (let ([u (instance-unit (car l))])
940
+ (unless (== u 0) (set! todo (append (-> (unit-of u) runtime-requires) todo)))))
941
+ (program-wasm-modules m))
942
+ (while (pair? todo)
943
+ (let ([id (car todo)])
944
+ (set! todo (cdr todo))
945
+ (when (== (member id seen) 0)
946
+ (let ([u (unit-of (module-at id 0))] [b (make-buffer)] [bytes datum 0])
947
+ (set! seen (cons id seen))
948
+ (sealed! (& b) (list1 (cache-form (-> u self))))
949
+ (set! bytes (bytes->datum (buffer-bytes (& b))))
950
+ (buffer-free! (& b))
951
+ (set! out (cons `(,id ,(bytes-digest (datum->bytes bytes)) ,bytes) out))
952
+ (set! todo (append (map (lambda ([r datum]) -> datum (-> (unit-of (car r)) path)) (-> u requires))
953
+ (append (-> u runtime-requires) todo)))))))
954
+ (reverse out)))
955
+
909
956
  (define (visit-wasm-modules [m datum] [seen (ptr hash-table)] [out datum]) -> datum
910
957
  (let ([name (wasm-module-name m 0 0)] [l nil])
911
958
  (when (!= (datum-get seen name) 0) (return out))
@@ -971,7 +1018,7 @@
971
1018
  (define cache-directory datum 0)
972
1019
  (define (set-cache-directory! [dir datum]) (set! cache-directory (keep dir)))
973
1020
 
974
- (const cache-format i64 7)
1021
+ (const cache-format i64 8)
975
1022
 
976
1023
  (define compiler-hash datum 0)
977
1024
 
@@ -990,18 +1037,17 @@
990
1037
 
991
1038
  (define (sealed? [s (slice u8)]) -> bool
992
1039
  (let ([n (-> s length)])
993
- (and (>= n 8) (== (@ (cast (ptr u64) (+ (-> s items) (- n 8))) 0) (data-hash (slice (-> s items) (- n 8)))))))
1040
+ (and (>= n 8) (== (@ (cast (ptr u64) (+ (-> s items) (- n 8))) 0) (hash-bytes (slice (-> s items) (- n 8)))))))
994
1041
 
995
- (define (data-hash [s (slice u8)]) -> u64
996
- (let ([h u64 14695981039346656037] [p (-> s items)])
997
- (for ([i u32 0]) (< i (-> s length)) (+= i 1)
998
- (set! h (* (bit-xor h (@ p i)) 1099511628211)))
999
- h))
1042
+ ;; sealed! writes d to b, followed by a checksum that read-data verifies.
1043
+ (define (sealed! [b (ptr buffer)] [d datum])
1044
+ (let* ([data (datum->bytes (data-bytes d))] [h (hash-bytes data)])
1045
+ (buffer-add! b data)
1046
+ (for ([i u64 0]) (< i 64) (+= i 8) (buffer-add-byte! b (cast i32 (bit-and (>> h i) 255))))))
1000
1047
 
1001
1048
  (define (write-data [path datum] [d datum]) -> bool
1002
- (let* ([data (datum->bytes (data-bytes d))] [h (data-hash data)] [b (make-buffer)] [temp string] [ok #f])
1003
- (buffer-add! (& b) data)
1004
- (for ([i u64 0]) (< i 64) (+= i 8) (buffer-add-byte! (& b) (cast i32 (bit-and (>> h i) 255))))
1049
+ (let ([b (make-buffer)] [temp string] [ok #f])
1050
+ (sealed! (& b) d)
1005
1051
  (when (>= (fs-make-temp-file (datum->string cache-directory) "" ".tmp" (& temp) 0) 0)
1006
1052
  (set! ok (and (>= (fs-write-file temp (buffer-bytes (& b)) 0) 0) (>= (fs-rename temp (datum->string path) 0) 0)))
1007
1053
  (unless ok (fs-remove temp #f 0))
@@ -1028,8 +1074,10 @@
1028
1074
  (equal? (section d 'format) (make-integer cache-format))
1029
1075
  (equal? (section d 'compiler) compiler-hash)))
1030
1076
 
1077
+ ;; load-cached loads a module from the cache, or from the program's compiled modules if that is where the module comes
1078
+ ;; from.
1031
1079
  (define (load-cached [path datum]) -> datum
1032
- (if (== (cache-compiler) 0)
1080
+ (if (if (compiled-root? path) (== (compiled-module path) 0) (== (cache-compiler) 0))
1033
1081
  0
1034
1082
  (begin
1035
1083
  (begin-module-arena)
@@ -1038,20 +1086,25 @@
1038
1086
  m))))
1039
1087
 
1040
1088
  (define (load-cached-in [path datum]) -> datum
1041
- (let* ([ds (read-data (cache-file (cache-name path)))]
1089
+ (let* ([shipped (compiled-module path)]
1090
+ [ds (if (!= shipped 0) (compiled-data (cadr shipped)) (read-data (cache-file (cache-name path))))]
1042
1091
  [d (if (pair? ds) (car ds) 0)]
1043
1092
  [key (cast u64 (symbol-of path))]
1044
1093
  [hash datum 0] [requires datum 0] [included datum 0] [known datum 0] [m datum 0])
1094
+ (when (and (!= shipped 0) (== d 0)) (fail-at 0 "the program's compiled ~a is missing or damaged" (list1 path)))
1095
+ (when (and (!= shipped 0) (not (current-cache? d)))
1096
+ (fail-at 0 "the program's compiled modules were built by a different compiler" nil))
1045
1097
  (unless (current-cache? d) (return 0))
1046
1098
  (set! hash (section d 'hash))
1047
1099
  (set! requires (section d 'requires))
1048
- (set! included (included-again (section d 'included)))
1049
- (unless (and (string? hash) (!= included 0)
1050
- (equal? (module-hash path (source-text path)
1051
- (map (lambda ([r datum]) -> datum (cdr r)) requires)
1052
- included)
1053
- hash))
1054
- (return 0))
1100
+ (unless (string? hash) (return 0))
1101
+ (when (== shipped 0)
1102
+ (set! included (included-again (section d 'included)))
1103
+ (unless (and (!= included 0)
1104
+ (equal? (module-hash path (source-text path) (map (lambda ([r datum]) -> datum (cdr r)) requires)
1105
+ included)
1106
+ hash))
1107
+ (return 0)))
1055
1108
  (unless (resolved-again? (section d 'resolved)) (return 0))
1056
1109
  (hash-set! (& registry) key (cast u32 (new-unit path path)))
1057
1110
  (while (pair? requires)
@@ -1093,13 +1146,17 @@
1093
1146
 
1094
1147
  (define (cache-name [path datum]) -> datum
1095
1148
  (let ([file (host-file path)])
1096
- (concat (content-hash (if (root-under-test? (identity-label path)) `(,file "test") (list1 file))) '".subc")))
1149
+ (concat (digest (if (root-under-test? (identity-label path)) `(,file "test") (list1 file))) '".subc")))
1097
1150
 
1098
1151
  (define (note-hash! [m datum])
1099
- (let* ([u (unit-of m)] [key (cast u64 (symbol-of (-> u hash)))] [known (cast datum (hash-ref (& units-by-hash) key))])
1152
+ (let* ([u (unit-of m)] [key (cast u64 (symbol-of (-> u hash)))] [known (cast datum (hash-ref (& units-by-hash) key))]
1153
+ [name-key (cast u64 (symbol-of (-> u name)))] [named (cast datum (hash-ref (& units-by-name) name-key))])
1100
1154
  (cond [(== known 0) (hash-set! (& units-by-hash) key (cast u32 m))]
1101
1155
  [(not (equal? (-> (unit-of known) path) (-> u path)))
1102
- (fail-at 0 "~a and ~a have the same hash, ~a" `(,(-> (unit-of known) path) ,(-> u path) ,(-> u hash)))])))
1156
+ (fail-at 0 "~a and ~a have the same hash, ~a" `(,(-> (unit-of known) path) ,(-> u path) ,(-> u hash)))])
1157
+ (cond [(== named 0) (hash-set! (& units-by-name) name-key (cast u32 m))]
1158
+ [(not (equal? (-> (unit-of named) path) (-> u path)))
1159
+ (fail-at 0 "~a and ~a have the same name, ~a" `(,(-> (unit-of named) path) ,(-> u path) ,(-> u name)))])))
1103
1160
 
1104
1161
  (define (load-compiled-module [d datum] [path datum]) -> datum
1105
1162
  (let ([m (new-unit path (section d 'name))])
@@ -1216,6 +1273,7 @@
1216
1273
  `((format . ,(make-integer cache-format)) (compiler . ,compiler-hash) (hash . ,(-> u hash))
1217
1274
  (definitions . ,(make-integer (length (-> u infos)))) (requires . ,require-forms) (resolved . ,(-> u resolved))
1218
1275
  (included . ,(map (lambda ([i datum]) -> datum (car i)) (-> u included))) (name . ,(-> u name))
1276
+ (runtime-requires . ,(-> u runtime-requires))
1219
1277
  (infos . ,infos) (provides . ,provides) (entries . ,entries)
1220
1278
  (inlines . ,inline-forms) (macros . ,macro-forms) (facts . ,fact-forms) (wasm-modules . ,wasm-modules)
1221
1279
  (memories . ,(-> u memories))))))
@@ -1343,7 +1401,10 @@
1343
1401
  [definitions (cast u32 (integer-value (section d 'definitions)))])
1344
1402
  (set! (-> u name) (keep (section d 'name)))
1345
1403
  (set! (-> u hash) (keep (section d 'hash)))
1346
- (hash-set! (& units-by-hash) (cast u64 (symbol-of (-> u hash))) (cast u32 m))
1404
+ (set! (-> u resolved) (keep (section d 'resolved)))
1405
+ (set! (-> u included) (keep (map (lambda ([i datum]) -> datum (cons i 0)) (section d 'included))))
1406
+ (set! (-> u runtime-requires) (keep (section d 'runtime-requires)))
1407
+ (note-hash! m)
1347
1408
  (set! (-> u scope) (new-run-scope!))
1348
1409
  (hash-set! (& module-scope-origins) (scope-key (-> u scope)) (cast u32 (keep (cons m (make-integer 0)))))
1349
1410
  (set! loading m)
@@ -1491,7 +1552,9 @@
1491
1552
  (define (declare-form! [f0 datum] [b (ptr body)] [only datum])
1492
1553
  (let* ([phase (-> b phase)] [f (head-expand f0 phase)] [kind (core-head f phase)])
1493
1554
  (when (and (!= only 0)
1494
- (!= (memq kind '(require require-unqualified language provide memory table define-syntax begin-for-syntax)) 0))
1555
+ (!= (memq kind '(require require-unqualified runtime-require language provide memory table define-syntax
1556
+ begin-for-syntax))
1557
+ 0))
1495
1558
  (fail-at f "~a (~a ...), but only func, global, import, tag, data and #%fact forms and expressions are allowed there"
1496
1559
  `(,only ,kind)))
1497
1560
  (case kind
@@ -1500,6 +1563,7 @@
1500
1563
  (for-each (lambda ([g datum]) (declare-form! (at-use f g) b only)) forms))]
1501
1564
  [('require) (require! f phase 0)]
1502
1565
  [('require-unqualified) (require! f phase 1)]
1566
+ [('runtime-require) (runtime-require! f phase)]
1503
1567
  [('language) (if (in-session?) (require! f phase 2) (fail-at f "the language must be the module's first form" nil))]
1504
1568
  [('provide) (provide! f phase)]
1505
1569
  [('func) (item! b (declare-func f phase))]
@@ -1782,6 +1846,21 @@
1782
1846
  (let ([me (the-module)] [r `(,(if (== from 0) '#f from) ,given ,path)])
1783
1847
  (when (== (member r (-> me resolved)) 0) (set! (-> me resolved) (keep (append (-> me resolved) (list1 r)))))))
1784
1848
 
1849
+ ;; (runtime-require source ...) lists modules that the program's sessions can load. They are resolved and checked the
1850
+ ;; same way as in require, and building the program also compiles them and writes them to the output.
1851
+ (define (runtime-require! [f datum] [phase i32])
1852
+ (let ([l (syntax->list f)] [me (the-module)])
1853
+ (unless (and (!= l 0) (andmap (lambda ([s datum]) -> bool (module-source? s)) (cdr l)))
1854
+ (no-match f "(runtime-require source ...)"))
1855
+ (when (or (!= phase 0) (in-session?)) (fail-at f "runtime-require belongs at phase 0 of a module" nil))
1856
+ (for-each (lambda ([spec datum])
1857
+ (let* ([from (module-source-file f spec)] [path (module-path-from from spec)])
1858
+ (note-resolved! from (syntax-e spec) path)
1859
+ (check-module! (-> me path) path spec)
1860
+ (when (== (member path (-> me runtime-requires)) 0)
1861
+ (set! (-> me runtime-requires) (keep (append (-> me runtime-requires) (list1 path)))))))
1862
+ (cdr l))))
1863
+
1785
1864
  ;; (include-text "file") is the file's text as a string literal. Its path is resolved as a require's is, and the
1786
1865
  ;; module's hash covers the file.
1787
1866
  (define (included-text [s datum]) -> datum
@@ -1799,7 +1878,7 @@
1799
1878
  (set! (-> me included) (keep (append (-> me included) (list1 (cons id (text-hash text)))))))
1800
1879
  (datum->syntax spec text spec))))
1801
1880
 
1802
- (define (text-hash [text datum]) -> datum (content-hash (list1 text)))
1881
+ (define (text-hash [text datum]) -> datum (digest (list1 text)))
1803
1882
 
1804
1883
  (define (require-unit! [name datum] [m datum] [phase i32]) -> datum
1805
1884
  (let ([me (the-module)] [req (cons m (make-integer phase))])
@@ -1902,8 +1981,13 @@
1902
1981
 
1903
1982
  (define (ns-name [name datum]) -> datum (format "~a/~a" `(,(-> current ns) ,name)))
1904
1983
 
1984
+ ;; instance-name returns the instance a module's code links to: the running program's own instance if the program
1985
+ ;; contains the module, which only happens for session code, and otherwise this namespace's instance.
1986
+ (define (instance-name [name datum]) -> datum (if (running-wasm-module? name) name (ns-name name)))
1987
+
1905
1988
  (define (namespaced? [name datum]) -> bool
1906
- (and (== (group-instance name) 0) (!= (hash-ref (& instance-refs) (cast u64 (symbol-of name))) 0)))
1989
+ (and (== (group-instance name) 0) (not (running-wasm-module? name))
1990
+ (!= (hash-ref (& instance-refs) (cast u64 (symbol-of name))) 0)))
1907
1991
 
1908
1992
  (define (integer-at [l datum] [n u32]) -> i32 (cast i32 (integer-value (list-ref l n))))
1909
1993
 
@@ -1915,7 +1999,8 @@
1915
1999
  (cond [(!= g 0) (set! out (cons (cons (car imports) g) out))]
1916
2000
  [(== r 0) 0]
1917
2001
  [(pair? (cddr r))
1918
- (set! out (cons (cons (car imports) (ns-name (wasm-module-name (car r) (integer-at r 1) (+ (integer-at r 2) (cast i32 t))))) out))]
2002
+ (set! out (cons (cons (car imports) (instance-name (wasm-module-name (car r) (integer-at r 1) (+ (integer-at r 2) (cast i32 t)))))
2003
+ out))]
1919
2004
  [else (set! out (cons (cons (car imports) (ns-name (car imports))) out))])
1920
2005
  (set! imports (cdr imports)))
1921
2006
  out))
@@ -1925,9 +2010,9 @@
1925
2010
  (when (!= r 0) (ensure-wasm-module! (car r) (integer-at r 1) (+ (cast u32 (integer-at r 2)) shift)))))
1926
2011
 
1927
2012
  (define (ensure-wasm-module! [m datum] [q i32] [t u32])
1928
- (let* ([name (ns-name (wasm-module-name m q (cast i32 t)))] [key (cast u64 (symbol-of name))] [p (ptr wasm-module) 0]
1929
- [l nil])
1930
- (when (== (hash-ref (-> current instances) key) 0)
2013
+ (let* ([plain (wasm-module-name m q (cast i32 t))] [name (ns-name plain)] [key (cast u64 (symbol-of name))]
2014
+ [p (ptr wasm-module) 0] [l nil])
2015
+ (when (and (not (running-wasm-module? plain)) (== (hash-ref (-> current instances) key) 0))
1931
2016
  (set! p (wasm-module-of m q))
1932
2017
  (when (== p 0) (fail-at 0 "internal: ~a has no phase ~a wasm module" `(,(-> (unit-of m) name) ,(make-integer q))))
1933
2018
  (set! l (suppliers-of m))
@@ -2336,13 +2421,51 @@
2336
2421
  (define session-source datum 0)
2337
2422
  (define session-message datum 0)
2338
2423
  (define session-running bool #f)
2424
+ (define session-evaluating bool #f)
2339
2425
  (define interacting bool #f)
2340
2426
 
2341
2427
  (define (in-session?) -> bool (and (!= session 0) (== current session)))
2342
2428
 
2429
+ ;; use-compiled-modules! makes sessions load the compiled modules that the program's build wrote, if there are any,
2430
+ ;; using the module map they were built with.
2431
+ (define (use-compiled-modules!)
2432
+ (let ([listed (compiled-listed (compiled-text '"compiled"))])
2433
+ (unless (null? listed)
2434
+ (set-compiled-module-map! (map (lambda ([f datum]) -> datum (syntax->datum f))
2435
+ (read-text (compiled-text '"compiled.map") (symbol-of '"compiled.map")))
2436
+ listed))))
2437
+
2438
+ ;; compiled-listed reads the compiled file, which has one module per line: its hash, a space, and its identity.
2439
+ (define (compiled-listed [text datum]) -> datum
2440
+ (let ([s (datum->string text)] [start u32 0] [out nil])
2441
+ (for ([i u32 0]) (<= i (-> s length)) (+= i 1)
2442
+ (when (or (== i (-> s length)) (== (@ s i) 10))
2443
+ (let ([space start])
2444
+ (while (and (< space i) (!= (@ s space) 32)) (+= space 1))
2445
+ (when (< space i)
2446
+ (set! out (cons `(,(string->datum (slice s (+ space 1) i)) ,(string->datum (slice s start space))) out))))
2447
+ (set! start (+ i 1))))
2448
+ (reverse out)))
2449
+
2450
+ (define (compiled-bytes [name datum]) -> datum
2451
+ (let ([b (host-compiled-file (datum->string name))] [d datum 0])
2452
+ (when (> (-> b length) 0) (set! d (bytes->datum b)))
2453
+ (free (-> b items))
2454
+ d))
2455
+
2456
+ (define (compiled-text [name datum]) -> datum
2457
+ (let ([d (compiled-bytes name)]) (if (== d 0) '"" (string->datum (cast string (datum->bytes d))))))
2458
+
2459
+ (define (compiled-data [hash datum]) -> datum
2460
+ (let ([d (compiled-bytes (concat hash '".subc"))])
2461
+ (if (and (!= d 0) (equal? (bytes-digest (datum->bytes d)) hash)) (data-of d) 0)))
2462
+
2343
2463
  (define (module-source) -> datum (if (in-session?) session-source (symbol-of (-> (the-module) path))))
2344
2464
 
2465
+ ;; session-open! opens the program's single session, which starts out in Substrate. name is used in error messages.
2345
2466
  (define (session-open! [name datum])
2467
+ (install-core!)
2468
+ (use-compiled-modules!)
2346
2469
  (let ([m (new-unit (identity 0 name) (provisional-name name))])
2347
2470
  (begin-module-arena)
2348
2471
  (set! session-mark (module-arena-mark))
@@ -2386,7 +2509,10 @@
2386
2509
  (set! e (-> e next)))
2387
2510
  (set! (-> (the-module) entries) entries)))
2388
2511
 
2512
+ ;; session-eval! compiles and runs forms in the session, and returns #f if they fail.
2389
2513
  (define (session-eval! [forms datum]) -> bool
2514
+ (when session-evaluating (session-recover!))
2515
+ (set! session-evaluating #t)
2390
2516
  (let* ([sc (new-scope!)] [scopes (scopes-change session-set sc 0)] [entries (-> (the-module) entries)] [ok #f]
2391
2517
  [was comp (@ session)])
2392
2518
  (set! session-scope sc)
@@ -2407,8 +2533,10 @@
2407
2533
  (set! (@ session) was)
2408
2534
  (set! (-> session wasm-module-counter) n)))
2409
2535
  (set! session-scope 0)
2536
+ (set! session-evaluating #f)
2410
2537
  ok))
2411
2538
 
2539
+ ;; session-eval-text! reads forms from text and evaluates them. Error messages refer to the text as source.
2412
2540
  (define (session-eval-text! [text datum] [source datum]) -> bool
2413
2541
  (let ([forms datum 0] [ok #f])
2414
2542
  (try
@@ -2417,6 +2545,7 @@
2417
2545
  [catch compile-error (message blamed loc) (session-fail! message blamed loc)])
2418
2546
  (and ok (session-eval! forms))))
2419
2547
 
2548
+ ;; session-eval-file! evaluates a file's forms one at a time, and calls report with the message of each one that fails.
2420
2549
  (define (session-eval-file! [root datum] [source datum] [report (closure (datum))])
2421
2550
  (let ([path (program-identity root source)] [forms datum 0])
2422
2551
  (check-module! 0 path 0)
@@ -2425,6 +2554,7 @@
2425
2554
  (unless (session-eval! (list1 (car forms))) (report (session-error)))
2426
2555
  (set! forms (cdr forms)))))
2427
2556
 
2557
+ ;; session-error returns the message of the last failure.
2428
2558
  (define (session-error) -> datum session-message)
2429
2559
 
2430
2560
  (define (run-session-wasm-module! [forms datum])
@@ -2449,7 +2579,9 @@
2449
2579
  (set! session-message (string->datum (buffer-string (& b))))
2450
2580
  (buffer-free! (& b))))
2451
2581
 
2582
+ ;; session-recover! resets the compiler after an evaluation fails or traps.
2452
2583
  (define (session-recover!)
2584
+ (set! session-evaluating #f)
2453
2585
  (end-module-arenas-to! session-mark)
2454
2586
  (while (pair? compiling)
2455
2587
  (hash-set! (& registry) (cast u64 (car compiling)) 0)
@@ -100,15 +100,28 @@
100
100
  [else ""]))
101
101
  ""))
102
102
 
103
+ ;; write-program! writes the built program to dir: its wasm modules and the program file that lists them, plus the
104
+ ;; compiled modules its sessions can load. Each compiled module is saved as <hash>.subc, where hash is the SHA-256 of
105
+ ;; its contents, and listed in the compiled file. compiled.map holds the module map they were built with.
103
106
  (define (write-program! [root datum] [file datum] [dir datum] [strip bool])
104
107
  (let* ([m (compile-module-file root file)] [pruned-modules (pruned (program-wasm-modules m))]
105
- [ls (if strip (stripped pruned-modules) pruned-modules)] [names nil])
108
+ [ls (if strip (stripped pruned-modules) pruned-modules)] [names nil] [compiled (program-compiled-modules m)]
109
+ [listed nil])
106
110
  (make-dir dir)
107
111
  (while (pair? ls)
108
112
  (write-file (joined `(,dir "/" ,(car (car ls)) ".wasm")) (datum->bytes (cdr (car ls))))
109
113
  (set! names (cons '"\n" (cons (car (car ls)) names)))
110
114
  (set! ls (cdr ls)))
111
- (write-file (joined `(,dir "/program")) (cast (slice u8) (datum->string (joined (reverse names)))))))
115
+ (write-file (joined `(,dir "/program")) (cast (slice u8) (datum->string (joined (reverse names)))))
116
+ (for-each (lambda ([c datum])
117
+ (write-file (joined `(,dir "/" ,(cadr c) ".subc")) (datum->bytes (caddr c)))
118
+ (set! listed (cons '"\n" (cons (car c) (cons '" " (cons (cadr c) listed))))))
119
+ compiled)
120
+ (unless (null? compiled)
121
+ (write-file (joined `(,dir "/compiled.map"))
122
+ (cast (slice u8) (datum->string (joined (map (lambda ([f datum]) -> datum (format "~s\n" (cons f nil)))
123
+ (compiled-module-map)))))))
124
+ (write-file (joined `(,dir "/compiled")) (cast (slice u8) (datum->string (joined (reverse listed)))))))
112
125
 
113
126
  (define (print-expanded [form datum])
114
127
  (let ([b (make-buffer)])