(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))