(;module: lux (lux [function] (data (coll [list "L/" Fold])))) (type: #export #rec Pattern (#BoolP Bool) (#NatP Nat) (#IntP Int) (#DegP Deg) (#RealP Real) (#TextP Text) (#TupleP (List Pattern)) (#VariantP Nat Nat Pattern) (#BindP Nat)) (type: #export #rec Analysis #Unit (#Bool Bool) (#Nat Nat) (#Int Int) (#Deg Deg) (#Real Real) (#Text Text) (#Sum (Either Analysis Analysis)) (#Product Analysis Analysis) (#Case Analysis (List [Pattern Analysis])) (#Function Scope Analysis) (#Apply Analysis Analysis) (#Procedure Text (List Analysis)) (#Variable Ref) (#Definition Ident)) ## Variants get analysed as binary sum types for the sake of semantic ## simplicity. ## This is because you can encode a variant of any size using just ## binary sums by nesting them. (do-template [ ] [(def: ( inner) (-> Analysis Analysis) (#Sum ( inner)))] [sum-left #;Left] [sum-right #;Right]) (def: #export (sum tag size temp value) (-> Nat Nat Nat Analysis Analysis) (if (n.= (n.dec size) tag) (if (n.= +1 tag) (sum-right value) (L/fold (function;const sum-left) (sum-right value) (list;n.range +0 (n.- +2 tag)))) (L/fold (function;const sum-left) (case value (#Sum _) (#Case value (list [(#BindP temp) (#Variable (#;Local temp))])) _ value) (list;n.range +0 tag)))) ## Tuples get analysed into binary products for the sake of semantic ## simplicity, since products/pairs can encode tuples of any length ## through nesting. (def: #export (product members) (-> (List Analysis) Analysis) (case members #;Nil #Unit (#;Cons singleton #;Nil) singleton (#;Cons left right) (#Product left (product right)))) ## Function application gets analysed into single-argument ## applications, since every other kind of application can be encoded ## into a finite series of single-argument applications. (def: #export (apply args func) (-> (List Analysis) Analysis Analysis) (L/fold (function [arg func] (#Apply arg func)) func args))