/
render.go
116 lines (100 loc) · 2.31 KB
/
render.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
package main
import (
"fmt"
"io"
"log"
"os"
"strings"
"text/template"
"github.com/spf13/pflag"
)
type parseGenData struct {
PackageName string
InterpFunc string
InterpFuncName string
OpCodeT string
InstructT string
FuncName string
NumCaptures int
Instructions []Inst
}
var packageName = pflag.String("package", "main", "package name for generated code")
var regexPattern = pflag.String("pattern", "", "regex to generate code for")
var funcName = pflag.String("func", "RegexMatch",
"function name for regex matching function")
var outFile = pflag.String("out", "", "output file for generated code")
const instruct = `
type Inst struct {
Op OpCode
Char rune
Label1 int64
Label2 int64
}`
const opcode = `
type OpCode uint
const (
Char OpCode = iota
Match
Jump
Split
Save
Nop
)`
var genTemplate = template.Must(template.New("matcher").Parse(`
package {{.PackageName}}
// Code autogenerated, don't touch
{{.OpCodeT}}
{{.InstructT}}
const NumCaptures = {{.NumCaptures}}
// {{.InterpFunc}}
func {{.FuncName}}(input string) (bool, []string) {
in := []Inst{ {{range .Instructions}}
Inst{ {{.Op}}, {{.Char}}, {{.Label1}}, {{.Label2}}},
{{end}} }
return {{.InterpFuncName}}(in, input)
}`))
func genMatcher(regex string, w io.Writer) error {
parser := new(regexParser)
if inst, err := parser.Parse(regex); err != nil {
return err
} else {
var thompson []byte
thompson, err = Asset("run_test.go")
if err != nil {
return err
}
tmp := strings.Split(string(thompson), "\n")
var vmSrc string
for i, str := range tmp {
if strings.Contains(str, "go:generate") {
vmSrc = strings.Join(tmp[i+1:], "\n")
break
}
}
captures := strings.Count(regex, "(") * 2
return genTemplate.Execute(w, parseGenData{
PackageName: *packageName,
InterpFunc: vmSrc,
InterpFuncName: "ThompsonVM",
OpCodeT: opcode,
InstructT: instruct,
FuncName: *funcName,
NumCaptures: captures,
Instructions: finalizeInst(inst.compile()),
})
}
}
func main() {
pflag.Parse()
if *outFile == "" {
*outFile = fmt.Sprintf("%s_regex", *funcName)
}
file, err := os.OpenFile(*outFile, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
file, err = os.Create(*outFile)
if err != nil {
log.Fatal(err)
}
}
genMatcher(*regexPattern, file)
}