(.module: [lux #- not or and list if] (lux (control pipe) (data [text] text/format [number] (coll [list "list/" Functor Fold])) (type abstract))) (abstract: #export Single {} Any) (abstract: #export Poly {} Any) (abstract: #export Keyword {} Any) (abstract: #export (Var kind) {} Text (def: name (All [k] (-> (Var k) Text)) (|>> :representation)) (def: #export var (-> Text (Var Single)) (|>> :abstraction)) (do-template [ ] [(def: #export (-> (Var Single) (Var )) (|>> :representation (format ) :abstraction))] [poly Poly "*"] [keyword Keyword "**"] ) ) (type: #export SVar (Var Single)) (type: #export PVar (Var Poly)) (type: #export KVar (Var Keyword)) (abstract: #export Expression {} Text (def: #export expression (-> Expression Text) (|>> :representation)) (def: #export code (-> Text Expression) (|>> :abstraction)) (def: #export none Expression (:abstraction "None")) (def: #export bool (-> Bit Expression) (|>> (case> #0 "False" #1 "True") :abstraction)) (def: #export int (-> Int Expression) (|>> %i :abstraction)) (def: #export float (-> Frac Expression) (|>> (cond> [(f/= number.positive-infinity)] [(new> "float(\"inf\")")] [(f/= number.negative-infinity)] [(new> "float(\"-inf\")")] [(f/= number.not-a-number)] [(new> "float(\"nan\")")] ## else [%f]) :abstraction)) (def: #export string (-> Text Expression) (|>> %t :abstraction)) (def: (composite-literal left-delimiter right-delimiter entry-serializer) (All [a] (-> Text Text (-> a Text) (-> (List a) Expression))) (function (_ entries) (:abstraction (format "(" left-delimiter (|> entries (list/map entry-serializer) (text.join-with ",")) right-delimiter ")")))) (do-template [
 ]
    [(def: #export 
       (-> (List Expression) Expression)
       (composite-literal 
  expression))]

    [tuple "(" ")"]
    [list  "[" "]"]
    )
  
  (def: #export (slice from to list)
    (-> Expression Expression Expression Expression)
    (:abstraction (format "(" (:representation list)
                          "[" (:representation from) ":" (:representation to) "]"
                          ")")))

  (def: #export (slice-from from list)
    (-> Expression Expression Expression)
    (:abstraction (format "(" (:representation list)
                          "[" (:representation from) ":]"
                          ")")))

  (def: #export dict
    (-> (List [Expression Expression]) Expression)
    (composite-literal "{" "}" (.function (_ [k v]) (format (:representation k) " : " (:representation v)))))

  (def: #export (apply args func)
    (-> (List Expression) Expression Expression)
    (:abstraction (format "(" (:representation func)
                          "(" (text.join-with "," (list/map expression args)) ")"
                          ")")))

  (do-template [  ]
    [(def: ( var)
       (-> Expression Text)
       (format  (:representation var)))]

    [splat-poly    Poly    "*"]
    [splat-keyword Keyword "**"]
    )

  (do-template [ ]
    [(def: #export ( args extra func)
       (-> (List Expression) Expression Expression Expression)
       (:abstraction (format "(" (:representation func)
                             (format "(" (|> args
                                             (list/map (function (_ arg) (format (:representation arg) ", ")))
                                             (text.join-with ""))
                                     ( extra) ")")
                             ")")))]

    [apply-poly    splat-poly]
    [apply-keyword splat-keyword]
    )

  (def: #export (field name object)
    (-> Text Expression Expression)
    (:abstraction (format "(" (:representation object) "." name ")")))

  (def: #export (send args method object)
    (-> (List Expression) Text Expression Expression)
    (|> object (field method) (apply args)))

  (do-template [ ]
    [(def: #export ( args extra method)
       (-> (List Expression) Expression Text
           (-> Expression Expression))
       (|>> (field method) ( args extra)))]

    [send-poly    apply-poly]
    [send-keyword apply-keyword]
    )

  (def: #export (nth idx array)
    (-> Expression Expression Expression)
    (:abstraction (format "(" (:representation array) "[" (:representation idx) "])")))

  (def: #export (if test then else)
    (-> Expression Expression Expression Expression)
    (:abstraction (format "(" (:representation then)
                          " if " (:representation test)
                          " else " (:representation else)
                          ")")))

  (do-template [ ]
    [(def: #export ( param subject)
       (-> Expression Expression Expression)
       (:abstraction (format "(" (:representation subject)
                             " "  " "
                             (:representation param) ")")))]

    [is      "is"]
    [=       "=="]
    [<       "<"]
    [<=      "<="]
    [>       ">"]
    [>=      ">="]
    [+       "+"]
    [-       "-"]
    [*       "*"]
    [/       "/"]
    [%       "%"]
    [**      "**"]
    [bit-or  "|"]
    [bit-and "&"]
    [bit-xor "^"]
    [bit-shl "<<"]
    [bit-shr ">>"]
    )

  (do-template [ ]
    [(def: #export ( param subject)
       (-> Expression Expression Expression)
       (:abstraction (format "(" (:representation param)
                             " "  " "
                             (:representation subject) ")")))]

    [or      "or"]
    [and     "and"]
    )

  (def: #export (not subject)
    (-> Expression Expression)
    (:abstraction (format "(not " (:representation subject) ")")))

  (def: #export (@@ var)
    (All [k] (-> (Var k) Expression))
    (:abstraction (format "(" (..name var) ")")))

  (def: #export (lambda arguments body)
    (-> (List (Ex [k] (Var k))) Expression Expression)
    (:abstraction (format "(" "lambda " (|> arguments (list/map ..name) (text.join-with ", ")) ": "
                          (:representation body) ")")))

  (def: #export global
    (-> Text Expression)
    (|>> var @@))

  (def: #export (length sequence)
    (-> Expression Expression)
    (apply (.list sequence) (global "len")))
  )

(abstract: #export Statement
  {}
  
  Text

  (def: #export statement (-> Statement Text) (|>> :representation))

  (def: nest
    (-> Statement Text)
    (|>> :representation
         (format text.new-line)
         (text.replace-all text.new-line (format text.new-line text.tab))))

  (def: #export (set-nth! idx value array)
    (-> Expression Expression Expression Statement)
    (:abstraction (format (expression array) "[" (expression idx) "] = " (expression value))))

  (def: #export (set! vars value)
    (-> (List (Var Single)) Expression Statement)
    (:abstraction
     (format (|> vars (list/map ..name) (text.join-with ", "))
             " = "
             (expression value))))

  (def: #export (if! test then! else!)
    (-> Expression Statement Statement Statement)
    (:abstraction
     (format "if " (expression test) ":"
             (nest then!)
             text.new-line "else:"
             (nest else!))))

  (def: #export (when! test then!)
    (-> Expression Statement Statement)
    (:abstraction
     (format "if " (expression test) ":"
             (nest then!))))

  (def: #export (cond! clauses else!)
    (-> (List [Expression Statement]) Statement Statement)
    (list/fold (.function (_ [test then!] next!)
                 (if! test then! next!))
               else!
               (list.reverse clauses)))

  (def: #export (then! pre! post!)
    (-> Statement Statement Statement)
    (:abstraction
     (format (:representation pre!)
             text.new-line
             (:representation post!))))

  (def: #export (while! test body!)
    (-> Expression Statement Statement)
    (:abstraction
     (format "while " (expression test) ":"
             (nest body!))))

  (def: #export (for-in! var inputs body!)
    (-> SVar Expression Statement Statement)
    (:abstraction
     (format "for " (..name var) " in " (expression inputs) ":"
             (nest body!))))

  (def: #export (do! expression)
    (-> Expression Statement)
    (:abstraction
     (format (..expression expression) ";")))

  (def: #export no-op!
    Statement
    (:abstraction text.new-line))

  (type: #export Except
    {#classes (List Text)
     #exception SVar
     #handler Statement})
  
  (def: #export (try! body! excepts)
    (-> Statement (List Except) Statement)
    (:abstraction
     (format "try:"
             (nest body!)
             (|> excepts
                 (list/map (function (_ [classes exception catch!])
                             (format text.new-line "except (" (text.join-with "," classes)
                                     ") as " (..name exception) ":"
                                     (nest catch!))))
                 (text.join-with "")))))

  (do-template [ ]
    [(def: #export ( message)
       (-> Expression Statement)
       (:abstraction
        (format  " " (expression message))))]

    [raise!  "raise"]
    [return! "return"]
    [print!  "print"]
    )
  
  (def: #export (def! name args body)
    (-> (Var Single) (List (Ex [k] (Var k))) Statement Statement)
    (:abstraction
     (format "def " (..name name)
             "(" (|> args (list/map ..name) (text.join-with ",")) "):"
             (nest body))))

  (def: #export (import! module-name)
    (-> Text Statement)
    (:abstraction (format "import " module-name)))
  )