#include "lyaml.h"
typedef struct {
lua_State *L;
yaml_parser_t parser;
yaml_event_t event;
char validevent;
int document_count;
} lyaml_parser;
static void
parser_delete_event (lyaml_parser *parser)
{
if (parser->validevent)
{
yaml_event_delete (&parser->event);
parser->validevent = 0;
}
}
static void
parser_set_mark (lua_State *L, const char *k, yaml_mark_t mark)
{
lua_pushstring (L, k);
lua_createtable (L, 0, 3);
#define MENTRY(_s) RAWSET_INTEGER(#_s, mark._s)
MENTRY( index );
MENTRY( line );
MENTRY( column );
#undef MENTRY
lua_rawset (L, -3);
}
static void
parser_push_eventtable (lyaml_parser *parser, const char *v, int n)
{
lua_State *L = parser->L;
lua_createtable (L, 0, n + 3);
RAWSET_STRING ("type", v);
#define MENTRY(_s) parser_set_mark (L, #_s, parser->event._s)
MENTRY( start_mark );
MENTRY( end_mark );
#undef MENTRY
}
static void
parse_STREAM_START (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.stream_start._f)
lua_State *L = parser->L;
const char *encoding;
switch (EVENTF (encoding))
{
#define MENTRY(_s) \
case YAML_##_s##_ENCODING: encoding = #_s; break
MENTRY( ANY );
MENTRY( UTF8 );
MENTRY( UTF16LE );
MENTRY( UTF16BE );
#undef MENTRY
default:
lua_pushfstring (L, "invalid encoding %d", EVENTF (encoding));
lua_error (L);
}
parser_push_eventtable (parser, "STREAM_START", 1);
RAWSET_STRING ("encoding", encoding);
#undef EVENTF
}
static void
parser_append_tag (lua_State *L, yaml_tag_directive_t tag)
{
lua_createtable (L, 0, 2);
#define MENTRY(_s) RAWSET_STRING(#_s, tag._s)
MENTRY( handle );
MENTRY( prefix );
#undef MENTRY
lua_rawseti (L, -2, lua_objlen (L, -2) + 1);
}
static void
parse_DOCUMENT_START (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.document_start._f)
lua_State *L = parser->L;
parser->document_count++;
parser_push_eventtable (parser, "DOCUMENT_START", 1);
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
if (EVENTF (version_directive))
{
lua_pushliteral (L, "version_directive");
lua_createtable (L, 0, 2);
#define MENTRY(_s) RAWSET_INTEGER(#_s, EVENTF (version_directive->_s))
MENTRY( major );
MENTRY( minor );
#undef MENTRY
lua_rawset (L, -3);
}
if (EVENTF (tag_directives.start) &&
EVENTF (tag_directives.end)) {
yaml_tag_directive_t *cur;
lua_pushliteral (L, "tag_directives");
lua_newtable (L);
for (cur = EVENTF (tag_directives.start);
cur != EVENTF (tag_directives.end);
cur = cur + 1)
{
parser_append_tag (L, *cur);
}
lua_rawset (L, -3);
}
#undef EVENTF
}
static void
parse_DOCUMENT_END (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.document_end._f)
lua_State *L = parser->L;
parser_push_eventtable (parser, "DOCUMENT_END", 1);
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
#undef EVENTF
}
static void
parse_ALIAS (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.alias._f)
lua_State *L = parser->L;
parser_push_eventtable (parser, "ALIAS", 1);
RAWSET_EVENTF (anchor);
#undef EVENTF
}
static void
parse_SCALAR (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.scalar._f)
lua_State *L = parser->L;
const char *style;
switch (EVENTF (style))
{
#define MENTRY(_s) \
case YAML_##_s##_SCALAR_STYLE: style = #_s; break
MENTRY( ANY );
MENTRY( PLAIN );
MENTRY( SINGLE_QUOTED );
MENTRY( DOUBLE_QUOTED );
MENTRY( LITERAL );
MENTRY( FOLDED );
#undef MENTRY
default:
lua_pushfstring (L, "invalid sequence style %d", EVENTF (style));
lua_error (L);
}
parser_push_eventtable (parser, "SCALAR", 6);
RAWSET_EVENTF (anchor);
RAWSET_EVENTF (tag);
RAWSET_EVENTF (value);
RAWSET_BOOLEAN ("plain_implicit", EVENTF (plain_implicit));
RAWSET_BOOLEAN ("quoted_implicit", EVENTF (quoted_implicit));
RAWSET_STRING ("style", style);
#undef EVENTF
}
static void
parse_SEQUENCE_START (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.sequence_start._f)
lua_State *L = parser->L;
const char *style;
switch (EVENTF (style))
{
#define MENTRY(_s) \
case YAML_##_s##_SEQUENCE_STYLE: style = #_s; break
MENTRY( ANY );
MENTRY( BLOCK );
MENTRY( FLOW );
#undef MENTRY
default:
lua_pushfstring (L, "invalid sequence style %d", EVENTF (style));
lua_error (L);
}
parser_push_eventtable (parser, "SEQUENCE_START", 4);
RAWSET_EVENTF (anchor);
RAWSET_EVENTF (tag);
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
RAWSET_STRING ("style", style);
#undef EVENTF
}
static void
parse_MAPPING_START (lyaml_parser *parser)
{
#define EVENTF(_f) (parser->event.data.mapping_start._f)
lua_State *L = parser->L;
const char *style;
switch (EVENTF (style))
{
#define MENTRY(_s) \
case YAML_##_s##_MAPPING_STYLE: style = #_s; break
MENTRY( ANY );
MENTRY( BLOCK );
MENTRY( FLOW );
#undef MENTRY
default:
lua_pushfstring (L, "invalid mapping style %d", EVENTF (style));
lua_error (L);
}
parser_push_eventtable (parser, "MAPPING_START", 4);
RAWSET_EVENTF (anchor);
RAWSET_EVENTF (tag);
RAWSET_BOOLEAN ("implicit", EVENTF (implicit));
RAWSET_STRING ("style", style);
#undef EVENTF
}
static void
parser_generate_error_message (lyaml_parser *parser)
{
yaml_parser_t *P = &parser->parser;
char buf[256];
luaL_Buffer b;
luaL_buffinit (parser->L, &b);
luaL_addstring (&b, P->problem ? P->problem : "A problem");
snprintf (buf, sizeof (buf), " at document: %d", parser->document_count);
luaL_addstring (&b, buf);
if (P->problem_mark.line || P->problem_mark.column)
{
snprintf (buf, sizeof (buf), ", line: %lu, column: %lu",
(unsigned long) P->problem_mark.line + 1,
(unsigned long) P->problem_mark.column + 1);
luaL_addstring (&b, buf);
}
luaL_addstring (&b, "\n");
if (P->context)
{
snprintf (buf, sizeof (buf), "%s at line: %lu, column: %lu\n",
P->context,
(unsigned long) P->context_mark.line + 1,
(unsigned long) P->context_mark.column + 1);
luaL_addstring (&b, buf);
}
luaL_pushresult (&b);
}
static int
event_iter (lua_State *L)
{
lyaml_parser *parser = (lyaml_parser *)lua_touserdata(L, lua_upvalueindex(1));
char *str;
parser_delete_event (parser);
if (yaml_parser_parse (&parser->parser, &parser->event) != 1)
{
parser_generate_error_message (parser);
return lua_error (L);
}
parser->validevent = 1;
lua_newtable (L);
lua_pushliteral (L, "type");
switch (parser->event.type)
{
#define MENTRY(_s) \
case YAML_##_s##_EVENT: parser_push_eventtable (parser, #_s, 0); break
MENTRY( STREAM_END );
MENTRY( SEQUENCE_END );
MENTRY( MAPPING_END );
#undef MENTRY
#define MENTRY(_s) \
case YAML_##_s##_EVENT: parse_##_s (parser); break
MENTRY( STREAM_START );
MENTRY( DOCUMENT_START );
MENTRY( DOCUMENT_END );
MENTRY( ALIAS );
MENTRY( SCALAR );
MENTRY( SEQUENCE_START );
MENTRY( MAPPING_START );
#undef MENTRY
case YAML_NO_EVENT:
lua_pushnil (L);
break;
default:
lua_pushfstring (L, "invalid event %d", parser->event.type);
return lua_error (L);
}
return 1;
}
static int
parser_gc (lua_State *L)
{
lyaml_parser *parser = (lyaml_parser *) lua_touserdata (L, 1);
if (parser)
{
parser_delete_event (parser);
yaml_parser_delete (&parser->parser);
}
return 0;
}
void
parser_init (lua_State *L)
{
luaL_newmetatable(L, "lyaml.parser");
lua_pushcfunction(L, parser_gc);
lua_setfield(L, -2, "__gc");
}
int
Pparser (lua_State *L)
{
lyaml_parser *parser;
const unsigned char *str;
luaL_argcheck (L, lua_isstring (L, 1), 1, "must provide a string argument");
str = (const unsigned char *) lua_tostring (L, 1);
parser = (lyaml_parser *) lua_newuserdata (L, sizeof (*parser));
memset ((void *) parser, 0, sizeof (*parser));
parser->L = L;
luaL_getmetatable (L, "lyaml.parser");
lua_setmetatable (L, -2);
if (yaml_parser_initialize (&parser->parser) == 0)
luaL_error (L, "cannot initialize parser for %s", str);
yaml_parser_set_input_string (&parser->parser, str, lua_strlen (L, 1));
lua_pushcclosure (L, event_iter, 1);
return 1;
}