haskell: Phase 17 — import declarations anywhere among top-level decls
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 21s

hk-collect-module-body previously ran a fixed import-loop at the start
and then a separate decl-loop; merged into a single hk-body-step
dispatcher that routes `import` to the imports list and everything else
to hk-parse-decl. Both call sites (initial step + post-semicolon loop)
use the dispatcher. The eval side reads imports as a list (not by AST
position) so mid-stream imports feed into hk-bind-decls! unchanged.

tests/parse-extras.sx 12 → 17: very-top, mid-stream, post-main,
two-imports-different-positions, unqualified-mid-file. Regression
sweep clean: eval 66/0, exceptions 14/0, typecheck 15/0, records 14/0,
ioref 13/0, map 26/0, set 17/0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 19:11:36 +00:00
parent aa620b767f
commit 4510e7e475
3 changed files with 62 additions and 3 deletions

View File

@@ -1733,10 +1733,18 @@
(= (hk-peek-type) "eof")
(hk-match? "vrbrace" nil)
(hk-match? "rbrace" nil))))
(define
hk-body-step
(fn
()
(cond
((hk-match? "reserved" "import")
(append! imports (hk-parse-import)))
(:else (append! decls (hk-parse-decl))))))
(when
(not (hk-body-at-end?))
(do
(append! decls (hk-parse-decl))
(hk-body-step)
(define
hk-body-loop
(fn
@@ -1747,7 +1755,7 @@
(hk-advance!)
(when
(not (hk-body-at-end?))
(append! decls (hk-parse-decl)))
(hk-body-step))
(hk-body-loop)))))
(hk-body-loop)))
(list imports decls))))

View File

@@ -61,3 +61,42 @@
"no regression: section-right still works"
(hk-deep-force (hk-run "main = (+ 3) 4"))
7)
(hk-test
"import: still works as the very first decl"
(hk-deep-force
(hk-run "import qualified Data.IORef as I
main = do { r <- I.newIORef 7; I.readIORef r }"))
(list "IO" 7))
(hk-test
"import: between decls — after main"
(hk-deep-force
(hk-run "main = do { r <- I.newIORef 11; I.readIORef r }
import qualified Data.IORef as I"))
(list "IO" 11))
(hk-test
"import: between two decls — uses helper after import"
(hk-deep-force
(hk-run "f x = x + 100
import qualified Data.IORef as I
main = do { r <- I.newIORef 5; I.modifyIORef r f; I.readIORef r }"))
(list "IO" 105))
(hk-test
"import: two imports in different positions"
(hk-deep-force
(hk-run "import qualified Data.IORef as I
helper x = x * 2
import qualified Data.Map as M
main = do { r <- I.newIORef (helper 21); I.readIORef r }"))
(list "IO" 42))
(hk-test
"import: unqualified, mid-file"
(hk-deep-force
(hk-run "go x = x
import Data.IORef
main = go 9"))
9)

View File

@@ -320,7 +320,7 @@ larger conformance programs and removes one-line workarounds in test sources.
`return (42 :: Int)`. Parser currently rejects `::` in `aexp` position;
desugar should drop the annotation (we have no inference at this layer
yet, so it's a parse-only pass-through).
- [ ] `import` declarations anywhere at the start of a module — currently
- [x] `import` declarations anywhere at the start of a module — currently
only the very-top-of-file form is recognised. Real test programs that
mix prelude code with `import qualified Data.IORef` need this.
- [ ] Multi-line top-level `where` blocks (`where { ... }` with explicit
@@ -420,6 +420,18 @@ constraints (qualified types `[ClassName var] => type`).
_Newest first._
**2026-05-10** — Phase 17 second box: `import` declarations anywhere among
top-level decls. `hk-collect-module-body` previously ran a fixed
import-loop at the start, then a separate decl-loop; merged into a single
`hk-body-step` dispatcher that routes `import` to the imports list and
everything else to `hk-parse-decl`. Each call site (initial step + post-
semicolon loop) now uses the dispatcher. Imports collected mid-stream
still feed into `hk-bind-decls!` correctly because the eval side reads
them via the imports list, not by AST position. tests/parse-extras.sx
12 → 17 covering very-top, mid-stream, post-main, two-imports-different-
positions, and unqualified mid-file. Regression: eval 66/0, exceptions
14/0, typecheck 15/0, records 14/0, ioref 13/0, map 26/0, set 17/0.
**2026-05-08** — Phase 17 first box: expression type annotations `(x :: Int)`,
`f (1 :: Int)`, `(\x -> x+1) :: Int -> Int`. Parser's `hk-parse-parens`
gains a `::` arm after the first inner expression: consume `::`, parse a