github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/astcomp/astcomp.go (about) 1 package astcomp 2 3 import ( 4 "fmt" 5 6 "github.com/arnodel/golua/ast" 7 "github.com/arnodel/golua/ir" 8 ) 9 10 // CompileLuaChunk compiles the given block statement to IR code and returns a 11 // slice or ir.Contant values and the index to the main code constant. 12 func CompileLuaChunk(source string, s ast.BlockStat) (kidx uint, consts []ir.Constant, err error) { 13 defer func() { 14 if r := recover(); r != nil { 15 compErr, ok := r.(Error) 16 if !ok { 17 panic(r) 18 } 19 err = compErr 20 } 21 }() 22 kp := ir.NewConstantPool() 23 rootIrC := ir.NewCodeBuilder("<global chunk>", kp) 24 rootIrC.DeclareLocal("_ENV", rootIrC.GetFreeRegister()) 25 irC := rootIrC.NewChild("<main chunk>") 26 c := &compiler{CodeBuilder: irC} 27 c.compileFunctionBody(ast.Function{ 28 ParList: ast.ParList{HasDots: true}, 29 Body: s, 30 }) 31 kidx, _ = irC.Close() 32 return kidx, kp.Constants(), nil 33 } 34 35 type compiler struct { 36 *ir.CodeBuilder 37 } 38 39 func (c *compiler) NewChild(name string) *compiler { 40 return &compiler{ 41 CodeBuilder: c.CodeBuilder.NewChild(name), 42 } 43 } 44 45 // Names of various labels and registers used during compilation. 46 const ( 47 breakLblName = ir.Name("<break>") 48 ellipsisRegName = ir.Name("...") 49 callerRegName = ir.Name("<caller>") 50 loopFRegName = ir.Name("<f>") 51 loopSRegName = ir.Name("<s>") 52 loopVarRegName = ir.Name("<var>") 53 ) 54 55 // Error that results from a valid AST which does not form a valid program. 56 type Error struct { 57 Where ast.Locator 58 Message string 59 } 60 61 func (e Error) Error() string { 62 loc := e.Where.Locate().StartPos() 63 return fmt.Sprintf("%d:%d: %s", loc.Line, loc.Column, e.Message) 64 } 65 66 // The compiler uses other packages that may return non nil errors only if there 67 // is a bug in the compiler. Such errors are wrapped in must() so that the bugs 68 // are not silently ignored. 69 type compilerBug struct { 70 err error 71 } 72 73 func (b compilerBug) Error() string { 74 return b.err.Error() 75 } 76 77 func must(err error) { 78 if err != nil { 79 panic(compilerBug{err: err}) 80 } 81 }