#include "mrk/parser_internal.h" #include mrk_err mrk_parser_init(mrk_parser **out) { MRK_CALLOC(out, 1, sizeof(mrk_parser)); return mrk_err_ok; } void mrk_parser_open(mrk_parser *parser, mrk_lexer *lexer) { parser->lexer = lexer; // Prefill lookahead character mrk_parser_advance(parser); } mrk_err mrk_parser_parse(mrk_ast_node **out, mrk_parser *parser) { mrk_ast_node *root; MRK_RES(mrk_ast_node_init(&root)); while (!mrk_parser_done(parser)) { mrk_ast_node *child; MRK_RES(mrk_ast_node_child_append(&child, root)); switch (mrk_parser_peek(parser).type) { case mrk_token_type_header_start: MRK_RES(mrk_parser_parse_header(child, parser)); break; case mrk_token_type_text: case mrk_token_type_left_bracket: MRK_RES(mrk_parser_parse_paragraph(child, parser)); break; } } *out = root; return mrk_err_ok; } mrk_err mrk_parser_parse_header(mrk_ast_node *out, mrk_parser *parser) { mrk_token header_token; mrk_parser_eat(&header_token, parser, mrk_token_type_header_start); out->type = mrk_ast_node_type_header; out->d.header.depth = mrk_token_len(header_token); // Parse subsections of header while (!mrk_parser_done(parser)) { mrk_ast_node *child; switch (mrk_parser_peek(parser).type) { case mrk_token_type_text: MRK_RES(mrk_ast_node_child_append(&child, out)); MRK_RES(mrk_parser_parse_text(child, parser)); break; // Newlines are interpreted as spaces case mrk_token_type_newline: MRK_RES(mrk_ast_node_child_append(&child, out)); child->type = mrk_ast_node_type_space; mrk_parser_advance(parser); break; case mrk_token_type_left_bracket: MRK_RES(mrk_ast_node_child_append(&child, out)); MRK_RES(mrk_parser_parse_link(child, parser)); break; // Header definition ends at newline case mrk_token_type_blank_line: mrk_parser_advance(parser); return mrk_err_ok; } } return mrk_err_ok; } mrk_err mrk_parser_parse_text(mrk_ast_node *out, mrk_parser *parser) { mrk_token text_token; MRK_RES(mrk_parser_eat(&text_token, parser, mrk_token_type_text)); out->type = mrk_ast_node_type_text; out->d.text.start = text_token.start; out->d.text.end = text_token.end; return mrk_err_ok; } mrk_err mrk_parser_parse_link(mrk_ast_node *out, mrk_parser *parser) { out->type = mrk_ast_node_type_link; MRK_RES(mrk_parser_eat(NULL, parser, mrk_token_type_left_bracket)); if (mrk_parser_done(parser)) { parser->error.msg = "Unclosed brackets"; return mrk_err_invalid; } mrk_ast_node *child; MRK_RES(mrk_ast_node_child_append(&child, out)); switch (mrk_parser_peek(parser).type) { case mrk_token_type_text: MRK_RES(mrk_parser_parse_text(child, parser)); break; // TODO allow other types of text (e.g. cursive) // TODO image links default: // TODO throw error break; } MRK_RES(mrk_parser_eat(NULL, parser, mrk_token_type_right_bracket)); MRK_RES(mrk_parser_eat(NULL, parser, mrk_token_type_left_paren)); mrk_token url_token; MRK_RES(mrk_parser_eat(&url_token, parser, mrk_token_type_text)); MRK_RES(mrk_parser_eat(NULL, parser, mrk_token_type_right_paren)); out->d.link.url_start = url_token.start; out->d.link.url_end = url_token.end; return mrk_err_ok; } mrk_err mrk_parser_parse_paragraph(mrk_ast_node *out, mrk_parser *parser) { out->type = mrk_ast_node_type_paragraph; while (!mrk_parser_done(parser)) { mrk_ast_node *child; switch (mrk_parser_peek(parser).type) { case mrk_token_type_text: MRK_RES(mrk_ast_node_child_append(&child, out)); MRK_RES(mrk_parser_parse_text(child, parser)); break; case mrk_token_type_left_bracket: MRK_RES(mrk_ast_node_child_append(&child, out)); MRK_RES(mrk_parser_parse_link(child, parser)); break; case mrk_token_type_newline: MRK_RES(mrk_ast_node_child_append(&child, out)); child->type = mrk_ast_node_type_space; mrk_parser_advance(parser); break; case mrk_token_type_blank_line: mrk_parser_advance(parser); return mrk_err_ok; } } return mrk_err_ok; }