-
-
Notifications
You must be signed in to change notification settings - Fork 23
/
parse.go
149 lines (140 loc) · 3.28 KB
/
parse.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package cxgo
import (
"bytes"
"fmt"
"path/filepath"
"strconv"
"strings"
"github.com/gotranspile/cxgo/libs"
"github.com/gotranspile/cxgo/libs/libcc"
"modernc.org/cc/v3"
)
type SourceConfig struct {
Predef string
Define []Define
Include []string
SysInclude []string
IgnoreIncludeDir bool
}
func Parse(c *libs.Env, root, fname string, sconf SourceConfig) (*cc.AST, error) {
path := filepath.Dir(fname)
if root == "" {
root = path
}
srcs := []cc.Source{{Name: fname}}
if sconf.Predef != "" {
srcs = []cc.Source{
{Name: "predef.h", Value: sconf.Predef}, // FIXME: this should preappend to the file content instead
{Name: fname},
}
}
var (
inc []string
sys []string
)
inc = append(inc, sconf.Include...)
sys = append(sys, sconf.SysInclude...)
if !sconf.IgnoreIncludeDir {
inc = append(inc,
filepath.Join(root, "includes"),
filepath.Join(root, "include"),
)
sys = append(sys, []string{
filepath.Join(root, "includes"),
filepath.Join(root, "include"),
}...)
}
inc = append(inc,
path,
"@",
)
return ParseSource(c, ParseConfig{
Sources: srcs,
WorkDir: path,
Includes: inc,
SysIncludes: sys,
Predefines: true,
Define: sconf.Define,
})
}
func addIncludeOverridePath(inc []string) []string {
return append(inc[:len(inc):len(inc)], libs.IncludePath)
}
var (
tokLBrace = cc.String("(")
tokRBrace = cc.String(")")
)
type Define struct {
Name string `yaml:"name" json:"name"`
Value string `yaml:"value" json:"value"`
}
type ParseConfig struct {
WorkDir string
Includes []string
SysIncludes []string
Predefines bool
Define []Define
Sources []cc.Source
}
func ParseSource(env *libs.Env, c ParseConfig) (*cc.AST, error) {
var srcs []cc.Source
if len(c.Define) != 0 {
var buf bytes.Buffer
for _, d := range c.Define {
buf.WriteString("#define ")
buf.WriteString(strings.TrimSpace(d.Name))
if d.Value != "" {
buf.WriteByte(' ')
buf.WriteString(strings.TrimSpace(d.Value))
}
buf.WriteByte('\n')
}
srcs = append(srcs, cc.Source{Name: "cxgo_config_defines.h", Value: buf.String()})
}
if c.Predefines {
srcs = append(srcs, cc.Source{Name: "cxgo_predef.h", Value: fmt.Sprintf(gccPredefine, "int")})
}
srcs = append(srcs, c.Sources...)
includes := addIncludeOverridePath(c.Includes)
sysIncludes := addIncludeOverridePath(c.SysIncludes)
return cc.Translate(&cc.Config{
Config3: cc.Config3{
WorkingDir: c.WorkDir,
Filesystem: cc.Overlay(cc.LocalFS(), newIncludeFS(env)),
},
ABI: libcc.NewABI(env.Env),
PragmaHandler: func(p cc.Pragma, toks []cc.Token) {
if len(toks) == 0 {
return
}
name := toks[0].Value.String()
toks = toks[1:]
switch name {
case "push_macro":
if len(toks) != 3 {
return
} else if toks[0].Value != tokLBrace || toks[2].Value != tokRBrace {
return
}
def := toks[1].Value.String()
def, err := strconv.Unquote(def)
if err != nil {
return
}
p.PushMacro(def)
case "pop_macro":
if len(toks) != 3 {
return
} else if toks[0].Value != tokLBrace || toks[2].Value != tokRBrace {
return
}
def := toks[1].Value.String()
def, err := strconv.Unquote(def)
if err != nil {
return
}
p.PopMacro(def)
}
},
}, includes, sysIncludes, srcs)
}