forked from jfourkiotis/golox
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgolox.go
95 lines (88 loc) · 2.29 KB
/
golox.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package main
import (
"bufio"
"flag"
"fmt"
"github.com/jfourkiotis/golox/ast"
"github.com/jfourkiotis/golox/env"
"github.com/jfourkiotis/golox/interpreter"
"github.com/jfourkiotis/golox/parseerror"
"github.com/jfourkiotis/golox/parser"
"github.com/jfourkiotis/golox/runtimeerror"
"github.com/jfourkiotis/golox/scanner"
"github.com/jfourkiotis/golox/semantic"
"github.com/jfourkiotis/golox/semanticerror"
"io/ioutil"
"os"
)
func check(err error) {
if err != nil {
panic(err)
}
}
func runFile(file string) {
dat, err := ioutil.ReadFile(file)
check(err)
run(string(dat), interpreter.GlobalEnv)
if parseerror.HadError {
os.Exit(65)
} else if runtimeerror.HadError || semanticerror.HadError {
os.Exit(70)
}
}
func runPrompt() {
reader := bufio.NewReader(os.Stdin)
env := interpreter.GlobalEnv
for {
fmt.Print("> ")
dat, err := reader.ReadBytes('\n') // there is also ReadString
check(err)
run(string(dat), env)
parseerror.HadError = false
runtimeerror.HadError = false
semanticerror.HadError = false
}
}
func run(src string, env *env.Environment) {
scanner := scanner.New(src)
tokens := scanner.ScanTokens()
parser := parser.New(tokens)
statements := parser.Parse()
if parseerror.HadError {
return
}
resolution, err := semantic.Resolve(statements)
if err != nil || semanticerror.HadError {
semanticerror.Print(err.Error())
return
} else if len(resolution.Unused) != 0 {
for stmt := range resolution.Unused {
switch n := stmt.(type) {
case *ast.Var:
fmt.Fprintf(os.Stdout, "Unused variable %q [Line: %d]\n", n.Name.Lexeme, n.Name.Line)
case *ast.Function:
fmt.Fprintf(os.Stdout, "Unused function %q [Line: %d]\n", n.Name.Lexeme, n.Name.Line)
case *ast.Class:
fmt.Fprintf(os.Stdout, "Unused class %q [Line: %d]\n", n.Name.Lexeme, n.Name.Line)
default:
panic(fmt.Sprintf("Unexpected ast.Node type %T\n", stmt))
}
}
err = semanticerror.Make(fmt.Sprintf("%d unused local variables/functions found", len(resolution.Unused)))
return
}
interpreter.Interpret(statements, env, resolution)
}
func main() {
flag.String("file", "", "the script file to execute")
flag.Parse()
args := flag.Args()
if len(args) > 1 {
fmt.Println("Usage: ./golox [script]")
os.Exit(64)
} else if len(args) == 1 {
runFile(args[0])
} else {
runPrompt()
}
}