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 }