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  }