lang: replace stack-based parser with a recursive parser
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
static bool parse_block_params(
|
||||
struct ivy_parser *parser, struct ivy_ast_block_node *block)
|
||||
{
|
||||
while (1) {
|
||||
if (parse_symbol(parser, IVY_SYM_PIPE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_COLON)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `|`, or `:` followed by parameter "
|
||||
"name");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_token *ident = NULL;
|
||||
if (!parse_word(parser, &ident)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected parameter identifier after `:`");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_ident_node *ident_node = create_node(IVY_AST_IDENT);
|
||||
ident_node->n_content = ident;
|
||||
fx_queue_push_back(&block->n_arg, &ident_node->n_base.n_entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_block(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
parse_trace(parser, "expected `[` before block contents");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_block_node *block = create_node(IVY_AST_BLOCK);
|
||||
if (!block) {
|
||||
parser->p_status = IVY_ERR_NO_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
if (peek_symbol(parser, IVY_SYM_COLON)) {
|
||||
result = parse_block_params(parser, block);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
parse_trace(parser, "invalid block parameter list");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool prev_was_expr = false;
|
||||
|
||||
while (1) {
|
||||
struct ivy_ast_node *child = NULL;
|
||||
if (parse_linefeed(parser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (prev_was_expr) {
|
||||
if (!parse_symbol(parser, IVY_SYM_DOT)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `.` after expression");
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
prev_was_expr = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peek_expr_start(parser)) {
|
||||
result = parse_expr(parser, EXPR_PARSE_NORMAL, &child);
|
||||
prev_was_expr = true;
|
||||
} else {
|
||||
parse_trace(parser, "expected `]` or expression");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result || !child) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&block->n_expr, &child->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(block);
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user