haskell: Phase 17 — expression type annotations (x :: Int) (parse + desugar pass-through)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 56s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 56s
Parser hk-parse-parens gains a `::` arm after the first inner expression: consume `::`, parse a type via the existing hk-parse-type, expect `)`, emit (:type-ann EXPR TYPE). Sections, tuples, parenthesised expressions and unit `()` are unchanged. Desugar drops the annotation — :type-ann E _ → (hk-desugar E) — since the existing eval path has no type-directed dispatch. Phase 20 will extend infer.sx to consume the annotation and unify against the inferred type. tests/parse-extras.sx (12/12) covers literal, arithmetic, function arg, string, bool, tuple, nested annotation, function-typed annotation, and no-regression checks for plain parens / 3-tuples / left+right sections. eval (66/0), exceptions (14/0), typecheck (15/0), records (14/0), ioref (13/0) all still clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -210,6 +210,7 @@
|
||||
:op (nth node 1)
|
||||
(hk-desugar (nth node 2))
|
||||
(hk-desugar (nth node 3))))
|
||||
((= tag "type-ann") (hk-desugar (nth node 1)))
|
||||
((= tag "neg") (list :neg (hk-desugar (nth node 1))))
|
||||
((= tag "if")
|
||||
(list
|
||||
|
||||
@@ -275,38 +275,47 @@
|
||||
(list :sect-right op-name expr-e))))))
|
||||
(:else
|
||||
(let
|
||||
((first-e (hk-parse-expr-inner))
|
||||
(items (list))
|
||||
(is-tuple false))
|
||||
(append! items first-e)
|
||||
(define
|
||||
hk-tup-loop
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(hk-match? "comma" nil)
|
||||
(do
|
||||
(hk-advance!)
|
||||
(set! is-tuple true)
|
||||
(append! items (hk-parse-expr-inner))
|
||||
(hk-tup-loop)))))
|
||||
(hk-tup-loop)
|
||||
((first-e (hk-parse-expr-inner)))
|
||||
(cond
|
||||
((hk-match? "rparen" nil)
|
||||
((hk-match? "reservedop" "::")
|
||||
(do
|
||||
(hk-advance!)
|
||||
(if is-tuple (list :tuple items) first-e)))
|
||||
(let
|
||||
((ann-type (hk-parse-type)))
|
||||
(hk-expect! "rparen" nil)
|
||||
(list :type-ann first-e ann-type))))
|
||||
(:else
|
||||
(let
|
||||
((op-info2 (hk-section-op-info)))
|
||||
((items (list)) (is-tuple false))
|
||||
(append! items first-e)
|
||||
(define
|
||||
hk-tup-loop
|
||||
(fn
|
||||
()
|
||||
(when
|
||||
(hk-match? "comma" nil)
|
||||
(do
|
||||
(hk-advance!)
|
||||
(set! is-tuple true)
|
||||
(append! items (hk-parse-expr-inner))
|
||||
(hk-tup-loop)))))
|
||||
(hk-tup-loop)
|
||||
(cond
|
||||
((and (not (nil? op-info2)) (not is-tuple) (let ((after2 (hk-peek-at (get op-info2 "len")))) (and (not (nil? after2)) (= (get after2 "type") "rparen"))))
|
||||
(let
|
||||
((op-name (get op-info2 "name")))
|
||||
(hk-consume-op!)
|
||||
((hk-match? "rparen" nil)
|
||||
(do
|
||||
(hk-advance!)
|
||||
(list :sect-left op-name first-e)))
|
||||
(:else (hk-err "expected ')' after expression"))))))))))))))
|
||||
(if is-tuple (list :tuple items) first-e)))
|
||||
(:else
|
||||
(let
|
||||
((op-info2 (hk-section-op-info)))
|
||||
(cond
|
||||
((and (not (nil? op-info2)) (not is-tuple) (let ((after2 (hk-peek-at (get op-info2 "len")))) (and (not (nil? after2)) (= (get after2 "type") "rparen"))))
|
||||
(let
|
||||
((op-name (get op-info2 "name")))
|
||||
(hk-consume-op!)
|
||||
(hk-advance!)
|
||||
(list :sect-left op-name first-e)))
|
||||
(:else (hk-err "expected ')' after expression")))))))))))))))))
|
||||
(define
|
||||
hk-comp-qual-is-gen?
|
||||
(fn
|
||||
|
||||
63
lib/haskell/tests/parse-extras.sx
Normal file
63
lib/haskell/tests/parse-extras.sx
Normal file
@@ -0,0 +1,63 @@
|
||||
;; Phase 17 — parser polish unit tests.
|
||||
|
||||
(hk-test
|
||||
"type-ann: literal int annotated"
|
||||
(hk-deep-force (hk-run "main = (42 :: Int)"))
|
||||
42)
|
||||
|
||||
(hk-test
|
||||
"type-ann: arithmetic annotated"
|
||||
(hk-deep-force (hk-run "main = (1 + 2 :: Int)"))
|
||||
3)
|
||||
|
||||
(hk-test
|
||||
"type-ann: function arg annotated"
|
||||
(hk-deep-force
|
||||
(hk-run "f x = x + 1\nmain = f (1 :: Int)"))
|
||||
2)
|
||||
|
||||
(hk-test
|
||||
"type-ann: string annotated"
|
||||
(hk-deep-force (hk-run "main = (\"hi\" :: String)"))
|
||||
"hi")
|
||||
|
||||
(hk-test
|
||||
"type-ann: bool annotated"
|
||||
(hk-deep-force (hk-run "main = (True :: Bool)"))
|
||||
(list "True"))
|
||||
|
||||
(hk-test
|
||||
"type-ann: tuple annotated"
|
||||
(hk-deep-force (hk-run "main = ((1, 2) :: (Int, Int))"))
|
||||
(list "Tuple" 1 2))
|
||||
|
||||
(hk-test
|
||||
"type-ann: nested annotation in arithmetic"
|
||||
(hk-deep-force (hk-run "main = (1 :: Int) + (2 :: Int)"))
|
||||
3)
|
||||
|
||||
(hk-test
|
||||
"type-ann: function-typed annotation passes through eval"
|
||||
(hk-deep-force
|
||||
(hk-run "main = let f = ((\\x -> x + 1) :: Int -> Int) in f 5"))
|
||||
6)
|
||||
|
||||
(hk-test
|
||||
"no regression: plain parens still work"
|
||||
(hk-deep-force (hk-run "main = (5)"))
|
||||
5)
|
||||
|
||||
(hk-test
|
||||
"no regression: 3-tuple still works"
|
||||
(hk-deep-force (hk-run "main = (1, 2, 3)"))
|
||||
(list "Tuple" 1 2 3))
|
||||
|
||||
(hk-test
|
||||
"no regression: section-left still works"
|
||||
(hk-deep-force (hk-run "main = (3 +) 4"))
|
||||
7)
|
||||
|
||||
(hk-test
|
||||
"no regression: section-right still works"
|
||||
(hk-deep-force (hk-run "main = (+ 3) 4"))
|
||||
7)
|
||||
Reference in New Issue
Block a user