github.com/xrash/gopher-lua@v0.0.0-20160304065408-e5faab4db06a/cmd/glua/glua.go (about)

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