xref: /freebsd/contrib/lyaml/ext/yaml/parser.c (revision 2bc180ef045e5911cce0cea1c2a139cffd2b577a)
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