forked from axellang/axel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAxel.axel
89 lines (68 loc) · 2.76 KB
/
Axel.axel
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
(pragma "OPTIONS_GHC -Wno-incomplete-patterns")
(module Axel)
(import Axel.Prelude all)
(import Axel.Parse [hygenisizeIdentifier])
(importq Axel.Sourcemap SM all)
(import Axel.Utils.FilePath [takeFileName])
(import Data.IORef [IORef modifyIORef newIORef readIORef])
(importq Data.Text T all)
(import System.IO.Unsafe [unsafePerformIO])
(=macro applyInfix [op x] (pure [`(flip ~op ~x)]))
(=macro applyInfix [x op y] (pure [`(~op ~x ~y)]))
(=macro defmacro {name : cases}
(pure (map (\ [(AST.SExpression _ {args : body})]
`(=macro ~name ~args ~@body)) cases)))
(defmacro def
({name : {typeSig : cases}}
(pure
(:
`(:: ~name ~@typeSig)
(map
(\
[(AST.SExpression
_
{(AST.SExpression _ {(AST.Symbol _ "list") : args}) : xs})]
`(= (~name ~@args) ~@xs))
cases)))))
(def if ([] {Bool -> {a -> {a -> a}}})
([True x _] x) ([False _ x] x))
(=macro syntaxQuote [x]
(pure
[(AST.quoteExpression (const (AST.Symbol Nothing "_")) x)]))
(def expandDo ([] {([] SM.Expression) -> SM.Expression})
([{(AST.SExpression _ [(syntaxQuote <-) var val]) : rest}]
`(>>= ~val (\ [~var] ~(expandDo rest))))
([{(AST.SExpression _ {(syntaxQuote let) : bindings}) : rest}]
`(let [~@bindings] ~(expandDo rest)))
([{val : rest}]
(case rest ([] val) (_ `(>> ~val ~(expandDo rest))))))
(defmacro do (input (pure [(expandDo input)])))
(:: gensymCounter [] (IORef Int))
(= gensymCounter (unsafePerformIO (newIORef 0)))
(pragma "NOINLINE gensymCounter")
(:: gensym [] (IO SM.Expression))
(= gensym (do
(<- suffix (readIORef gensymCounter))
(let (identifier
{"aXEL_AUTOGENERATED_IDENTIFIER_" <> (showText suffix)}))
(modifyIORef gensymCounter succ)
(pure (AST.Symbol Nothing (T.unpack identifier)))))
(=macro \case cases
(fmap (\ [varId] [`(\ [~varId] (case ~varId ~@cases))])
gensym))
(=macro | cases
(pure
[(foldr
(\ [(AST.SExpression _ [cond x]) acc] `(if ~cond ~x ~acc))
'undefined
cases)]))
(:: isPrelude [] {FilePath -> Bool})
(= isPrelude {(== (FilePath "Axel.axel")) . takeFileName})
(:: preludeMacros [] ([] Text))
(= preludeMacros (map {T.pack . hygenisizeIdentifier} ["|"
"applyInfix"
"defmacro"
"def"
"do"
"\\case"
"syntaxQuote"]))