-
Notifications
You must be signed in to change notification settings - Fork 6
/
tau.go
130 lines (107 loc) · 2.48 KB
/
tau.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package tau
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"github.com/NicoNex/tau/internal/ast"
"github.com/NicoNex/tau/internal/compiler"
"github.com/NicoNex/tau/internal/parser"
"github.com/NicoNex/tau/internal/vm"
)
const TauVersion = "v2.0.15"
var ErrParseError = errors.New("error: parse error")
func readFile(fname string) []byte {
b, err := os.ReadFile(fname)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
return b
}
func writeFile(fname string, cont []byte) {
if err := os.WriteFile(fname, cont, 0644); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func precompiledBytecode(path string) (compiler.Bytecode, error) {
b, err := os.ReadFile(path)
if err != nil {
fmt.Println(err)
return compiler.Bytecode{}, fmt.Errorf("error opening file %q: %w", path, err)
}
return compiler.DecodeBytecode(b), nil
}
func compile(path string) (bc compiler.Bytecode, err error) {
input := string(readFile(path))
res, errs := parser.Parse(path, input)
if len(errs) > 0 {
var buf strings.Builder
for _, e := range errs {
buf.WriteString(e.Error())
buf.WriteByte('\n')
}
return compiler.Bytecode{}, errors.New(buf.String())
}
c := compiler.New()
c.SetFileInfo(path, input)
if err = c.Compile(res); err != nil {
return
}
return c.Bytecode(), nil
}
func ExecFileVM(f string) (err error) {
var bytecode compiler.Bytecode
if filepath.Ext(f) == ".tauc" {
bytecode = compiler.DecodeBytecode(readFile(f))
} else {
if bytecode, err = compile(f); err != nil {
fmt.Println(err)
return
}
}
tvm := vm.New(f, bytecode)
tvm.Run()
return nil
}
func CompileFiles(files []string) error {
for _, f := range files {
b := readFile(f)
res, errs := parser.Parse(f, string(b))
if len(errs) != 0 {
for _, e := range errs {
fmt.Println(e)
}
return ErrParseError
}
c := compiler.New()
c.SetFileInfo(f, string(b))
if err := c.Compile(res); err != nil {
fmt.Println(err)
continue
}
ext := filepath.Ext(f)
writeFile(f[:len(f)-len(ext)]+".tauc", c.Bytecode().Encode())
}
return nil
}
func PrintVersionInfo(w io.Writer) {
fmt.Fprintf(w, "Tau %s on %s\n", TauVersion, strings.Title(runtime.GOOS))
}
func Parse(src string) (ast.Node, error) {
tree, errs := parser.Parse("<input>", src)
if len(errs) > 0 {
var buf strings.Builder
buf.WriteString("parser error:\n")
for _, e := range errs {
buf.WriteString(e.Error())
buf.WriteByte('\n')
}
return nil, errors.New(buf.String())
}
return tree, nil
}