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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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