aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/compiler.lux
blob: 205c62df0906fcc09433a466df34d36db7c0787d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
(;module:
  lux
  (lux (control monad)
       [io #- run]
       (data ["E" error]
             [text "T/" Eq<Text>]
             text/format)
       [macro #+ Monad<Lux>])
  (luxc ["&" base]
        ["&;" io]
        ["&;" module]
        (compiler ["&&;" runtime]
                  ["&&;" statement])
        ))

(def: (compile ast)
  (-> AST (Lux Unit))
  (case ast
    (^ [_ (#;FormS (list [_ (#;SymbolS ["" "_lux_def"])]
                         [_ (#;SymbolS ["" def-name])]
                         def-value
                         def-meta))])
    (&&statement;compile-def def-name def-value def-meta)

    (^ [_ (#;FormS (list [_ (#;SymbolS ["" "_lux_program"])]
                         [_ (#;SymbolS ["" prog-args])]
                         prog-body))])
    (&&statement;compile-program prog-args prog-body)

    _
    (&;fail (format "Unrecognized statement: " (%ast ast)))))

(def: (exhaust action)
  (All [a] (-> (Lux a) (Lux Unit)))
  (do Monad<Lux>
    [result action]
    (exhaust action)))

(def: (compile-module source-dirs module-name compiler-state)
  (-> (List &;Path) Text Compiler (IO (Error Compiler)))
  (do Monad<IO>
    [[file-name file-content] (&io;read-module source-dirs module-name)
     #let [file-hash (T/hash file-content)]
     #let [result (macro;run compiler-state
                             (do Monad<Lux>
                               [module-exists? (&module;exists? module-name)]
                               (if module-exists?
                                 (&;fail (format "Cannot re-define a module: " module-name))
                                 (wrap []))))]]
    (case result
      (#E;Success [compiler-state _])
      (let [result (macro;run compiler-state
                              (do Monad<Lux>
                                [_ (&module;create module-name file-hash)
                                 _ (&module;flag-active module-name)
                                 _ (if (T/= "lux" module-name)
                                     &&runtime;compile-runtime
                                     (wrap []))
                                 _ (exhaust
                                    (do @
                                      [ast parse]
                                      (compile ast)))
                                 _ (&module;flag-compiled module-name)]
                                (&module;generate-module file-hash module-name)))]
        (case result
          (#E;Success [compiler-state module-descriptor])
          (do @
            [_ (&io;write-module module-name module-descriptor)]
            (wrap (#E;Success compiler-state)))

          (#E;Error error)
          (wrap (#E;Error error))))
      
      (#E;Error error)
      (wrap (#E;Error error)))))

(def: (or-crash! action)
  (All [a] (-> (IO (E;Error a)) (IO a)))
  (do Monad<IO>
    [result action]
    (case result
      (#E;Success output)
      (wrap output)

      (#E;Error error)
      (error! (format "Compilation failed:\n" error)))))

(def: #export (compile-program mode program target sources)
  (-> &;Mode &;Path &;Path (List &;Path) (IO Unit))
  (do Monad<IO>
    [#let [compiler-state (init-compiler-state mode host-state)]
     compiler-state (or-crash! (compile-module source-dirs "lux" compiler-state))
     compiler-state (or-crash! (compile-module source-dirs program compiler-state))
     #let [_ (log! "Compilation complete!")]]
    (wrap [])))