1 /*
2 * scanner.c, libyaml scanner 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
29 typedef struct {
30 lua_State *L;
31 yaml_parser_t parser;
32 yaml_token_t token;
33 char validtoken;
34 int document_count;
35 } lyaml_scanner;
36
37
38 static void
scanner_delete_token(lyaml_scanner * scanner)39 scanner_delete_token (lyaml_scanner *scanner)
40 {
41 if (scanner->validtoken)
42 {
43 yaml_token_delete (&scanner->token);
44 scanner->validtoken = 0;
45 }
46 }
47
48 /* With the token result table on the top of the stack, insert
49 a mark entry. */
50 static void
scanner_set_mark(lua_State * L,const char * k,yaml_mark_t mark)51 scanner_set_mark (lua_State *L, const char *k, yaml_mark_t mark)
52 {
53 lua_pushstring (L, k);
54 lua_createtable (L, 0, 3);
55 #define MENTRY(_s) RAWSET_INTEGER (#_s, mark._s)
56 MENTRY( index );
57 MENTRY( line );
58 MENTRY( column );
59 #undef MENTRY
60 lua_rawset (L, -3);
61 }
62
63 /* Push a new token table, pre-populated with shared elements. */
64 static void
scanner_push_tokentable(lyaml_scanner * scanner,const char * v,int n)65 scanner_push_tokentable (lyaml_scanner *scanner, const char *v, int n)
66 {
67 lua_State *L = scanner->L;
68
69 lua_createtable (L, 0, n + 3);
70 RAWSET_STRING ("type", v);
71
72 #define MENTRY(_s) scanner_set_mark (L, #_s, scanner->token._s)
73 MENTRY( start_mark );
74 MENTRY( end_mark );
75 #undef MENTRY
76 }
77
78 static void
scan_STREAM_START(lyaml_scanner * scanner)79 scan_STREAM_START (lyaml_scanner *scanner)
80 {
81 #define EVENTF(_f) (scanner->token.data.stream_start._f)
82 lua_State *L = scanner->L;
83 const char *encoding;
84
85 switch (EVENTF (encoding))
86 {
87 #define MENTRY(_s) \
88 case YAML_##_s##_ENCODING: encoding = #_s; break
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 scanner_push_tokentable (scanner, "STREAM_START", 1);
100 RAWSET_STRING ("encoding", encoding);
101 #undef EVENTF
102 }
103
104 static void
scan_VERSION_DIRECTIVE(lyaml_scanner * scanner)105 scan_VERSION_DIRECTIVE (lyaml_scanner *scanner)
106 {
107 #define EVENTF(_f) (scanner->token.data.version_directive._f)
108 lua_State *L = scanner->L;
109
110 scanner_push_tokentable (scanner, "VERSION_DIRECTIVE", 2);
111
112 #define MENTRY(_s) RAWSET_INTEGER (#_s, EVENTF (_s))
113 MENTRY( major );
114 MENTRY( minor );
115 #undef MENTRY
116 #undef EVENTF
117 }
118
119 static void
scan_TAG_DIRECTIVE(lyaml_scanner * scanner)120 scan_TAG_DIRECTIVE (lyaml_scanner *scanner)
121 {
122 #define EVENTF(_f) (scanner->token.data.tag_directive._f)
123 lua_State *L = scanner->L;
124
125 scanner_push_tokentable (scanner, "TAG_DIRECTIVE", 2);
126 RAWSET_EVENTF( handle );
127 RAWSET_EVENTF( prefix );
128 #undef EVENTF
129 }
130
131 static void
scan_ALIAS(lyaml_scanner * scanner)132 scan_ALIAS (lyaml_scanner *scanner)
133 {
134 #define EVENTF(_f) (scanner->token.data.alias._f)
135 lua_State *L = scanner->L;
136
137 scanner_push_tokentable (scanner, "ALIAS", 1);
138 RAWSET_EVENTF (value);
139 #undef EVENTF
140 }
141
142 static void
scan_ANCHOR(lyaml_scanner * scanner)143 scan_ANCHOR (lyaml_scanner *scanner)
144 {
145 #define EVENTF(_f) (scanner->token.data.anchor._f)
146 lua_State *L = scanner->L;
147
148 scanner_push_tokentable (scanner, "ANCHOR", 1);
149 RAWSET_EVENTF (value);
150 #undef EVENTF
151 }
152
153 static void
scan_TAG(lyaml_scanner * scanner)154 scan_TAG(lyaml_scanner *scanner)
155 {
156 #define EVENTF(_f) (scanner->token.data.tag._f)
157 lua_State *L = scanner->L;
158
159 scanner_push_tokentable (scanner, "TAG", 2);
160 RAWSET_EVENTF( handle );
161 RAWSET_EVENTF( suffix );
162 #undef EVENTF
163 }
164
165 static void
scan_SCALAR(lyaml_scanner * scanner)166 scan_SCALAR (lyaml_scanner *scanner)
167 {
168 #define EVENTF(_f) (scanner->token.data.scalar._f)
169 lua_State *L = scanner->L;
170 const char *style;
171
172 switch (EVENTF (style))
173 {
174 #define MENTRY(_s) \
175 case YAML_##_s##_SCALAR_STYLE: style = #_s; break
176
177 MENTRY( PLAIN );
178 MENTRY( SINGLE_QUOTED );
179 MENTRY( DOUBLE_QUOTED );
180 MENTRY( LITERAL );
181 MENTRY( FOLDED );
182 #undef MENTRY
183
184 default:
185 lua_pushfstring (L, "invalid scalar style %d", EVENTF (style));
186 lua_error (L);
187 }
188
189 scanner_push_tokentable (scanner, "SCALAR", 3);
190 RAWSET_EVENTF (value);
191 RAWSET_INTEGER ("length", EVENTF (length));
192 RAWSET_STRING ("style", style);
193 #undef EVENTF
194 }
195
196 static void
scanner_generate_error_message(lyaml_scanner * scanner)197 scanner_generate_error_message (lyaml_scanner *scanner)
198 {
199 yaml_parser_t *P = &scanner->parser;
200 char buf[256];
201 luaL_Buffer b;
202
203 luaL_buffinit (scanner->L, &b);
204 luaL_addstring (&b, P->problem ? P->problem : "A problem");
205 snprintf (buf, sizeof (buf), " at document: %d", scanner->document_count);
206 luaL_addstring (&b, buf);
207
208 if (P->problem_mark.line || P->problem_mark.column)
209 {
210 snprintf (buf, sizeof (buf), ", line: %lu, column: %lu",
211 (unsigned long) P->problem_mark.line + 1,
212 (unsigned long) P->problem_mark.column + 1);
213 luaL_addstring (&b, buf);
214 }
215 luaL_addstring (&b, "\n");
216
217 if (P->context)
218 {
219 snprintf (buf, sizeof (buf), "%s at line: %lu, column: %lu\n",
220 P->context,
221 (unsigned long) P->context_mark.line + 1,
222 (unsigned long) P->context_mark.column + 1);
223 luaL_addstring (&b, buf);
224 }
225
226 luaL_pushresult (&b);
227 }
228
229 static int
token_iter(lua_State * L)230 token_iter (lua_State *L)
231 {
232 lyaml_scanner *scanner = (lyaml_scanner *)lua_touserdata(L, lua_upvalueindex(1));
233 char *str;
234
235 scanner_delete_token (scanner);
236 if (yaml_parser_scan (&scanner->parser, &scanner->token) != 1)
237 {
238 scanner_generate_error_message (scanner);
239 return lua_error (L);
240 }
241
242 scanner->validtoken = 1;
243
244 lua_newtable (L);
245 lua_pushliteral (L, "type");
246
247 switch (scanner->token.type)
248 {
249 /* First the simple tokens, generated right here... */
250 #define MENTRY(_s) \
251 case YAML_##_s##_TOKEN: scanner_push_tokentable (scanner, #_s, 0); break
252 MENTRY( STREAM_END );
253 MENTRY( DOCUMENT_START );
254 MENTRY( DOCUMENT_END );
255 MENTRY( BLOCK_SEQUENCE_START );
256 MENTRY( BLOCK_MAPPING_START );
257 MENTRY( BLOCK_END );
258 MENTRY( FLOW_SEQUENCE_START );
259 MENTRY( FLOW_SEQUENCE_END );
260 MENTRY( FLOW_MAPPING_START );
261 MENTRY( FLOW_MAPPING_END );
262 MENTRY( BLOCK_ENTRY );
263 MENTRY( FLOW_ENTRY );
264 MENTRY( KEY );
265 MENTRY( VALUE );
266 #undef MENTRY
267
268 /* ...then the complex tokens, generated by a function call. */
269 #define MENTRY(_s) \
270 case YAML_##_s##_TOKEN: scan_##_s (scanner); break
271 MENTRY( STREAM_START );
272 MENTRY( VERSION_DIRECTIVE );
273 MENTRY( TAG_DIRECTIVE );
274 MENTRY( ALIAS );
275 MENTRY( ANCHOR );
276 MENTRY( TAG );
277 MENTRY( SCALAR );
278 #undef MENTRY
279
280 case YAML_NO_TOKEN:
281 lua_pushnil (L);
282 break;
283 default:
284 lua_pushfstring (L, "invalid token %d", scanner->token.type);
285 return lua_error (L);
286 }
287
288 return 1;
289 }
290
291 static int
scanner_gc(lua_State * L)292 scanner_gc (lua_State *L)
293 {
294 lyaml_scanner *scanner = (lyaml_scanner *) lua_touserdata (L, 1);
295
296 if (scanner)
297 {
298 scanner_delete_token (scanner);
299 yaml_parser_delete (&scanner->parser);
300 }
301 return 0;
302 }
303
304 void
scanner_init(lua_State * L)305 scanner_init (lua_State *L)
306 {
307 luaL_newmetatable (L, "lyaml.scanner");
308 lua_pushcfunction (L, scanner_gc);
309 lua_setfield (L, -2, "__gc");
310 }
311
312 int
Pscanner(lua_State * L)313 Pscanner (lua_State *L)
314 {
315 lyaml_scanner *scanner;
316 const unsigned char *str;
317
318 /* requires a single string type argument */
319 luaL_argcheck (L, lua_isstring (L, 1), 1, "must provide a string argument");
320 str = (const unsigned char *) lua_tostring (L, 1);
321
322 /* create a user datum to store the scanner */
323 scanner = (lyaml_scanner *) lua_newuserdata (L, sizeof (*scanner));
324 memset ((void *) scanner, 0, sizeof (*scanner));
325 scanner->L = L;
326
327 /* set its metatable */
328 luaL_getmetatable (L, "lyaml.scanner");
329 lua_setmetatable (L, -2);
330
331 /* try to initialize the scanner */
332 if (yaml_parser_initialize (&scanner->parser) == 0)
333 luaL_error (L, "cannot initialize parser for %s", str);
334 yaml_parser_set_input_string (&scanner->parser, str, lua_strlen (L, 1));
335
336 /* create and return the iterator function, with the loader userdatum as
337 its sole upvalue */
338 lua_pushcclosure (L, token_iter, 1);
339 return 1;
340 }
341