github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/cmd/luaexec/luaexec.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/hirochachacha/plua/compiler"
    11  	"github.com/hirochachacha/plua/compiler/parser"
    12  	"github.com/hirochachacha/plua/object"
    13  	"github.com/hirochachacha/plua/position"
    14  	"github.com/hirochachacha/plua/runtime"
    15  	"github.com/hirochachacha/plua/stdlib"
    16  
    17  	isatty "github.com/mattn/go-isatty"
    18  )
    19  
    20  func main() {
    21  	flag.Usage = func() {
    22  		fmt.Fprintln(os.Stderr, "usage: luaexec [file]")
    23  		flag.PrintDefaults()
    24  	}
    25  
    26  	flag.Parse()
    27  
    28  	switch {
    29  	case len(os.Args) >= 2:
    30  		c := compiler.NewCompiler()
    31  
    32  		proto, err := c.CompileFile(os.Args[1], compiler.Either)
    33  		if err != nil {
    34  			object.PrintError(err)
    35  			os.Exit(1)
    36  		}
    37  
    38  		exec(proto)
    39  	case !isatty.IsTerminal(os.Stdin.Fd()):
    40  		c := compiler.NewCompiler()
    41  
    42  		proto, err := c.Compile(os.Stdin, "=stdin", compiler.Either)
    43  		if err != nil {
    44  			object.PrintError(err)
    45  			os.Exit(1)
    46  		}
    47  
    48  		exec(proto)
    49  	default:
    50  		interact()
    51  	}
    52  
    53  }
    54  
    55  func exec(proto *object.Proto) {
    56  	p := runtime.NewProcess()
    57  
    58  	var a object.Table
    59  
    60  	if len(os.Args) >= 2 {
    61  		a = p.NewTableSize(len(os.Args)-2, 2)
    62  		for i, arg := range os.Args {
    63  			a.Set(object.Integer(i-1), object.String(arg))
    64  		}
    65  	} else {
    66  		a = p.NewTableSize(0, 1)
    67  		a.Set(object.Integer(0), object.String(os.Args[0]))
    68  	}
    69  
    70  	p.Globals().Set(object.String("arg"), a)
    71  
    72  	p.Require("", stdlib.Open)
    73  
    74  	_, err := p.Exec(proto)
    75  	if err != nil {
    76  		object.PrintError(err)
    77  		os.Exit(1)
    78  	}
    79  }
    80  
    81  func eof(s string) position.Position {
    82  	line := 0
    83  	column := 0
    84  	for _, r := range s {
    85  		if r == '\n' {
    86  			line++
    87  			column = 0
    88  		} else {
    89  			column++
    90  		}
    91  	}
    92  	line++
    93  	column++
    94  	return position.Position{Line: line, Column: column}
    95  }
    96  
    97  func isIncomplete(code string, err error) bool {
    98  	if err, ok := err.(*parser.Error); ok {
    99  		eof := eof(code)
   100  		return err.Pos.Line == eof.Line && err.Pos.Column == eof.Column
   101  	}
   102  
   103  	return false
   104  }
   105  
   106  func interact() {
   107  	c := compiler.NewCompiler()
   108  
   109  	p := runtime.NewProcess()
   110  
   111  	p.Require("", stdlib.Open)
   112  
   113  	stdin := bufio.NewScanner(os.Stdin)
   114  
   115  	var code string
   116  
   117  	for {
   118  		var err error
   119  
   120  		if len(code) != 0 {
   121  			_, err = fmt.Fprint(os.Stdout, ">> ")
   122  		} else {
   123  			_, err = fmt.Fprint(os.Stdout, "> ")
   124  		}
   125  
   126  		if err != nil {
   127  			panic(err)
   128  		}
   129  
   130  		if !stdin.Scan() {
   131  			if err := stdin.Err(); err != nil {
   132  				panic(err)
   133  			}
   134  
   135  			return
   136  		}
   137  
   138  		line := stdin.Text()
   139  		var proto *object.Proto
   140  
   141  		if len(code) == 0 {
   142  			if line == "exit" {
   143  				return
   144  			}
   145  
   146  			code = "return " + line
   147  
   148  			proto, err = c.Compile(strings.NewReader(code), "=stdin", compiler.Text)
   149  			if err != nil {
   150  				code = line
   151  
   152  				proto, err = c.Compile(strings.NewReader(code), "=stdin", compiler.Text)
   153  			}
   154  		} else {
   155  			code += "\n" + line
   156  
   157  			proto, err = c.Compile(strings.NewReader(code), "=stdin", compiler.Text)
   158  		}
   159  
   160  		if err != nil {
   161  			if isIncomplete(code, err) {
   162  				continue
   163  			}
   164  
   165  			code = ""
   166  
   167  			object.PrintError(err)
   168  
   169  			continue
   170  		}
   171  
   172  		code = ""
   173  
   174  		rets, err := p.Exec(proto)
   175  		if err != nil {
   176  			object.PrintError(err)
   177  		} else {
   178  			if len(rets) > 0 {
   179  				fmt.Fprintln(os.Stdout, object.Repr(rets[0]))
   180  			}
   181  		}
   182  
   183  		p = p.Fork()
   184  	}
   185  }