(.require [library [lux (.except Alias) [abstract [monad (.only do)]] [control ["<>" parser (.use "[1]#[0]" monad)] ["[0]" io] ["[0]" maybe]] [data ["[0]" product] ["[0]" text ["%" \\format]] [collection ["[0]" list (.use "[1]#[0]" functor)]]] ["[0]" meta (.only) ["@" target] [type abstract] ["[0]" code (.only) ["<[1]>" \\parser (.only Parser)]] [macro (.only with_symbols) [syntax (.only syntax)] ["[0]" template]]]]]) (primitive .public (Object brand) Any) (with_template [] [(with_expansions [ (template.symbol [ "'"])] (primitive .public Any) (type .public (..Object )))] [Null] [Function] ) (with_template [ ] [(type .public )] [Boolean Bit] [Integer Int] [Float Frac] [String Text] ) (type Nullable [Bit Code]) (def nullable (Parser Nullable) (let [token (' "?")] (<| (<>.and (<>.parses? (.this token))) (<>.after (<>.not (.this token))) .any))) (type Alias Text) (def alias (Parser Alias) (<>.after (.this (' "as")) .local)) (type Field [Bit Text (Maybe Alias) Nullable]) (def static! (Parser Any) (.this (' "static"))) (def field (Parser Field) (.form (all <>.and (<>.parses? ..static!) .local (<>.maybe ..alias) ..nullable))) (def constant (Parser Field) (.form (all <>.and (<>#in true) .local (<>.maybe ..alias) ..nullable))) (type Common_Method (Record [#name Text #alias (Maybe Alias) #inputs (List Nullable) #io? Bit #try? Bit #output Nullable])) (type Static_Method Common_Method) (type Virtual_Method Common_Method) (type Method (Variant {#Static Static_Method} {#Virtual Virtual_Method})) (def common_method (Parser Common_Method) (all <>.and .local (<>.maybe ..alias) (.tuple (<>.some ..nullable)) (<>.parses? (.this (' "io"))) (<>.parses? (.this (' "try"))) ..nullable)) (def static_method (<>.after ..static! ..common_method)) (def method (Parser Method) (.form (<>.or ..static_method ..common_method))) (type Member (Variant {#Field Field} {#Method Method})) (def member (Parser Member) (all <>.or ..field ..method )) (def input_variables (-> (List Nullable) (List [Bit Code])) (|>> list.enumeration (list#each (function (_ [idx [nullable? type]]) [nullable? (|> idx %.nat code.local)])))) (def (nullable_type [nullable? type]) (-> Nullable Code) (if nullable? (` (.Maybe (, type))) type)) (def (with_null g!temp [nullable? input]) (-> Code [Bit Code] Code) (if nullable? (` (when (, input) {.#Some (, g!temp)} (, g!temp) {.#Null} ("php object null"))) input)) (def (without_null g!temp [nullable? outputT] output) (-> Code Nullable Code Code) (if nullable? (` (let [(, g!temp) (, output)] (if ("php object null?" (, g!temp)) {.#None} {.#Some (, g!temp)}))) (` (let [(, g!temp) (, output)] (if (not ("php object null?" (, g!temp))) (, g!temp) (.panic! "Null is an invalid value!")))))) (type Import (Variant {#Class Text (Maybe Alias) Text (List Member)} {#Function Static_Method} {#Constant Field})) (def import (Parser Import) (all <>.or (all <>.and .local (<>.maybe ..alias) (<>.else ["" (list)] (.tuple (<>.and .text (<>.some member))))) (.form ..common_method) ..constant )) (def .public try (syntax (_ [expression .any]) ... {.#doc (example (when (try (risky_computation input)) ... {.#Right success} ... (do_something success) ... {.#Left error} ... (recover_from_failure error)))} (in (list (` ("lux try" (io.io (, expression)))))))) (def (with_io with? without) (-> Bit Code Code) (if with? (` (io.io (, without))) without)) (def (io_type io? rawT) (-> Bit Code Code) (if io? (` (io.IO (, rawT))) rawT)) (def (with_try with? without_try) (-> Bit Code Code) (if with? (` (..try (, without_try))) without_try)) (def (try_type try? rawT) (-> Bit Code Code) (if try? (` (.Either .Text (, rawT))) rawT)) (def (make_function g!method g!temp source inputsT io? try? outputT) (-> Code Code Code (List Nullable) Bit Bit Nullable Code) (let [g!inputs (input_variables inputsT)] (` (def ((, g!method) [(,* (list#each product.right g!inputs))]) (-> [(,* (list#each nullable_type inputsT))] (, (|> (nullable_type outputT) (try_type try?) (io_type io?)))) (as_expected (, (<| (with_io io?) (with_try try?) (without_null g!temp outputT) (` ("php apply" (as ..Function (, source)) (,* (list#each (with_null g!temp) g!inputs))))))))))) (def .public import (syntax (_ [import ..import]) (with_symbols [g!temp] (when import {#Class [class alias format members]} (with_symbols [g!object] (let [qualify (is (-> Text Code) (function (_ member_name) (|> format (text.replaced "[1]" (maybe.else class alias)) (text.replaced "[0]" member_name) code.local))) g!type (code.local (maybe.else class alias)) class_import (` ("php constant" (, (code.text class))))] (in (list.partial (` (type (, g!type) (..Object (Primitive (, (code.text class)))))) (list#each (function (_ member) (when member {#Field [static? field alias fieldT]} (let [g!field (qualify (maybe.else field alias))] (if static? (` (def (, g!field) (syntax ((, g!field) []) (at meta.monad (,' in) (list (` (.as (, (nullable_type fieldT)) ("php constant" (, (code.text (%.format class "::" field))))))))))) (` (def ((, g!field) (, g!object)) (-> (, g!type) (, (nullable_type fieldT))) (as_expected (, (without_null g!temp fieldT (` ("php object get" (, (code.text field)) (as (..Object .Any) (, g!object))))))))))) {#Method method} (when method {#Static [method alias inputsT io? try? outputT]} (..make_function (qualify (maybe.else method alias)) g!temp (` ("php object get" (, (code.text method)) (as (..Object .Any) ("php constant" (, (code.text (%.format class "::" method))))))) inputsT io? try? outputT) {#Virtual [method alias inputsT io? try? outputT]} (let [g!inputs (input_variables inputsT)] (` (def ((, (qualify (maybe.else method alias))) [(,* (list#each product.right g!inputs))] (, g!object)) (-> [(,* (list#each nullable_type inputsT))] (, g!type) (, (|> (nullable_type outputT) (try_type try?) (io_type io?)))) (as_expected (, (<| (with_io io?) (with_try try?) (without_null g!temp outputT) (` ("php object do" (, (code.text method)) (, g!object) (,* (list#each (with_null g!temp) g!inputs))))))))))))) members))))) {#Function [name alias inputsT io? try? outputT]} (let [imported (` ("php constant" (, (code.text name))))] (in (list (..make_function (code.local (maybe.else name alias)) g!temp imported inputsT io? try? outputT)))) {#Constant [_ name alias fieldT]} (let [imported (` ("php constant" (, (code.text name)))) g!name (code.local (maybe.else name alias))] (in (list (` (def (, g!name) (syntax ((, g!name) []) (at meta.monad (,' in) (list (` (.as (, (nullable_type fieldT)) (, imported))))))))))) ))))