github.com/jslyzt/glua@v0.0.0-20210819023911-4030c8e0234a/cmd/glua/glua.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "runtime/pprof" 8 9 "github.com/chzyer/readline" 10 lua "github.com/jslyzt/glua" 11 "github.com/jslyzt/glua/parse" 12 ) 13 14 func main() { 15 os.Exit(mainAux()) 16 } 17 18 func mainAux() int { 19 var ( 20 opte, optl, optp string 21 opti, optv, optdt, optdc bool 22 optm int 23 ) 24 25 flag.StringVar(&opte, "e", "", "") 26 flag.StringVar(&optl, "l", "", "") 27 flag.StringVar(&optp, "p", "", "") 28 flag.IntVar(&optm, "mx", 0, "") 29 flag.BoolVar(&opti, "i", false, "") 30 flag.BoolVar(&optv, "v", false, "") 31 flag.BoolVar(&optdt, "dt", false, "") 32 flag.BoolVar(&optdc, "dc", false, "") 33 flag.Usage = func() { 34 fmt.Println(`Usage: glua [options] [script [args]]. 35 Available options are: 36 -e stat execute string 'stat' 37 -l name require library 'name' 38 -mx MB memory limit(default: unlimited) 39 -dt dump AST trees 40 -dc dump VM codes 41 -i enter interactive mode after executing 'script' 42 -p file write cpu profiles to the file 43 -v show version information`) 44 } 45 flag.Parse() 46 if len(optp) != 0 { 47 f, err := os.Create(optp) 48 if err != nil { 49 fmt.Println(err.Error()) 50 os.Exit(1) 51 } 52 pprof.StartCPUProfile(f) 53 defer pprof.StopCPUProfile() 54 } 55 if len(opte) == 0 && !opti && !optv && flag.NArg() == 0 { 56 opti = true 57 } 58 59 status := 0 60 61 L := lua.NewState() 62 defer L.Close() 63 if optm > 0 { 64 L.SetMx(optm) 65 } 66 67 if optv || opti { 68 fmt.Println(lua.PackageCopyRight) 69 } 70 71 if len(optl) > 0 { 72 if err := L.DoFile(optl); err != nil { 73 fmt.Println(err.Error()) 74 } 75 } 76 77 if nargs := flag.NArg(); nargs > 0 { 78 script := flag.Arg(0) 79 argtb := L.NewTable() 80 for i := 1; i < nargs; i++ { 81 L.RawSet(argtb, lua.LNumber(i), lua.LString(flag.Arg(i))) 82 } 83 L.SetGlobal("arg", argtb) 84 if optdt || optdc { 85 file, err := os.Open(script) 86 if err != nil { 87 fmt.Println(err.Error()) 88 return 1 89 } 90 chunk, err2 := parse.Parse(file, script) 91 if err2 != nil { 92 fmt.Println(err2.Error()) 93 return 1 94 } 95 if optdt { 96 fmt.Println(parse.Dump(chunk)) 97 } 98 if optdc { 99 proto, err3 := lua.Compile(chunk, script) 100 if err3 != nil { 101 fmt.Println(err3.Error()) 102 return 1 103 } 104 fmt.Println(proto.String()) 105 } 106 } 107 if err := L.DoFile(script); err != nil { 108 fmt.Println(err.Error()) 109 status = 1 110 } 111 } 112 113 if len(opte) > 0 { 114 if err := L.DoString(opte); err != nil { 115 fmt.Println(err.Error()) 116 status = 1 117 } 118 } 119 120 if opti { 121 doREPL(L) 122 } 123 return status 124 } 125 126 // do read/eval/print/loop 127 func doREPL(L *lua.LState) { 128 rl, err := readline.New("> ") 129 if err != nil { 130 panic(err) 131 } 132 defer rl.Close() 133 for { 134 if str, err := loadline(rl, L); err == nil { 135 if err := L.DoString(str); err != nil { 136 fmt.Println(err) 137 } 138 } else { // error on loadline 139 fmt.Println(err) 140 return 141 } 142 } 143 } 144 145 func incomplete(err error) bool { 146 if lerr, ok := err.(*lua.APIError); ok { 147 if perr, ok := lerr.Cause.(*parse.Error); ok { 148 return perr.Pos.Line == parse.EOF 149 } 150 } 151 return false 152 } 153 154 func loadline(rl *readline.Instance, L *lua.LState) (string, error) { 155 rl.SetPrompt("> ") 156 line, err := rl.Readline() 157 if err == nil { 158 if _, err := L.LoadString("return " + line); err == nil { // try add return <...> then compile 159 return line, nil 160 } 161 return multiline(line, rl, L) 162 } 163 return "", err 164 } 165 166 func multiline(ml string, rl *readline.Instance, L *lua.LState) (string, error) { 167 for { 168 if _, err := L.LoadString(ml); err == nil { // try compile 169 return ml, nil 170 } else if !incomplete(err) { // syntax error , but not EOF 171 return ml, nil 172 } else { 173 rl.SetPrompt(">> ") 174 if line, err := rl.Readline(); err == nil { 175 ml = ml + "\n" + line 176 } else { 177 return "", err 178 } 179 } 180 } 181 }