From 4510e7e475478a6688319552880509cd2e8fc131 Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 10 May 2026 19:11:36 +0000 Subject: [PATCH] =?UTF-8?q?haskell:=20Phase=2017=20=E2=80=94=20`import`=20?= =?UTF-8?q?declarations=20anywhere=20among=20top-level=20decls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- lib/haskell/parser.sx | 12 ++++++++-- lib/haskell/tests/parse-extras.sx | 39 +++++++++++++++++++++++++++++++ plans/haskell-completeness.md | 14 ++++++++++- 3 files changed, 62 insertions(+), 3 deletions(-) diff --git a/lib/haskell/parser.sx b/lib/haskell/parser.sx index b7e0085f..97f7884f 100644 --- a/lib/haskell/parser.sx +++ b/lib/haskell/parser.sx @@ -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)))) diff --git a/lib/haskell/tests/parse-extras.sx b/lib/haskell/tests/parse-extras.sx index 723dd22d..849f2217 100644 --- a/lib/haskell/tests/parse-extras.sx +++ b/lib/haskell/tests/parse-extras.sx @@ -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) diff --git a/plans/haskell-completeness.md b/plans/haskell-completeness.md index cddb0516..dd4f56e0 100644 --- a/plans/haskell-completeness.md +++ b/plans/haskell-completeness.md @@ -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