github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/compiler/codegen/gen_other.go (about) 1 package codegen 2 3 import ( 4 "github.com/hirochachacha/plua/compiler/ast" 5 "github.com/hirochachacha/plua/compiler/token" 6 "github.com/hirochachacha/plua/internal/version" 7 "github.com/hirochachacha/plua/object" 8 "github.com/hirochachacha/plua/opcode" 9 ) 10 11 // gen with global scope 12 func (g *generator) genFile(f *ast.File) { 13 g.newScope() 14 15 g.LastLineDefined = f.End().Line 16 17 g.IsVararg = true 18 19 g.declareEnviron() 20 21 for _, e := range f.Chunk { 22 g.genStmt(e) 23 } 24 25 g.pushReturn() 26 27 g.closeScope() 28 29 if g.scope != nil { 30 panic("unexpected") 31 } 32 33 g.closeJumps() 34 } 35 36 func (g *generator) genFuncBody(f *ast.FuncBody, self bool, endLine int) { 37 g.newScope() 38 39 g.LineDefined = f.Pos().Line 40 41 if self { 42 g.declareLocal("self", 0) 43 44 for i, param := range f.Params.List { 45 g.declareLocalName(param, i+1) 46 } 47 48 g.NParams = len(f.Params.List) + 1 49 } else { 50 for i, param := range f.Params.List { 51 g.declareLocalName(param, i) 52 } 53 54 g.NParams = len(f.Params.List) 55 } 56 57 g.addSP(g.NParams) 58 59 g.IsVararg = f.Params.Ellipsis.IsValid() 60 61 if f.Body != nil { 62 g.genBlock(f.Body) 63 } 64 65 g.LastLineDefined = endLine 66 67 g.pushReturn() 68 69 g.closeScope() 70 71 g.closeJumps() 72 } 73 74 func (g *generator) genBlock(b *ast.Block) { 75 for _, e := range b.List { 76 g.genStmt(e) 77 } 78 } 79 80 // gen test condtion or immediate bool 81 func (g *generator) genTest(cond ast.Expr, not bool) immBool { 82 switch cond := cond.(type) { 83 case *ast.ParenExpr: 84 return g.genTest(cond.X, not) 85 86 case *ast.BasicLit: 87 if !skipDeadCodeElimination { 88 switch cond.Token.Type { 89 case token.FALSE, token.NIL: 90 if not { 91 return immTrue 92 } 93 return immFalse 94 default: 95 if not { 96 return immFalse 97 } 98 return immTrue 99 } 100 } 101 102 x := g.genExpr(cond, genR) 103 if not { 104 g.pushInst(opcode.AC(opcode.TEST, x, 1)) 105 } else { 106 g.pushInst(opcode.AC(opcode.TEST, x, 0)) 107 } 108 case *ast.UnaryExpr: 109 switch cond.Op { 110 case token.NOT: 111 if !skipDeadCodeElimination { 112 if val, ok := g.foldExpr(cond.X); ok { 113 if !object.ToGoBool(val) { 114 if not { 115 return immFalse 116 } 117 return immTrue 118 } 119 120 if not { 121 return immTrue 122 } 123 return immFalse 124 } 125 } 126 127 return g.genTest(cond.X, !not) 128 default: 129 x := g.genExpr(cond, genR) 130 if not { 131 g.pushInst(opcode.AC(opcode.TEST, x, 1)) 132 } else { 133 g.pushInst(opcode.AC(opcode.TEST, x, 0)) 134 } 135 } 136 case *ast.BinaryExpr: 137 if !skipDeadCodeElimination { 138 if val, ok := g.foldBinary(cond); ok { 139 if object.ToGoBool(val) { 140 if not { 141 return immFalse 142 } 143 return immTrue 144 } 145 146 if not { 147 return immTrue 148 } 149 return immFalse 150 } 151 } 152 153 switch cond.Op { 154 case token.EQ: 155 x := g.genExpr(cond.X, genR|genK) 156 y := g.genExpr(cond.Y, genR|genK) 157 158 if not { 159 g.pushInst(opcode.ABC(opcode.EQ, 1, x, y)) 160 } else { 161 g.pushInst(opcode.ABC(opcode.EQ, 0, x, y)) 162 } 163 case token.NE: 164 x := g.genExpr(cond.X, genR|genK) 165 y := g.genExpr(cond.Y, genR|genK) 166 167 if not { 168 g.pushInst(opcode.ABC(opcode.EQ, 0, x, y)) 169 } else { 170 g.pushInst(opcode.ABC(opcode.EQ, 1, x, y)) 171 } 172 case token.LT: 173 x := g.genExpr(cond.X, genR|genK) 174 y := g.genExpr(cond.Y, genR|genK) 175 176 if not { 177 g.pushInst(opcode.ABC(opcode.LT, 1, x, y)) 178 } else { 179 g.pushInst(opcode.ABC(opcode.LT, 0, x, y)) 180 } 181 case token.LE: 182 x := g.genExpr(cond.X, genR|genK) 183 y := g.genExpr(cond.Y, genR|genK) 184 185 if not { 186 g.pushInst(opcode.ABC(opcode.LE, 1, x, y)) 187 } else { 188 g.pushInst(opcode.ABC(opcode.LE, 0, x, y)) 189 } 190 case token.GT: 191 x := g.genExpr(cond.X, genR|genK) 192 y := g.genExpr(cond.Y, genR|genK) 193 194 if not { 195 g.pushInst(opcode.ABC(opcode.LT, 1, y, x)) 196 } else { 197 g.pushInst(opcode.ABC(opcode.LT, 0, y, x)) 198 } 199 case token.GE: 200 x := g.genExpr(cond.X, genR|genK) 201 y := g.genExpr(cond.Y, genR|genK) 202 203 if not { 204 g.pushInst(opcode.ABC(opcode.LE, 1, y, x)) 205 } else { 206 g.pushInst(opcode.ABC(opcode.LE, 0, y, x)) 207 } 208 case token.AND: 209 if !skipDeadCodeElimination { 210 if val, ok := g.foldExpr(cond.X); ok { 211 if !object.ToGoBool(val) { 212 if not { 213 return immTrue 214 } 215 return immFalse 216 } 217 218 return g.genTest(cond.Y, not) 219 } 220 } 221 222 x := g.genExpr(cond, genR) 223 if not { 224 g.pushInst(opcode.AC(opcode.TEST, x, 1)) 225 } else { 226 g.pushInst(opcode.AC(opcode.TEST, x, 0)) 227 } 228 case token.OR: 229 if !skipDeadCodeElimination { 230 if val, ok := g.foldExpr(cond.X); ok { 231 if object.ToGoBool(val) { 232 if not { 233 return immFalse 234 } 235 return immTrue 236 } 237 238 return g.genTest(cond.Y, not) 239 } 240 } 241 242 x := g.genExpr(cond, genR) 243 if not { 244 g.pushInst(opcode.AC(opcode.TEST, x, 1)) 245 } else { 246 g.pushInst(opcode.AC(opcode.TEST, x, 0)) 247 } 248 default: 249 x := g.genExpr(cond, genR) 250 if not { 251 g.pushInst(opcode.AC(opcode.TEST, x, 1)) 252 } else { 253 g.pushInst(opcode.AC(opcode.TEST, x, 0)) 254 } 255 } 256 // no optimization 257 default: 258 x := g.genExpr(cond, genR) 259 if not { 260 g.pushInst(opcode.AC(opcode.TEST, x, 1)) 261 } else { 262 g.pushInst(opcode.AC(opcode.TEST, x, 0)) 263 } 264 } 265 266 return immUndefined 267 } 268 269 func (g *generator) genConst(val object.Value, typ genType) (rk int) { 270 k := g.constant(val) 271 272 if typ&genK != 0 { 273 return g.markRK(k, true) 274 } 275 276 if k > opcode.MaxBx { 277 g.pushInst(opcode.ABx(opcode.LOADKX, g.sp, 0)) 278 g.pushInst(opcode.Ax(opcode.EXTRAARG, k)) 279 } else { 280 g.pushInst(opcode.ABx(opcode.LOADK, g.sp, k)) 281 } 282 283 rk = g.sp 284 285 g.nextSP() 286 287 return 288 } 289 290 func (g *generator) genSetGlobal(name *ast.Name, r int) { 291 env, ok := g.resolve(version.LUA_ENV) 292 if !ok { 293 panic("unexpected") 294 } 295 296 rk := g.markRK(g.constant(object.String(name.Name)), false) 297 298 switch env.kind { 299 case linkLocal: 300 g.pushInst(opcode.ABC(opcode.SETTABLE, env.index, rk, r)) 301 case linkUpval: 302 g.pushInst(opcode.ABC(opcode.SETTABUP, env.index, rk, r)) 303 default: 304 panic("unreachable") 305 } 306 } 307 308 func (g *generator) genGetGlobal(name *ast.Name) (r int) { 309 env, ok := g.resolve(version.LUA_ENV) 310 if !ok { 311 panic("unexpected") 312 } 313 314 rk := g.markRK(g.constant(object.String(name.Name)), false) 315 316 switch env.kind { 317 case linkLocal: 318 g.pushInst(opcode.ABC(opcode.GETTABLE, g.sp, env.index, rk)) 319 case linkUpval: 320 g.pushInst(opcode.ABC(opcode.GETTABUP, g.sp, env.index, rk)) 321 default: 322 panic("unreachable") 323 } 324 325 r = g.sp 326 327 g.nextSP() 328 329 return 330 } 331 332 func (g *generator) genPrefix(prefix []*ast.Name) (r int) { 333 sp := g.sp 334 335 r = g.genName(prefix[0], genR) 336 for _, name := range prefix[1:] { 337 y := g.genName(name, genKey) 338 339 g.pushInst(opcode.ABC(opcode.GETTABLE, sp, r, y)) 340 341 r = sp 342 } 343 344 if r == sp { 345 g.setSP(sp + 1) 346 } 347 348 return 349 }