-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
parser.go
227 lines (207 loc) · 6.55 KB
/
parser.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
package zetasql
import "C"
import (
"unsafe"
"github.com/goccy/go-zetasql/ast"
internal "github.com/goccy/go-zetasql/internal/ccall/go-zetasql"
"github.com/goccy/go-zetasql/internal/helper"
)
type ParserOptions struct {
raw unsafe.Pointer
}
func NewParserOptions() *ParserOptions {
var v unsafe.Pointer
internal.ParserOptions_new(&v)
return newParserOptions(v)
}
func newParserOptions(v unsafe.Pointer) *ParserOptions {
if v == nil {
return nil
}
return &ParserOptions{raw: v}
}
func (o *ParserOptions) getRaw() unsafe.Pointer {
if o == nil {
return nil
}
return o.raw
}
func (o *ParserOptions) SetLanguageOptions(opt *LanguageOptions) {
internal.ParserOptions_set_language_options(o.raw, opt.raw)
}
func (o *ParserOptions) LanguageOptions() *LanguageOptions {
var v unsafe.Pointer
internal.ParserOptions_language_options(o.raw, &v)
return newLanguageOptions(v)
}
type parserOutput struct {
raw unsafe.Pointer
}
func (o *parserOutput) stmt() (ast.StatementNode, error) {
var stmt unsafe.Pointer
internal.ParserOutput_statement(o.raw, &stmt)
node, ok := newNode(stmt).(ast.StatementNode)
if !ok {
return nil, ErrParseStatement
}
return node, nil
}
func (o *parserOutput) script() (ast.ScriptNode, error) {
var script unsafe.Pointer
internal.ParserOutput_script(o.raw, &script)
node, ok := newNode(script).(ast.ScriptNode)
if !ok {
return nil, ErrParseScript
}
return node, nil
}
func (o *parserOutput) typ() (ast.TypeNode, error) {
var typ unsafe.Pointer
internal.ParserOutput_type(o.raw, &typ)
node, ok := newNode(typ).(ast.TypeNode)
if !ok {
return nil, ErrParseType
}
return node, nil
}
func (o *parserOutput) expr() (ast.ExpressionNode, error) {
var expr unsafe.Pointer
internal.ParserOutput_expression(o.raw, &expr)
node, ok := newNode(expr).(ast.ExpressionNode)
if !ok {
return nil, ErrParseExpression
}
return node, nil
}
// ParseStatement parses <statement_string> and returns the statement node upon success.
//
// A semi-colon following the statement is optional.
//
// Script statements are not supported.
//
// This can return errors annotated with an ErrorLocation payload that indicates
// the input location of an error.
func ParseStatement(stmt string, opt *ParserOptions) (ast.StatementNode, error) {
var (
out unsafe.Pointer
status unsafe.Pointer
)
internal.ParseStatement(unsafe.Pointer(C.CString(stmt)), opt.getRaw(), &out, &status)
st := helper.NewStatus(status)
if !st.OK() {
return nil, st.Error()
}
parserOut := &parserOutput{raw: out}
return parserOut.stmt()
}
// ParseScript parses <script_string> and returns the script node upon success.
//
// A terminating semi-colon is optional for the last statement in the script,
// and mandatory for all other statements.
//
// <error_message_mode> describes how errors should be represented.
func ParseScript(script string, opt *ParserOptions, mode ErrorMessageMode) (ast.ScriptNode, error) {
var (
out unsafe.Pointer
status unsafe.Pointer
)
internal.ParseScript(unsafe.Pointer(C.CString(script)), opt.getRaw(), int(mode), &out, &status)
st := helper.NewStatus(status)
if !st.OK() {
return nil, st.Error()
}
parserOut := &parserOutput{raw: out}
return parserOut.script()
}
// ParseType parses <type_string> as a type name and returns the type node upon success.
//
// This can return errors annotated with an ErrorLocation payload that indicates
// the input location of an error.
func ParseType(typ string, opt *ParserOptions) (ast.TypeNode, error) {
var (
out unsafe.Pointer
status unsafe.Pointer
)
internal.ParseType(unsafe.Pointer(C.CString(typ)), opt.getRaw(), &out, &status)
st := helper.NewStatus(status)
if !st.OK() {
return nil, st.Error()
}
parserOut := &parserOutput{raw: out}
return parserOut.typ()
}
// ParseExpression parses <expression_string> as an expression and returns the expression node upon success.
//
// This can return errors annotated with an ErrorLocation payload that indicates
// the input location of an error.
func ParseExpression(expr string, opt *ParserOptions) (ast.ExpressionNode, error) {
var (
out unsafe.Pointer
status unsafe.Pointer
)
internal.ParseExpression(unsafe.Pointer(C.CString(expr)), opt.getRaw(), &out, &status)
st := helper.NewStatus(status)
if !st.OK() {
return nil, st.Error()
}
parserOut := &parserOutput{raw: out}
return parserOut.expr()
}
// ParseNextStatement parses one statement from a string that may contain multiple statements.
// This can be called in a loop with the same <resume_location> to parse all statements from a string.
//
// Returns the statement node upon success. The second return value will be true if parsing reached
// the end of the string.
//
// Statements are separated by semicolons. A final semicolon is not required
// on the last statement. If only whitespace and comments follow the
// semicolon, The second return value will be set to true. Otherwise, it will be set
// to false. Script statements are not supported.
//
// After a parse error, <resume_location> is not updated and parsing further
// statements is not supported.
//
// This can return errors annotated with an ErrorLocation payload that indicates
// the input location of an error.
func ParseNextStatement(loc *ParseResumeLocation, opt *ParserOptions) (ast.StatementNode, bool, error) {
var (
out unsafe.Pointer
isEnd bool
status unsafe.Pointer
)
internal.ParseNextStatement(loc.raw, opt.getRaw(), &out, &isEnd, &status)
st := helper.NewStatus(status)
if !st.OK() {
return nil, isEnd, st.Error()
}
parserOut := &parserOutput{raw: out}
stmt, err := parserOut.stmt()
return stmt, isEnd, err
}
// ParseNextScriptStatement similar to the ParseNextStatement function,
// but allows statements specific to scripting, in addition to SQL statements.
// Entire constructs such as IF...END IF,
// WHILE...END WHILE, and BEGIN...END are returned as a single statement, and
// may contain inner statements, which can be examined through the returned parse tree.
func ParseNextScriptStatement(loc *ParseResumeLocation, opt *ParserOptions) (ast.StatementNode, bool, error) {
var (
out unsafe.Pointer
isEnd bool
status unsafe.Pointer
)
internal.ParseNextScriptStatement(loc.raw, opt.getRaw(), &out, &isEnd, &status)
st := helper.NewStatus(status)
if !st.OK() {
return nil, isEnd, st.Error()
}
parserOut := &parserOutput{raw: out}
stmt, err := parserOut.stmt()
return stmt, isEnd, err
}
// Unparse a given AST back to a canonical SQL string and return it.
// Works for any AST node.
func Unparse(node ast.Node) string {
var v unsafe.Pointer
internal.Unparse(getNodeRaw(node), &v)
return C.GoString((*C.char)(v))
}