A `while' or `switch' body is a block with no `do' around it, and its declarations landed in the enclosing frame. Two operands of one narrow type skipped the conversions, so `(+ c c)' answered `char'.
110 lines
3.3 KiB
Scheme
110 lines
3.3 KiB
Scheme
(input)
|
|
(output "literals: 42 3.5 hello"
|
|
"calls: 12"
|
|
"members: 1 2.5"
|
|
"pointers: 1 2.5"
|
|
"arrays: 30"
|
|
"loop: 0 1 2"
|
|
"shadowed: 9 then 42"
|
|
"still an int: 200"
|
|
"partial: 1 2.5"
|
|
"joined: 43.5 84 49 1"
|
|
"promoted: 200 60000 3705032704"
|
|
"from elements: 4 9 0")
|
|
(return 0)
|
|
|
|
;;; `_' as a type means "work it out from the initializer". What the
|
|
;;; pass can answer comes from declarations -- Sex writes a type at
|
|
;;; every binding site -- and from the signature of whatever a call
|
|
;;; names. A partial type like `(* _)' is solved by unifying what was
|
|
;;; written against what the initializer gives, so only the wildcard
|
|
;;; inside the spelling is filled in.
|
|
|
|
(include stdio.h)
|
|
|
|
(struct point ((x int) (y float)))
|
|
|
|
(fn area ((w int) (h int)) int
|
|
(return (* w h)))
|
|
|
|
(pub fn main () int
|
|
(var n _ 42)
|
|
(var f _ 3.5)
|
|
(var s _ "hello")
|
|
(printf "literals: %d %g %s\n" n f s)
|
|
|
|
(var a _ (area 3 4))
|
|
(printf "calls: %d\n" a)
|
|
|
|
(var p (struct point) #((struct point) : .x 1 .y 2.5))
|
|
(var px _ (. p x))
|
|
(var py _ (. p y))
|
|
(printf "members: %d %g\n" px py)
|
|
|
|
(var pp _ (& p))
|
|
(printf "pointers: %d %g\n" (-> pp x) (-> pp y))
|
|
|
|
(var table (¤ int 3))
|
|
(= (¤ table 0) 10)
|
|
(= (¤ table 1) 20)
|
|
(var first _ (¤ table 0))
|
|
(var second _ (¤ table 1))
|
|
(printf "arrays: %d\n" (+ first second))
|
|
|
|
;; a for opens a scope, and its initializer is declared inside it
|
|
(printf "loop:")
|
|
(for (var i _ 0) (< i 3) (++ i)
|
|
(printf " %d" i))
|
|
(printf "\n")
|
|
|
|
;; a block's declarations end with it, and so do the declarations of
|
|
;; everything else C brackets -- a `while' body is a block with no
|
|
;; `do' written around it
|
|
(do (var n _ 9)
|
|
(printf "shadowed: %d then " n))
|
|
(printf "%d\n" n)
|
|
|
|
(var wide int 200)
|
|
(while false (var wide char 1) (printf "%d" wide))
|
|
(if false (do (var wide char 1) (printf "%d" wide)))
|
|
;; a statement before the declaration: a label may not be followed by
|
|
;; one until C23
|
|
(switch a (case 1 (printf "") (var wide char 1) (printf "%d" wide) (break)))
|
|
;; a copy, not a sum: an arithmetic result would be promoted to `int'
|
|
;; whatever leaked, and say nothing
|
|
(var copy _ wide)
|
|
(printf "still an int: %d\n" copy)
|
|
|
|
;; a wildcard inside a written type: only it is solved
|
|
(var pp2 (* _) (& p))
|
|
(printf "partial: %d %g\n" (-> pp2 x) (-> pp2 y))
|
|
|
|
;; C's usual arithmetic conversions, far enough to answer `_'
|
|
(var d double 1.5)
|
|
(var l long 7)
|
|
(var g float 0.5)
|
|
(var mixed _ (+ n d))
|
|
(var same _ (+ n n))
|
|
(var wider _ (+ n l))
|
|
(var single _ (+ g g))
|
|
(printf "joined: %g %d %ld %g\n" mixed same wider single)
|
|
|
|
;; ...including the promotions, which two operands of one narrow type
|
|
;; are exactly where they show: `char' + `char' is an `int'
|
|
(var c1 char 100)
|
|
(var c2 char 100)
|
|
(var h1 short 30000)
|
|
(var narrow _ (+ c1 c2))
|
|
(var narrower _ (+ h1 h1))
|
|
(var kept (unsigned int) 4000000000)
|
|
(var unpromoted _ (+ kept kept))
|
|
(printf "promoted: %d %d %u\n" narrow narrower unpromoted)
|
|
|
|
;; a brace initializer has no type of its own, but its elements solve
|
|
;; the hole in the array type around it -- and the length stays as
|
|
;; written, whether or not every slot is initialized
|
|
(var squares (¤ _ 4) #(0 1 4 9))
|
|
(var sparse (¤ _ 8) #(0 1))
|
|
(printf "from elements: %d %d %d\n" (¤ squares 2) (¤ squares 3) (¤ sparse 7))
|
|
(return 0))
|