|
| 1 | +## The home of all intermediate languages and passes, representing the core of |
| 2 | +## the compiler. |
| 3 | + |
| 4 | +import |
| 5 | + nanopass/nanopass, |
| 6 | + experimental/sexp_parse |
| 7 | + |
| 8 | +defineLanguage Lsrc: |
| 9 | + n(int) |
| 10 | + fl(float) |
| 11 | + str(string) |
| 12 | + # TODO: only allow a type being used as a terminal once |
| 13 | + x(string) # identifier |
| 14 | + |
| 15 | + rec_field(rf) ::= Field(x, e) |
| 16 | + field_decl(f) ::= Field(x, t) |
| 17 | + |
| 18 | + pattern(p) ::= As(x, t) |
| 19 | + mrule(mr) ::= Rule(p, e) |
| 20 | + expr(e) ::= n | fl | x | |
| 21 | + ArrayCons(...e) | |
| 22 | + TupleCons(...e) | |
| 23 | + RecordCons(rf0, ...rf1) | |
| 24 | + Seq(t, ...e) | |
| 25 | + Seq(str) | |
| 26 | + Call(e, ...e) | |
| 27 | + FieldAccess(e, n) | |
| 28 | + FieldAccess(e, x) | |
| 29 | + At(e0, e1) | |
| 30 | + As(e, t) | |
| 31 | + And(e0, e1) | |
| 32 | + Or(e0, e1) | |
| 33 | + If(e0, e1) | |
| 34 | + If(e0, e1, e2) | |
| 35 | + While(e0, e1) | |
| 36 | + Return(e) | |
| 37 | + Unreachable() | |
| 38 | + Exprs(...e0, e1) | |
| 39 | + Asgn(e0, e1) | |
| 40 | + Decl(x, e) | |
| 41 | + Match(e, mr0, ...mr1) |
| 42 | + typ(t) ::= x | VoidTy() | UnitTy() | BoolTy() | IntTy() | FloatTy() | |
| 43 | + ArrayTy(n, t) | |
| 44 | + SeqTy(t) | |
| 45 | + TupleTy(t0, ...t1) | |
| 46 | + RecordTy(f0, ...f1) | |
| 47 | + UnionTy(t0, ...t1) | |
| 48 | + ProcTy(t0, ...t1) |
| 49 | + |
| 50 | + param_decl(pd) ::= ParamDecl(x, t) |
| 51 | + params(pa) ::= Params(...pd) |
| 52 | + decl(d) ::= ProcDecl(x, t, pa, e) | TypeDecl(x, t) |
| 53 | + module(m) ::= Module(...d) |
| 54 | + |
| 55 | +defineLanguage L1, Lsrc: |
| 56 | + ## Language without And and Or. |
| 57 | + expr(e) ::= -And(e, e) | -Or(e, e) |
| 58 | + |
| 59 | +defineLanguage L2, L1: |
| 60 | + ## Language without single-branch `If`. |
| 61 | + expr(e) ::= -If(e, e) |
| 62 | + |
| 63 | +defineLanguage L3, L2: |
| 64 | + ## Language that replaces Decl with Let. |
| 65 | + expr(e) ::= -Decl(x, e) | +Let(x, e, e) |
| 66 | + |
| 67 | +defineLanguage L4, L3: |
| 68 | + ## Removes the `Match` form. |
| 69 | + pattern(p) ::= -As(x, t) |
| 70 | + mrule(mr) ::= -Rule(p, e) |
| 71 | + expr(e) ::= -Match(e, mr, ...mr) |
| 72 | + |
| 73 | +defineLanguage L5, L4: |
| 74 | + ## Removes the While form and adds the Loop and Break form. |
| 75 | + expr(e) ::= -While(e, e) | +Loop(e) | +Break(n) |
| 76 | + |
| 77 | +defineLanguage L6, L5: |
| 78 | + ## Requires explicit copies. |
| 79 | + root(ro) ::= +lv | +e |
| 80 | + lvalue(lv) ::= |
| 81 | + +At(ro, e) | |
| 82 | + +FieldAccess(ro, n) |
| 83 | + expr(e) ::= |
| 84 | + -At(e, e) | |
| 85 | + -FieldAccess(e, n) | |
| 86 | + +Copy(lv) |
| 87 | + |
| 88 | +proc parse(s: var SexpParser): Lsrc {.inpass.} = |
| 89 | + ## Parses the source language from an S-expression stream. |
| 90 | + proc ident(s: var SexpParser): dst.x {.transform.} = |
| 91 | + s.space() |
| 92 | + s.expect(tkIdent) |
| 93 | + build x(s.eatString()) |
| 94 | + |
| 95 | + proc call(s: var SexpParser): dst.e {.transform.} = |
| 96 | + let callee = expr(s) |
| 97 | + var x = @[expr(s)] |
| 98 | + s.space() |
| 99 | + while s.currToken != tkParensRi: |
| 100 | + expr(s) |
| 101 | + s.space() |
| 102 | + |
| 103 | + s.eat(tkParensRi) |
| 104 | + build Call(callee, x) |
| 105 | + |
| 106 | + proc expr(s: var SexpParser): dst.e {.transform.} = |
| 107 | + s.space() |
| 108 | + case s.currToken |
| 109 | + of tkParsensLe: |
| 110 | + let k = s.getTok() |
| 111 | + if k == tkIdent: |
| 112 | + case s.currString |
| 113 | + of "if": |
| 114 | + build If(expr(s), expr(s), expr(s)) |
| 115 | + of "while": |
| 116 | + build While(expr(s), expr(s)) |
| 117 | + of "decl": |
| 118 | + build Decl(ident(s), expr(s)) |
| 119 | + of "and": |
| 120 | + build And(expr(s), expr(s)) |
| 121 | + of "or": |
| 122 | + build Or(expr(s), expr(s)) |
| 123 | + else: |
| 124 | + # TODO: implement the remaining keywords |
| 125 | + call(s) |
| 126 | + else: |
| 127 | + call(s) |
| 128 | + |
| 129 | + of tkString: |
| 130 | + build str(s.eatString()) |
| 131 | + of tkIdent: |
| 132 | + build x(s.eatString()) |
| 133 | + of tkInt: |
| 134 | + build n(parseInt(s.eatString())) |
| 135 | + of tkFloat: |
| 136 | + build fl(parseFloat(s.eatString())) |
| 137 | + else: |
| 138 | + syntaxError(s) |
| 139 | + |
| 140 | + proc typ(s: var SexpParser): dst.t {.transform.} = |
| 141 | + s.space() |
| 142 | + # TODO: implement |
| 143 | + |
| 144 | + proc params(s: var SexprParser): dst.pa {.transform.} = |
| 145 | + s.space() |
| 146 | + # TODO: implement |
| 147 | + |
| 148 | + proc top(s: var SexpParser): dst.d {.transform.} = |
| 149 | + s.eat(tkParensLe) |
| 150 | + s.expect(tkIdent) |
| 151 | + case s.currToken |
| 152 | + of "proc": |
| 153 | + build ProcDecl(ident(s), typ(s), params(s), expr(s)) |
| 154 | + of "type": |
| 155 | + build TypeDecl(ident(s), typ(s)) |
| 156 | + else: |
| 157 | + syntaxError() |
| 158 | + |
| 159 | +proc removeAndOr(_: Lsrc): L1 {.pass.} = |
| 160 | + proc expr(_: src.e): dst.e {.transform.} = |
| 161 | + And([a], [b]) -> build If(a, b, x("false")) |
| 162 | + Or([a], [b]) -> build If(a, x("true"), b) |
| 163 | + |
| 164 | +proc removeSingleIf(_: L1): L2 {.pass.} = |
| 165 | + proc expr(_: src.e): dst.e {.transform.} = |
| 166 | + If([a], [b]) -> build If(a, b, TupleCons()) |
| 167 | + |
| 168 | +proc declToLet(_: L2): L3 {.pass.} = |
| 169 | + proc expr(_: src.e): dst.e {.transform.} = |
| 170 | + Decl(`x`, `e`) -> build Let(x, e, TupleCons()) |
| 171 | + Exprs(`e0`, [last]): |
| 172 | + var r = last |
| 173 | + var got: seq[dst.e] |
| 174 | + for i in countdown(e0.high, 0): |
| 175 | + match e0[i]: |
| 176 | + Decl(`x`, `e`): |
| 177 | + r = |
| 178 | + if got.len == 0: build Let(x, e, r) |
| 179 | + else: build Let(x, e, Exprs(got, r)) |
| 180 | + else: |
| 181 | + got.insert expr(e0[i]) |
| 182 | + |
| 183 | + if got.len == 0: build Exprs(got, r) |
| 184 | + else: r |
0 commit comments