1 /*
2 * parser.c, libyaml parser binding for Lua
3 * Written by Gary V. Vaughan, 2013
4 *
5 * Copyright (C) 2013-2022 Gary V. Vaughan
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include "lyaml.h"
27
28 typedef struct {
29 lua_State *L;
30 yaml_parser_t parser;
31 yaml_event_t event;
32 char validevent;
33 int document_count;
34 } lyaml_parser;
35
36
37 static void
parser_delete_event(lyaml_parser * parser)38 parser_delete_event (lyaml_parser *parser)
39 {
40 if (parser->validevent)
41 {
42 yaml_event_delete (&parser->event);
43 parser->validevent = 0;
44 }
45 }
46
47 /* With the event result table on the top of the stack, insert
48 a mark entry. */
49 static void
parser_set_mark(lua_State * L,const char * k,yaml_mark_t mark)50 parser_set_mark (lua_State *L, const char *k, yaml_mark_t mark)
51 {
52 lua_pushstring (L, k);
53 lua_createtable (L, 0, 3);
54 #define MENTRY(_s) RAWSET_INTEGER(#_s, mark._s)
55 MENTRY( index );
56 MENTRY( line );
57 MENTRY( column );
58 #undef MENTRY
59 lua_rawset (L, -3);
60 }
61
62 /* Push a new event table, pre-populated with shared elements. */
63 static void
parser_push_eventtable(lyaml_parser * parser,const char * v,int n)64 parser_push_eventtable (lyaml_parser *parser, const char *v, int n)
65 {
66 lua_State *L = parser->L;
67
68 lua_createtable (L, 0, n + 3);
69 RAWSET_STRING ("type", v);
70 #define MENTRY(_s) parser_set_mark (L, #_s, parser->event._s)
71 MENTRY( start_mark );
72 MENTRY( end_mark );
73 #undef MENTRY
74 }
75
76 static void
parse_STREAM_START(lyaml_parser * parser)77 parse_STREAM_START (lyaml_parser *parser)
78 {
79 #define EVENTF(_f) (parser->event.data.stream_start._f)
80 lua_State *L = parser->L;
81 const char *encoding;
82
83 switch (EVENTF (encoding))
84 {
85 #define MENTRY(_s) \
86 case YAML_##_s##_ENCODING: encoding = #_s; break
87
88 MENTRY( ANY );
89 MENTRY( UTF8 );
90 MENTRY( UTF16LE );
91 MENTRY( UTF16BE );
92 #undef MENTRY
93
94 default:
95 lua_pushfstring (L, "invalid encoding %d", EVENTF (encoding));
96 lua_error (L);
97 }
98
99 parser_push_eventtable (parser, "STREAM_START", 1);
100 RAWSET_STRING ("encoding", encoding);
101 #undef EVENTF
102 }
103
104 /* With the tag list on the top of the stack, append TAG. */
105 static void
parser_append_tag(lua_State * L,yaml_tag_directive_t tag)106 parser_append_tag (lua_State *L, yaml_tag_directive_t tag)
107 {
108 lua_createtable (L, 0, 2);
109 #define MENTRY(_s) RAWSET_STRING(#_s, tag._s)
110 MENTRY( handle );
111 MENTRY( prefix );
112 #undef MENTRY
113 lua_rawseti (L, -2, lua_objlen (L, -2) + 1);
114 }
115
116 static void
parse_DOCUMENT_START(lyaml_parser * parser)117 parse_DOCUMENT_START (lyaml_parser *parser)
118 {
119 #define EVENTF(_f) (parser->event.data.document_start._f)
120 lua_State *L = parser->L;
121
122 /* increment document count */
123 parser->document_count++;
124
125 parser_push_eventtable (parser, "DOCUMENT_START", 1);
126 RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
127
128 /* version_directive = { major = M, minor = N } */
129 if (EVENTF (version_directive))
130 {
131 lua_pushliteral (L, "version_directive");
132 lua_createtable (L, 0, 2);
133 #define MENTRY(_s) RAWSET_INTEGER(#_s, EVENTF (version_directive->_s))
134 MENTRY( major );
135 MENTRY( minor );
136 #undef MENTRY
137 lua_rawset (L, -3);
138 }
139
140 /* tag_directives = { {handle = H1, prefix = P1}, ... } */
141 if (EVENTF (tag_directives.start) &&
142 EVENTF (tag_directives.end)) {
143 yaml_tag_directive_t *cur;
144
145 lua_pushliteral (L, "tag_directives");
146 lua_newtable (L);
147 for (cur = EVENTF (tag_directives.start);
148 cur != EVENTF (tag_directives.end);
149 cur = cur + 1)
150 {
151 parser_append_tag (L, *cur);
152 }
153 lua_rawset (L, -3);
154 }
155 #undef EVENTF
156 }
157
158 static void
parse_DOCUMENT_END(lyaml_parser * parser)159 parse_DOCUMENT_END (lyaml_parser *parser)
160 {
161 #define EVENTF(_f) (parser->event.data.document_end._f)
162 lua_State *L = parser->L;
163
164 parser_push_eventtable (parser, "DOCUMENT_END", 1);
165 RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
166 #undef EVENTF
167 }
168
169 static void
parse_ALIAS(lyaml_parser * parser)170 parse_ALIAS (lyaml_parser *parser)
171 {
172 #define EVENTF(_f) (parser->event.data.alias._f)
173 lua_State *L = parser->L;
174
175 parser_push_eventtable (parser, "ALIAS", 1);
176 RAWSET_EVENTF (anchor);
177 #undef EVENTF
178 }
179
180 static void
parse_SCALAR(lyaml_parser * parser)181 parse_SCALAR (lyaml_parser *parser)
182 {
183 #define EVENTF(_f) (parser->event.data.scalar._f)
184 lua_State *L = parser->L;
185 const char *style;
186
187 switch (EVENTF (style))
188 {
189 #define MENTRY(_s) \
190 case YAML_##_s##_SCALAR_STYLE: style = #_s; break
191
192 MENTRY( ANY );
193 MENTRY( PLAIN );
194 MENTRY( SINGLE_QUOTED );
195 MENTRY( DOUBLE_QUOTED );
196 MENTRY( LITERAL );
197 MENTRY( FOLDED );
198 #undef MENTRY
199
200 default:
201 lua_pushfstring (L, "invalid sequence style %d", EVENTF (style));
202 lua_error (L);
203 }
204
205
206 parser_push_eventtable (parser, "SCALAR", 6);
207 RAWSET_EVENTF (anchor);
208 RAWSET_EVENTF (tag);
209 RAWSET_EVENTF (value);
210
211 RAWSET_BOOLEAN ("plain_implicit", EVENTF (plain_implicit));
212 RAWSET_BOOLEAN ("quoted_implicit", EVENTF (quoted_implicit));
213 RAWSET_STRING ("style", style);
214 #undef EVENTF
215 }
216
217 static void
parse_SEQUENCE_START(lyaml_parser * parser)218 parse_SEQUENCE_START (lyaml_parser *parser)
219 {
220 #define EVENTF(_f) (parser->event.data.sequence_start._f)
221 lua_State *L = parser->L;
222 const char *style;
223
224 switch (EVENTF (style))
225 {
226 #define MENTRY(_s) \
227 case YAML_##_s##_SEQUENCE_STYLE: style = #_s; break
228
229 MENTRY( ANY );
230 MENTRY( BLOCK );
231 MENTRY( FLOW );
232 #undef MENTRY
233
234 default:
235 lua_pushfstring (L, "invalid sequence style %d", EVENTF (style));
236 lua_error (L);
237 }
238
239 parser_push_eventtable (parser, "SEQUENCE_START", 4);
240 RAWSET_EVENTF (anchor);
241 RAWSET_EVENTF (tag);
242 RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
243 RAWSET_STRING ("style", style);
244 #undef EVENTF
245 }
246
247 static void
parse_MAPPING_START(lyaml_parser * parser)248 parse_MAPPING_START (lyaml_parser *parser)
249 {
250 #define EVENTF(_f) (parser->event.data.mapping_start._f)
251 lua_State *L = parser->L;
252 const char *style;
253
254 switch (EVENTF (style))
255 {
256 #define MENTRY(_s) \
257 case YAML_##_s##_MAPPING_STYLE: style = #_s; break
258
259 MENTRY( ANY );
260 MENTRY( BLOCK );
261 MENTRY( FLOW );
262 #undef MENTRY
263
264 default:
265 lua_pushfstring (L, "invalid mapping style %d", EVENTF (style));
266 lua_error (L);
267 }
268
269 parser_push_eventtable (parser, "MAPPING_START", 4);
270 RAWSET_EVENTF (anchor);
271 RAWSET_EVENTF (tag);
272 RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
273 RAWSET_STRING ("style", style);
274 #undef EVENTF
275 }
276
277 static void
parser_generate_error_message(lyaml_parser * parser)278 parser_generate_error_message (lyaml_parser *parser)
279 {
280 yaml_parser_t *P = &parser->parser;
281 char buf[256];
282 luaL_Buffer b;
283
284 luaL_buffinit (parser->L, &b);
285 luaL_addstring (&b, P->problem ? P->problem : "A problem");
286 snprintf (buf, sizeof (buf), " at document: %d", parser->document_count);
287 luaL_addstring (&b, buf);
288
289 if (P->problem_mark.line || P->problem_mark.column)
290 {
291 snprintf (buf, sizeof (buf), ", line: %lu, column: %lu",
292 (unsigned long) P->problem_mark.line + 1,
293 (unsigned long) P->problem_mark.column + 1);
294 luaL_addstring (&b, buf);
295 }
296 luaL_addstring (&b, "\n");
297
298 if (P->context)
299 {
300 snprintf (buf, sizeof (buf), "%s at line: %lu, column: %lu\n",
301 P->context,
302 (unsigned long) P->context_mark.line + 1,
303 (unsigned long) P->context_mark.column + 1);
304 luaL_addstring (&b, buf);
305 }
306
307 luaL_pushresult (&b);
308 }
309
310 static int
event_iter(lua_State * L)311 event_iter (lua_State *L)
312 {
313 lyaml_parser *parser = (lyaml_parser *)lua_touserdata(L, lua_upvalueindex(1));
314 char *str;
315
316 parser_delete_event (parser);
317 if (yaml_parser_parse (&parser->parser, &parser->event) != 1)
318 {
319 parser_generate_error_message (parser);
320 return lua_error (L);
321 }
322
323 parser->validevent = 1;
324
325 lua_newtable (L);
326 lua_pushliteral (L, "type");
327
328 switch (parser->event.type)
329 {
330 /* First the simple events, generated right here... */
331 #define MENTRY(_s) \
332 case YAML_##_s##_EVENT: parser_push_eventtable (parser, #_s, 0); break
333 MENTRY( STREAM_END );
334 MENTRY( SEQUENCE_END );
335 MENTRY( MAPPING_END );
336 #undef MENTRY
337
338 /* ...then the complex events, generated by a function call. */
339 #define MENTRY(_s) \
340 case YAML_##_s##_EVENT: parse_##_s (parser); break
341 MENTRY( STREAM_START );
342 MENTRY( DOCUMENT_START );
343 MENTRY( DOCUMENT_END );
344 MENTRY( ALIAS );
345 MENTRY( SCALAR );
346 MENTRY( SEQUENCE_START );
347 MENTRY( MAPPING_START );
348 #undef MENTRY
349
350 case YAML_NO_EVENT:
351 lua_pushnil (L);
352 break;
353 default:
354 lua_pushfstring (L, "invalid event %d", parser->event.type);
355 return lua_error (L);
356 }
357
358 return 1;
359 }
360
361 static int
parser_gc(lua_State * L)362 parser_gc (lua_State *L)
363 {
364 lyaml_parser *parser = (lyaml_parser *) lua_touserdata (L, 1);
365
366 if (parser)
367 {
368 parser_delete_event (parser);
369 yaml_parser_delete (&parser->parser);
370 }
371 return 0;
372 }
373
374 void
parser_init(lua_State * L)375 parser_init (lua_State *L)
376 {
377 luaL_newmetatable(L, "lyaml.parser");
378 lua_pushcfunction(L, parser_gc);
379 lua_setfield(L, -2, "__gc");
380 }
381
382 int
Pparser(lua_State * L)383 Pparser (lua_State *L)
384 {
385 lyaml_parser *parser;
386 const unsigned char *str;
387
388 /* requires a single string type argument */
389 luaL_argcheck (L, lua_isstring (L, 1), 1, "must provide a string argument");
390 str = (const unsigned char *) lua_tostring (L, 1);
391
392 /* create a user datum to store the parser */
393 parser = (lyaml_parser *) lua_newuserdata (L, sizeof (*parser));
394 memset ((void *) parser, 0, sizeof (*parser));
395 parser->L = L;
396
397 /* set its metatable */
398 luaL_getmetatable (L, "lyaml.parser");
399 lua_setmetatable (L, -2);
400
401 /* try to initialize the parser */
402 if (yaml_parser_initialize (&parser->parser) == 0)
403 luaL_error (L, "cannot initialize parser for %s", str);
404 yaml_parser_set_input_string (&parser->parser, str, lua_strlen (L, 1));
405
406 /* create and return the iterator function, with the loader userdatum as
407 its sole upvalue */
408 lua_pushcclosure (L, event_iter, 1);
409 return 1;
410 }
411