(.module: lux (lux (control [monad #+ do] ["ex" exception #+ exception:] ["p" parser]) (data ["e" error] [text] text/format (coll [list "list/" Functor] (dictionary ["dict" unordered #+ Dict]))) [macro #+ with-gensyms] (macro [code] ["s" syntax #+ syntax:]) [host]) (luxc ["&" lang] (lang ["la" analysis] ["ls" synthesis] (host [js #+ JS Expression Statement]))) [///] (/// [".T" runtime] [".T" case] [".T" function] [".T" loop])) ## [Types] (type: #export Translator (-> ls.Synthesis (Meta Expression))) (type: #export Proc (-> Translator (List ls.Synthesis) (Meta Expression))) (type: #export Bundle (Dict Text Proc)) (syntax: (Vector {size s.nat} elemT) (wrap (list (` [(~+ (list.repeat size elemT))])))) (type: #export Nullary (-> (Vector +0 Expression) Expression)) (type: #export Unary (-> (Vector +1 Expression) Expression)) (type: #export Binary (-> (Vector +2 Expression) Expression)) (type: #export Trinary (-> (Vector +3 Expression) Expression)) (type: #export Variadic (-> (List Expression) Expression)) ## [Utils] (def: #export (install name unnamed) (-> Text (-> Text Proc) (-> Bundle Bundle)) (dict.put name (unnamed name))) (def: #export (prefix prefix bundle) (-> Text Bundle Bundle) (|> bundle dict.entries (list/map (function (_ [key val]) [(format prefix " " key) val])) (dict.from-list text.Hash))) (def: (wrong-arity proc expected actual) (-> Text Nat Nat Text) (format "Wrong number of arguments for " (%t proc) "\n" "Expected: " (|> expected .int %i) "\n" " Actual: " (|> actual .int %i))) (syntax: (arity: {name s.local-symbol} {arity s.nat}) (with-gensyms [g!_ g!proc g!name g!translate g!inputs] (do @ [g!input+ (monad.seq @ (list.repeat arity (macro.gensym "input")))] (wrap (list (` (def: #export ((~ (code.local-symbol name)) (~ g!proc)) (-> (-> (..Vector (~ (code.nat arity)) Expression) Expression) (-> Text ..Proc)) (function ((~ g!_) (~ g!name)) (function ((~ g!_) (~ g!translate) (~ g!inputs)) (case (~ g!inputs) (^ (list (~+ g!input+))) (do macro.Monad [(~+ (|> g!input+ (list/map (function (_ g!input) (list g!input (` ((~ g!translate) (~ g!input)))))) list.concat))] ((~' wrap) ((~ g!proc) [(~+ g!input+)]))) (~' _) (macro.fail (wrong-arity (~ g!name) +1 (list.size (~ g!inputs)))))))))))))) (arity: nullary +0) (arity: unary +1) (arity: binary +2) (arity: trinary +3) (def: #export (variadic proc) (-> Variadic (-> Text Proc)) (function (_ proc-name) (function (_ translate inputsS) (do macro.Monad [inputsI (monad.map @ translate inputsS)] (wrap (proc inputsI)))))) (def: (self-contained content) (-> Expression Expression) (format "(" content ")")) (def: (void action) (-> Expression Expression) (format "(" action "," runtimeT.unit ")")) ## [Procedures] ## [[Lux]] (def: (lux//is [leftJS rightJS]) Binary (self-contained (format leftJS " === " rightJS))) (def: (lux//if [testJS thenJS elseJS]) Trinary (caseT.translate-if testJS thenJS elseJS)) (def: (lux//try riskyJS) Unary (format runtimeT.lux//try "(" riskyJS ")")) (exception: #export (Wrong-Syntax {message Text}) message) (def: #export (wrong-syntax procedure args) (-> Text (List ls.Synthesis) Text) (format "Procedure: " procedure "\n" "Arguments: " (%code (code.tuple args)))) (def: lux//loop (-> Text Proc) (function (_ proc-name) (function (_ translate inputsS) (case (s.run inputsS ($_ p.seq s.nat (s.tuple (p.many s.any)) s.any)) (#e.Success [offset initsS+ bodyS]) (loopT.translate-loop translate offset initsS+ bodyS) (#e.Error error) (&.throw Wrong-Syntax (wrong-syntax proc-name inputsS))) ))) (def: lux//recur (-> Text Proc) (function (_ proc-name) (function (_ translate inputsS) (loopT.translate-recur translate inputsS)))) ## [[Bits]] (do-template [ ] [(def: ( [subjectJS paramJS]) Binary (format "(" subjectJS "," paramJS ")"))] [bit//and runtimeT.bit//and] [bit//or runtimeT.bit//or] [bit//xor runtimeT.bit//xor] ) (do-template [ ] [(def: ( [subjectJS paramJS]) Binary (let [simple-param (format runtimeT.int//to-number "(" paramJS ")")] (format "(" subjectJS "," simple-param ")")))] [bit//left-shift runtimeT.bit//left-shift] [bit//arithmetic-right-shift runtimeT.bit//arithmetic-right-shift] [bit//logical-right-shift runtimeT.bit//logical-right-shift] ) ## [[Arrays]] (def: (array//new sizeJS) Unary (self-contained (format "new Array(" runtimeT.int//to-number "(" sizeJS ")" ")"))) (def: (array//get [arrayJS idxJS]) Binary (format runtimeT.array//get "(" arrayJS "," idxJS ")")) (def: (array//put [arrayJS idxJS elemJS]) Trinary (format runtimeT.array//put "(" arrayJS "," idxJS "," elemJS ")")) (def: (array//remove [arrayJS idxJS]) Binary (format runtimeT.array//remove "(" arrayJS "," idxJS ")")) (def: (array//size arrayJS) Unary (format arrayJS ".length")) ## [[Numbers]] (host.import: java/lang/Double (#static MIN_VALUE Double) (#static MAX_VALUE Double)) (do-template [ ] [(def: ( _) Nullary ( ))] [frac//smallest Double::MIN_VALUE runtimeT.frac] [frac//min (f/* -1.0 Double::MAX_VALUE) runtimeT.frac] [frac//max Double::MAX_VALUE runtimeT.frac] ) (do-template [ ] [(def: ( [subjectJS paramJS]) Binary (format "(" subjectJS "," paramJS ")"))] [int//add runtimeT.int//+] [int//sub runtimeT.int//-] [int//mul runtimeT.int//*] [int//div runtimeT.int///] [int//rem runtimeT.int//%] ) (do-template [ ] [(def: ( [subjectJS paramJS]) Binary (self-contained (format subjectJS " " " " paramJS)))] [frac//add "+"] [frac//sub "-"] [frac//mul "*"] [frac//div "/"] [frac//rem "%"] [frac//= "==="] [frac//< "<"] [text//= "==="] [text//< "<"] ) (do-template [ ] [(def: ( [subjectJS paramJS]) Binary (format "(" subjectJS "," paramJS ")"))] [int//= runtimeT.int//=] [int//< runtimeT.int//<] ) (def: (frac//encode inputJS) Unary (format (self-contained inputJS) ".toString()")) (def: (frac//decode inputJS) Unary (let [decoding (format "parseFloat(" inputJS ")") thunk (self-contained (format "function () { return " decoding "; }"))] (lux//try thunk))) (do-template [ ] [(def: ( inputJS) Unary (format "(" inputJS ")"))] [int//to-frac runtimeT.int//to-number] [frac//to-int runtimeT.int//from-number] [text//hash runtimeT.text//hash] ) (def: (int//char inputJS) Unary (format "String.fromCharCode" "(" (int//to-frac inputJS) ")")) ## [[Text]] (def: (text//size inputJS) Unary (format inputJS ".length")) (def: (text//concat [subjectJS paramJS]) Binary (format subjectJS "." "concat" "(" paramJS ")")) (def: (text//char [subjectJS paramJS]) Binary (format runtimeT.text//char "(" subjectJS "," paramJS ")")) (do-template [ ] [(def: ( [subjectJS paramJS extraJS]) Trinary (format "(" subjectJS "," paramJS "," extraJS ")"))] [text//clip runtimeT.text//clip] [text//index runtimeT.text//index] ) ## [[Math]] (do-template [ ] [(def: ( inputJS) Unary (format "Math." "(" inputJS ")"))] [math//cos "cos"] [math//sin "sin"] [math//tan "tan"] [math//acos "acos"] [math//asin "asin"] [math//atan "atan"] [math//cosh "cosh"] [math//sinh "sinh"] [math//tanh "tanh"] [math//exp "exp"] [math//log "log"] [math//ceil "ceil"] [math//floor "floor"] [math//round "round"] ) (do-template [ ] [(def: ( [inputJS paramJS]) Binary (format "Math." "(" inputJS "," paramJS ")"))] [math//atan2 "atan2"] [math//pow "pow"] ) ## [[IO]] (def: (io//log messageJS) Unary (void (format runtimeT.io//log "(" messageJS ")"))) (def: (io//error messageJS) Unary (format runtimeT.io//error "(" messageJS ")")) (def: (io//exit codeJS) Unary (format "(" (format "(!((typeof process) === \"undefined\") && process.exit && process.exit(" (int//to-frac codeJS) "))") " || " "window.close()" " || " "location.reload()" ")")) (def: (io//current-time []) Nullary (frac//to-int "(new Date()).getTime()")) ## [[Atoms]] (def: (atom//new initJS) Unary (format "{" runtimeT.atom-field ":" initJS "}")) (def: (atom//read atomJS) Unary (format (self-contained atomJS) "." runtimeT.atom-field)) (def: (atom//compare-and-swap [atomJS oldJS newJS]) Trinary (format runtimeT.atom//compare-and-swap "(" atomJS "," oldJS "," newJS ")")) ## [[Box]] (def: (box//new initJS) Unary (format "[" initJS "]")) (def: (box//read boxJS) Unary (format "(" boxJS ")[0]")) (def: (box//write [valueJS boxJS]) Binary (void (format (box//read boxJS) " = " valueJS))) ## [[Processes]] (def: (process//parallelism-level []) Nullary (frac//to-int "1")) (def: (process//schedule [milli-secondsJS procedureJS]) Binary (format "setTimeout(" "function() {" procedureJS "(null)" "}" "," (int//to-frac milli-secondsJS) ")")) ## [Bundles] (def: lux-procs Bundle (|> (dict.new text.Hash) (install "is" (binary lux//is)) (install "try" (unary lux//try)) (install "if" (trinary lux//if)) (install "loop" lux//loop) (install "recur" lux//recur) )) (def: bit-procs Bundle (<| (prefix "bit") (|> (dict.new text.Hash) (install "and" (binary bit//and)) (install "or" (binary bit//or)) (install "xor" (binary bit//xor)) (install "left-shift" (binary bit//left-shift)) (install "logical-right-shift" (binary bit//logical-right-shift)) (install "arithmetic-right-shift" (binary bit//arithmetic-right-shift)) ))) (def: int-procs Bundle (<| (prefix "int") (|> (dict.new text.Hash) (install "+" (binary int//add)) (install "-" (binary int//sub)) (install "*" (binary int//mul)) (install "/" (binary int//div)) (install "%" (binary int//rem)) (install "=" (binary int//=)) (install "<" (binary int//<)) (install "to-frac" (unary int//to-frac)) (install "char" (unary int//char))))) (def: frac-procs Bundle (<| (prefix "frac") (|> (dict.new text.Hash) (install "+" (binary frac//add)) (install "-" (binary frac//sub)) (install "*" (binary frac//mul)) (install "/" (binary frac//div)) (install "%" (binary frac//rem)) (install "=" (binary frac//=)) (install "<" (binary frac//<)) (install "smallest" (nullary frac//smallest)) (install "min" (nullary frac//min)) (install "max" (nullary frac//max)) (install "to-int" (unary frac//to-int)) (install "encode" (unary frac//encode)) (install "decode" (unary frac//decode))))) (def: text-procs Bundle (<| (prefix "text") (|> (dict.new text.Hash) (install "=" (binary text//=)) (install "<" (binary text//<)) (install "concat" (binary text//concat)) (install "index" (trinary text//index)) (install "size" (unary text//size)) (install "hash" (unary text//hash)) (install "char" (binary text//char)) (install "clip" (trinary text//clip)) ))) (def: array-procs Bundle (<| (prefix "array") (|> (dict.new text.Hash) (install "new" (unary array//new)) (install "get" (binary array//get)) (install "put" (trinary array//put)) (install "remove" (binary array//remove)) (install "size" (unary array//size)) ))) (def: math-procs Bundle (<| (prefix "math") (|> (dict.new text.Hash) (install "cos" (unary math//cos)) (install "sin" (unary math//sin)) (install "tan" (unary math//tan)) (install "acos" (unary math//acos)) (install "asin" (unary math//asin)) (install "atan" (unary math//atan)) (install "cosh" (unary math//cosh)) (install "sinh" (unary math//sinh)) (install "tanh" (unary math//tanh)) (install "exp" (unary math//exp)) (install "log" (unary math//log)) (install "ceil" (unary math//ceil)) (install "floor" (unary math//floor)) (install "round" (unary math//round)) (install "atan2" (binary math//atan2)) (install "pow" (binary math//pow)) ))) (def: io-procs Bundle (<| (prefix "io") (|> (dict.new text.Hash) (install "log" (unary io//log)) (install "error" (unary io//error)) (install "exit" (unary io//exit)) (install "current-time" (nullary io//current-time))))) (def: atom-procs Bundle (<| (prefix "atom") (|> (dict.new text.Hash) (install "new" (unary atom//new)) (install "read" (unary atom//read)) (install "compare-and-swap" (trinary atom//compare-and-swap))))) (def: box-procs Bundle (<| (prefix "box") (|> (dict.new text.Hash) (install "new" (unary box//new)) (install "read" (unary box//read)) (install "write" (binary box//write))))) (def: process-procs Bundle (<| (prefix "process") (|> (dict.new text.Hash) (install "parallelism-level" (nullary process//parallelism-level)) (install "schedule" (binary process//schedule)) ))) (def: #export procedures Bundle (<| (prefix "lux") (|> lux-procs (dict.merge bit-procs) (dict.merge int-procs) (dict.merge frac-procs) (dict.merge text-procs) (dict.merge array-procs) (dict.merge math-procs) (dict.merge io-procs) (dict.merge atom-procs) (dict.merge box-procs) (dict.merge process-procs) )))