lang: replace stack-based parser with a recursive parser

This commit is contained in:
2026-04-06 18:25:43 +01:00
parent 3a549aa6df
commit b904813cef
77 changed files with 2984 additions and 6499 deletions
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
@@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
struct ast_node_type atom_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_atom_node),
};
+9 -149
View File
@@ -1,149 +1,24 @@
#include "block.h"
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "node.h"
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
void block_add_terminator(struct block_parser_state *state, unsigned short tok)
{
if (state->s_nr_terminators < BLOCK_TERMINATOR_MAX) {
state->s_terminators[state->s_nr_terminators++] = tok;
}
}
void block_copy_terminators(
const struct block_parser_state *src, struct block_parser_state *dest)
{
dest->s_nr_terminators = src->s_nr_terminators;
for (unsigned int i = 0; i < src->s_nr_terminators; i++) {
dest->s_terminators[i] = src->s_terminators[i];
}
}
bool block_terminates_at_token(struct block_parser_state *state, unsigned short tok)
{
for (unsigned int i = 0; i < BLOCK_TERMINATOR_MAX; i++) {
if (state->s_terminators[i] == tok) {
return true;
}
}
return false;
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct block_parser_state *state
= parser_get_state(ctx, struct block_parser_state);
struct ivy_ast_block_node *node
= (struct ivy_ast_block_node *)(state->s_base.s_node);
int flags = 0;
if (block_terminates_at_token(state, IVY_KW_END)) {
flags = PARSE_REPEAT_TOKEN;
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, flags);
}
static struct token_parse_result parse_else(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct block_parser_state *state
= parser_get_state(ctx, struct block_parser_state);
struct ivy_ast_block_node *node
= (struct ivy_ast_block_node *)(state->s_base.s_node);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_keyword(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct block_parser_state *state
= parser_get_state(ctx, struct block_parser_state);
struct ivy_ast_block_node *node
= (struct ivy_ast_block_node *)(state->s_base.s_node);
if (block_terminates_at_token(state, tok->t_keyword)) {
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
static struct token_parse_result parse_symbol(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct block_parser_state *state
= parser_get_state(ctx, struct block_parser_state);
struct ivy_ast_block_node *node
= (struct ivy_ast_block_node *)(state->s_base.s_node);
if (block_terminates_at_token(state, tok->t_symbol)) {
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
static struct token_parse_result parse_global(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_push_state(ctx, IVY_AST_GLOBAL, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_expr_begin(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct block_parser_state *state
= parser_get_state(ctx, struct block_parser_state);
struct ivy_ast_block_node *node
= (struct ivy_ast_block_node *)(state->s_base.s_node);
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
memcpy(expr->s_terminators, state->s_terminators,
sizeof expr->s_terminators);
expr->s_nr_terminators = state->s_nr_terminators;
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct ivy_ast_block_node *block
= (struct ivy_ast_block_node *)parent->s_node;
fx_queue_push_back(&block->n_expr, &child->n_entry);
return IVY_OK;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
struct ivy_ast_block_node *block = (struct ivy_ast_block_node *)node;
fx_queue_entry *entry = fx_queue_first(&block->n_expr);
fx_queue_entry *entry = fx_queue_first(&block->n_arg);
while (entry) {
struct ivy_ast_node *expr
= fx_unbox(struct ivy_ast_node, entry, n_entry);
ast_node_iterator_enqueue_node(iterator, node, expr);
entry = fx_queue_next(entry);
}
entry = fx_queue_first(&block->n_expr);
while (entry) {
struct ivy_ast_node *expr
= fx_unbox(struct ivy_ast_node, entry, n_entry);
@@ -153,21 +28,6 @@ static void collect_children(
}
struct ast_node_type block_node_ops = {
.n_add_child = add_child,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct block_parser_state),
.n_node_size = sizeof(struct ivy_ast_block_node),
.n_keyword_parsers = {
KW_PARSER(GLOBAL, parse_global),
KW_PARSER(END, parse_end),
KW_PARSER(ELSE, parse_else),
KW_PARSER(ELIF, parse_else), /* same behaviour as ELSE */
KW_PARSER_FALLBACK(parse_keyword),
},
.n_symbol_parsers = {
SYM_PARSER_FALLBACK(parse_symbol),
},
.n_expr_parser = {
.expr_begin = parse_expr_begin,
},
};
-22
View File
@@ -1,26 +1,4 @@
#ifndef _AST_BLOCK_H_
#define _AST_BLOCK_H_
#include "ctx.h"
#define BLOCK_TERMINATOR_MAX 8
struct block_parser_state {
struct parser_state s_base;
bool s_single_expr;
/* the block will be terminated when any token in this list
* is encountered. the token that terminated the block will
* not be consumed. */
unsigned short s_terminators[BLOCK_TERMINATOR_MAX];
unsigned short s_nr_terminators;
};
extern void block_add_terminator(
struct block_parser_state *state, unsigned short tok);
extern void block_copy_terminators(
const struct block_parser_state *src, struct block_parser_state *dest);
extern bool block_terminates_at_token(
struct block_parser_state *state, unsigned short tok);
#endif
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "iterate.h"
#include "node.h"
@@ -22,6 +21,5 @@ static void collect_children(
struct ast_node_type cascade_node_ops = {
.n_collect_children = collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_cascade_node),
};
-159
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "iterate.h"
#include "node.h"
@@ -6,142 +5,6 @@
#include <ivy/lang/lex.h>
#include <stdio.h>
struct class_parser_state {
struct parser_state s_base;
enum {
AREA_IDENT,
AREA_BODY,
} s_current_area;
int s_prev_token;
};
static struct token_parse_result parse_hyphen_right_angle(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct class_parser_state *state
= parser_get_state(ctx, struct class_parser_state);
if (state->s_current_area != AREA_BODY) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_push_state(ctx, IVY_AST_PROPERTY, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_plus(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct class_parser_state *state
= parser_get_state(ctx, struct class_parser_state);
if (state->s_current_area != AREA_BODY) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_push_state(ctx, IVY_AST_MSGH, 0);
struct parser_state *msgh_state = parser_get_state_generic(ctx);
struct ivy_ast_msgh_node *msgh
= (struct ivy_ast_msgh_node *)msgh_state->s_node;
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_hyphen(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct class_parser_state *state
= parser_get_state(ctx, struct class_parser_state);
if (state->s_current_area != AREA_BODY) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_push_state(ctx, IVY_AST_MSGH, 0);
struct parser_state *msgh_state = parser_get_state_generic(ctx);
struct ivy_ast_msgh_node *msgh
= (struct ivy_ast_msgh_node *)msgh_state->s_node;
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct class_parser_state *state
= parser_get_state(ctx, struct class_parser_state);
struct ivy_ast_class_node *node
= (struct ivy_ast_class_node *)(state->s_base.s_node);
if (state->s_current_area != AREA_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token == IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
node->n_ident = tok;
state->s_prev_token = IVY_TOK_IDENT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct class_parser_state *state
= parser_get_state(ctx, struct class_parser_state);
struct ivy_ast_class_node *node
= (struct ivy_ast_class_node *)(state->s_base.s_node);
if (state->s_current_area == AREA_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_linefeed(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct class_parser_state *state
= parser_get_state(ctx, struct class_parser_state);
if (state->s_current_area != AREA_IDENT) {
return PARSE_RESULT(IVY_OK, 0);
}
if (state->s_prev_token != IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev_token = IVY_TOK_LINEFEED;
state->s_current_area = AREA_BODY;
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *state, struct ivy_ast_node *child)
{
struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)state->s_node;
switch (child->n_type) {
case IVY_AST_MSGH:
fx_queue_push_back(&c->n_msg_handlers, &child->n_entry);
break;
case IVY_AST_PROPERTY:
fx_queue_push_back(&c->n_properties, &child->n_entry);
break;
default:
return IVY_ERR_NOT_SUPPORTED;
}
return IVY_OK;
}
static void to_string(struct ivy_ast_node *node, fx_string *str)
{
struct ivy_ast_class_node *c = (struct ivy_ast_class_node *)node;
@@ -151,13 +14,6 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
c->n_ident->t_str);
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct class_parser_state *state = (struct class_parser_state *)sp;
state->s_prev_token = IVY_KW_CLASS;
state->s_current_area = AREA_IDENT;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -180,22 +36,7 @@ static void collect_children(
}
struct ast_node_type class_node_ops = {
.n_add_child = add_child,
.n_to_string = to_string,
.n_init_state = init_state,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct class_parser_state),
.n_node_size = sizeof(struct ivy_ast_class_node),
.n_symbol_parsers = {
SYM_PARSER(HYPHEN_RIGHT_ANGLE, parse_hyphen_right_angle),
SYM_PARSER(HYPHEN, parse_hyphen),
SYM_PARSER(PLUS, parse_plus),
},
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
TOK_PARSER(LINEFEED, parse_linefeed),
},
.n_keyword_parsers = {
KW_PARSER(END, parse_end),
},
};
+1 -353
View File
@@ -1,337 +1,5 @@
#include "block.h"
#include "expr/expr.h"
#include "iterate.h"
struct cond_group_parser_state {
struct parser_state s_base;
bool s_inline;
unsigned int s_prev_token;
struct ivy_ast_cond_node *s_cur_branch;
fx_queue s_branches;
struct ivy_ast_node *s_prev_node;
};
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct cond_group_parser_state *state
= (struct cond_group_parser_state *)sp;
state->s_prev_node = (struct ivy_ast_node *)arg;
}
static enum ivy_status flush_current_branch(struct cond_group_parser_state *state)
{
if (!state->s_cur_branch) {
return IVY_ERR_INTERNAL_FAILURE;
}
fx_queue_push_back(&state->s_branches, &state->s_cur_branch->n_base.n_entry);
state->s_cur_branch
= (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND);
if (!state->s_cur_branch) {
return IVY_ERR_NO_MEMORY;
}
return IVY_OK;
}
struct token_parse_result parse_if(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
if (state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch
= (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND);
if (!state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0);
}
if (state->s_prev_node) {
/* this is an inline if-else */
state->s_inline = true;
state->s_cur_branch->n_body = state->s_prev_node;
state->s_prev_node = NULL;
} else {
state->s_inline = false;
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
state->s_prev_token = IVY_KW_IF;
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_elif(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
if (!state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_inline) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_THEN) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_body = state->s_prev_node;
state->s_prev_node = NULL;
enum ivy_status status = flush_current_branch(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
state->s_prev_token = IVY_KW_ELIF;
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_then(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
if (!state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_inline) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_IF && state->s_prev_token != IVY_KW_ELIF) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
/* previous component was the if-condition. */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_cond = state->s_prev_node;
state->s_prev_node = NULL;
/* next component will be a block. */
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
/* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */
block_add_terminator(block, IVY_KW_ELIF);
block_add_terminator(block, IVY_KW_ELSE);
block_add_terminator(block, IVY_KW_END);
state->s_prev_token = IVY_KW_THEN;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_else(
struct ivy_parser *ctx, struct ivy_token *tok)
{
enum ivy_status status;
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
if (!state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_inline) {
/* previous component was either an expression or a block, and is the if branch body. */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_THEN) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_body = state->s_prev_node;
state->s_prev_node = NULL;
status = flush_current_branch(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
/* next component should be a block. */
} else {
/* previous component was the if-condition. */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_IF) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_cond = state->s_prev_node;
state->s_prev_node = NULL;
status = flush_current_branch(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
/* next component will be an expression. */
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
/* set the sub-expression depth to be non-zero so the expression
* parser doesn't consume the expression separator. */
expr->s_subexpr_depth = 1;
}
state->s_prev_token = IVY_KW_ELSE;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_expr_begin(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
if (state->s_prev_token != IVY_KW_ELSE
&& state->s_prev_token != IVY_KW_THEN) {
/* expression can only follow else and then keywords. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_END);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static enum ivy_status finalise_cond_group(struct cond_group_parser_state *state)
{
struct ivy_ast_cond_group_node *group
= (struct ivy_ast_cond_group_node *)state->s_base.s_node;
if (state->s_inline) {
/* we have just reached the end of either the 'if' or the 'else' expression. */
if (!state->s_cur_branch) {
/* not currently parsing a conditional branch. */
return IVY_ERR_BAD_SYNTAX;
}
if (!state->s_prev_node) {
/* else expression is empty. */
return IVY_ERR_BAD_SYNTAX;
}
if (state->s_prev_token == IVY_KW_ELSE) {
/* this is the else expression, s_prev_node is the else body. */
state->s_cur_branch->n_body = state->s_prev_node;
} else if (state->s_prev_token == IVY_KW_IF) {
/* this is the if expression, s_prev_node is the if condition. */
state->s_cur_branch->n_cond = state->s_prev_node;
}
state->s_prev_node = NULL;
flush_current_branch(state);
group->n_branches = state->s_branches;
state->s_branches = FX_QUEUE_INIT;
return IVY_OK;
} else {
/* we have just reached the 'end' keyword. */
if (!state->s_cur_branch) {
/* not currently parsing a conditional branch. */
return IVY_ERR_BAD_SYNTAX;
}
if (!state->s_prev_node) {
/* else expression is empty. */
return IVY_ERR_BAD_SYNTAX;
}
state->s_cur_branch->n_body = state->s_prev_node;
state->s_prev_node = NULL;
flush_current_branch(state);
group->n_branches = state->s_branches;
state->s_branches = FX_QUEUE_INIT;
return IVY_OK;
}
}
static struct token_parse_result parse_punct_terminator(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
if (!state->s_inline) {
/* only inline conditional can be ended with punctuation. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_cond_group(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct cond_group_parser_state *state
= parser_get_state(ctx, struct cond_group_parser_state);
enum ivy_status status = finalise_cond_group(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
int flags = 0;
if (state->s_inline) {
flags = PARSE_REPEAT_TOKEN;
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, flags);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct cond_group_parser_state *state
= (struct cond_group_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
#include "node.h"
static void cond_group_collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
@@ -363,31 +31,11 @@ static void cond_collect_children(
}
struct ast_node_type cond_group_node_ops = {
.n_init_state = init_state,
.n_add_child = add_child,
.n_collect_children = cond_group_collect_children,
.n_state_size = sizeof(struct cond_group_parser_state),
.n_node_size = sizeof(struct ivy_ast_cond_group_node),
.n_keyword_parsers = {
KW_PARSER(IF, parse_if),
KW_PARSER(THEN, parse_then),
KW_PARSER(ELIF, parse_elif),
KW_PARSER(ELSE, parse_else),
KW_PARSER(END, parse_end),
},
.n_symbol_parsers = {
SYM_PARSER(DOT, parse_punct_terminator),
SYM_PARSER(COMMA, parse_punct_terminator),
SYM_PARSER(RIGHT_PAREN, parse_punct_terminator),
SYM_PARSER(BANG, parse_punct_terminator),
},
.n_expr_parser = {
.expr_begin = parse_expr_begin,
},
};
struct ast_node_type cond_node_ops = {
.n_collect_children = cond_collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_cond_node),
};
-4
View File
@@ -1,17 +1,13 @@
#include "ctx.h"
#include "node.h"
struct ast_node_type c_true_node_ops = {
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_node),
};
struct ast_node_type c_false_node_ops = {
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_node),
};
struct ast_node_type c_null_node_ops = {
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_node),
};
-356
View File
@@ -1,356 +0,0 @@
#include "ctx.h"
#include "../debug.h"
#include "node.h"
#include <fx/core/queue.h>
#include <ivy/diag.h>
#include <ivy/lang/ast.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef IVY_LANG_DEBUG
static void print_state_stack(struct ivy_parser *parser)
{
fx_queue_iterator it = {0};
fx_queue_foreach (&it, &parser->p_state) {
struct parser_state *state
= fx_unbox(struct parser_state, it.entry, s_entry);
debug_printf(
" %s\n",
ivy_ast_node_type_to_string(state->s_node->n_type));
}
}
#endif
enum ivy_status ivy_parser_create(struct ivy_parser **parser)
{
struct ivy_parser *out = malloc(sizeof *out);
if (!out) {
return IVY_ERR_NO_MEMORY;
}
memset(out, 0x0, sizeof *out);
parser_push_state(out, IVY_AST_UNIT, 0);
*parser = out;
return IVY_OK;
}
void ivy_parser_destroy(struct ivy_parser *parser, struct ivy_ast_node **result)
{
struct ivy_ast_node *root = NULL;
fx_queue_entry *entry = fx_queue_first(&parser->p_state);
;
while (entry) {
struct parser_state *state
= fx_unbox(struct parser_state, entry, s_entry);
fx_queue_entry *next = fx_queue_next(entry);
fx_queue_delete(&parser->p_state, entry);
if (root) {
ivy_ast_node_destroy(root);
}
root = state->s_node;
free(state);
entry = next;
}
if (result) {
*result = root;
} else if (root) {
ivy_ast_node_destroy(root);
}
free(parser);
}
enum ivy_status ivy_parser_set_diag_ctx(
struct ivy_parser *parser, struct ivy_diag_ctx *ctx)
{
parser->p_diag_ctx = ctx;
return IVY_OK;
}
enum ivy_status ivy_parser_get_status(struct ivy_parser *parser)
{
return parser->p_status;
}
enum ivy_status ivy_parser_push_token(
struct ivy_parser *parser, struct ivy_token *tok)
{
if (!tok) {
return ivy_parser_push_eof(parser);
}
while (true) {
struct parser_state *state = parser_get_state_generic(parser);
if (!state) {
parser->p_status = IVY_ERR_INTERNAL_FAILURE;
break;
}
token_parse_function func = get_token_parser(state->s_node, tok);
if (func) {
struct token_parse_result result = func(parser, tok);
parser->p_status = result.r_status;
#ifdef IVY_LANG_DEBUG
debug_printf("states (after token)\n");
print_state_stack(parser);
#endif
if (result.r_flags & PARSE_REPEAT_TOKEN) {
continue;
}
break;
}
if (tok->t_type == IVY_TOK_LINEFEED) {
ivy_token_destroy(tok);
parser->p_status = IVY_OK;
break;
}
parser->p_status = IVY_ERR_BAD_SYNTAX;
break;
}
return parser->p_status;
}
enum ivy_status ivy_parser_push_eof(struct ivy_parser *parser)
{
while (true) {
struct parser_state *state = parser_get_state_generic(parser);
if (!state) {
parser->p_status = IVY_ERR_INTERNAL_FAILURE;
break;
}
token_parse_function func = NULL;
struct ivy_token tok = {0};
switch (state->s_node->n_type) {
case IVY_AST_EXPR:
case IVY_AST_COND_GROUP:
case IVY_AST_FOR_LOOP:
case IVY_AST_WHILE_LOOP:
tok.t_type = IVY_TOK_SYMBOL;
tok.t_symbol = IVY_SYM_DOT;
func = get_token_parser(state->s_node, &tok);
break;
default:
break;
}
if (!func) {
break;
}
struct token_parse_result result = func(parser, &tok);
parser->p_status = result.r_status;
if (result.r_flags & PARSE_REPEAT_TOKEN) {
continue;
}
#ifdef IVY_LANG_DEBUG
debug_printf("states (after token)\n");
print_state_stack(parser);
#endif
break;
}
return parser->p_status;
}
struct parser_state *parser_get_state_generic(struct ivy_parser *parser)
{
fx_queue_entry *entry = fx_queue_last(&parser->p_state);
if (!entry) {
return NULL;
}
struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry);
return state;
}
struct parser_state *parser_get_parent_state_generic(
struct ivy_parser *parser, enum ivy_ast_node_type type)
{
fx_queue_entry *entry = fx_queue_last(&parser->p_state);
if (!entry) {
return NULL;
}
entry = fx_queue_prev(entry);
if (!entry) {
return NULL;
}
struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry);
if (state->s_node->n_type != type) {
return NULL;
}
return state;
}
struct parser_state *parser_push_state(
struct ivy_parser *parser, enum ivy_ast_node_type type, uintptr_t arg)
{
const struct ast_node_type *node_type = get_ast_node_type(type);
if (!node_type) {
return NULL;
}
struct parser_state *state = malloc(node_type->n_state_size);
if (!state) {
return NULL;
}
memset(state, 0x0, node_type->n_state_size);
fx_queue_entry *current_state_entry = fx_queue_last(&parser->p_state);
if (current_state_entry) {
struct parser_state *current_state = fx_unbox(
struct parser_state, current_state_entry, s_entry);
state->s_parent = current_state->s_node;
}
state->s_node = ast_node_create(type);
fx_queue_push_back(&parser->p_state, &state->s_entry);
if (node_type->n_init_state) {
node_type->n_init_state(parser, state, arg);
}
#ifdef IVY_LANG_DEBUG
debug_printf("states (after push)\n");
print_state_stack(parser);
#endif
return state;
}
void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags)
{
if (parser->p_state.q_first == parser->p_state.q_last) {
return;
}
fx_queue_entry *entry = fx_queue_last(&parser->p_state);
struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry);
fx_queue_pop_back(&parser->p_state);
if (state && state->s_node && (flags & STATE_ADD_NODE_TO_PARENT)) {
parser_add_child(parser, state->s_node);
}
free(state);
#ifdef IVY_LANG_DEBUG
debug_printf("states (after pop)\n");
print_state_stack(parser);
#endif
}
void parser_replace_current_node(
struct ivy_parser *parser, struct ivy_ast_node *new_node)
{
struct parser_state *state = parser_get_state_generic(parser);
if (!state) {
return;
}
ivy_ast_node_destroy(state->s_node);
state->s_node = new_node;
}
enum ivy_status parser_add_child(
struct ivy_parser *parser, struct ivy_ast_node *new_node)
{
struct parser_state *state = parser_get_state_generic(parser);
if (!state) {
return IVY_ERR_NOT_SUPPORTED;
}
const struct ast_node_type *node_type
= get_ast_node_type(state->s_node->n_type);
if (!node_type || !node_type->n_add_child) {
return IVY_ERR_NOT_SUPPORTED;
}
return node_type->n_add_child(state, new_node);
}
bool ivy_parser_is_node_complete(struct ivy_parser *parser)
{
return (parser->p_state.q_first == parser->p_state.q_last);
}
struct ivy_ast_node *ivy_parser_root_node(struct ivy_parser *parser)
{
fx_queue_entry *entry = fx_queue_first(&parser->p_state);
struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry);
return state ? state->s_node : NULL;
}
struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser)
{
fx_queue_entry *entry = fx_queue_first(&parser->p_state);
struct parser_state *state = fx_unbox(struct parser_state, entry, s_entry);
if (!state) {
return NULL;
}
if (state->s_node->n_type != IVY_AST_UNIT) {
return NULL;
}
struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)state->s_node;
entry = fx_queue_pop_front(&unit->n_children);
if (!entry) {
return NULL;
}
return fx_unbox(struct ivy_ast_node, entry, n_entry);
}
struct ivy_diag *parser_push_diag(
struct ivy_parser *parser, unsigned long diag_class, unsigned long msg,
struct ivy_token *tok)
{
struct ivy_diag *diag
= ivy_diag_ctx_create_diag(parser->p_diag_ctx, diag_class);
if (msg != 0) {
ivy_diag_push_msg(diag, msg);
}
if (tok) {
ivy_diag_set_location(diag, tok->t_start.c_row, tok->t_start.c_col);
const struct ivy_diag_highlight hl[] = {
IVY_DIAG_HL(
ERROR, tok->t_start.c_row, tok->t_start.c_col,
tok->t_end.c_row, tok->t_end.c_col),
};
const size_t nr_hl = sizeof hl / sizeof hl[0];
ivy_diag_push_snippet(
diag, tok->t_start.c_row, tok->t_end.c_row, NULL, 0, hl,
nr_hl);
};
return diag;
}
-50
View File
@@ -1,50 +0,0 @@
#ifndef _AST_CTX_H_
#define _AST_CTX_H_
#include <fx/core/queue.h>
#include <ivy/diag.h>
#include <ivy/lang/ast.h>
#include <ivy/lang/diag.h>
#include <ivy/status.h>
#define parser_get_state(parser, state_type) \
((state_type *)parser_get_state_generic(parser))
#define parser_get_parent_state(parser, type_id, state_type) \
((state_type *)parser_get_parent_state_generic(parser, type_id))
struct parser_state {
fx_queue_entry s_entry;
struct ivy_ast_node *s_parent;
struct ivy_ast_node *s_node;
};
struct ivy_parser {
enum ivy_status p_status;
struct ivy_diag_ctx *p_diag_ctx;
fx_queue p_state;
fx_queue p_token_queue;
fx_queue p_node_queue;
};
enum pop_state_flags {
STATE_ADD_NODE_TO_PARENT = 0x01u,
};
extern struct parser_state *parser_push_state(
struct ivy_parser *parser, enum ivy_ast_node_type node_type, uintptr_t arg);
extern void parser_pop_state(struct ivy_parser *parser, enum pop_state_flags flags);
extern struct parser_state *parser_get_state_generic(struct ivy_parser *parser);
extern struct parser_state *parser_get_parent_state_generic(
struct ivy_parser *parser, enum ivy_ast_node_type type);
extern void parser_replace_current_node(
struct ivy_parser *parser, struct ivy_ast_node *new_node);
extern enum ivy_status parser_add_child(
struct ivy_parser *parser, struct ivy_ast_node *new_node);
extern struct ivy_diag *parser_push_diag(
struct ivy_parser *parser, unsigned long diag_class, unsigned long msg,
struct ivy_token *tok);
#endif
-2
View File
@@ -1,9 +1,7 @@
#include "ctx.h"
#include "node.h"
#include <stdio.h>
struct ast_node_type discard_node_ops = {
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_discard_node),
};
+16
View File
@@ -0,0 +1,16 @@
#include "iterate.h"
#include "node.h"
#include <fx/ds/string.h>
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
struct ivy_ast_do_node *do_node = (struct ivy_ast_do_node *)node;
ast_node_iterator_enqueue_node(iterator, node, do_node->n_block);
}
struct ast_node_type do_node_ops = {
.n_collect_children = collect_children,
.n_node_size = sizeof(struct ivy_ast_op_node),
};
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
@@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
struct ast_node_type double_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_double_node),
};
File diff suppressed because it is too large Load Diff
-104
View File
@@ -1,104 +0,0 @@
#include "expr.h"
#include "../node.h"
void expr_add_terminator(struct expr_parser_state *state, unsigned short tok)
{
if (state->s_nr_terminators < EXPR_TERMINATOR_MAX) {
state->s_terminators[state->s_nr_terminators++] = tok;
}
}
void expr_copy_terminators(
const struct expr_parser_state *src, struct expr_parser_state *dest)
{
dest->s_nr_terminators = src->s_nr_terminators;
for (unsigned int i = 0; i < src->s_nr_terminators; i++) {
dest->s_terminators[i] = src->s_terminators[i];
}
}
bool expr_terminates_at_token(struct expr_parser_state *state, unsigned short tok)
{
for (unsigned int i = 0; i < EXPR_TERMINATOR_MAX; i++) {
if (state->s_terminators[i] == tok) {
return true;
}
}
return false;
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct expr_parser_state *state = (struct expr_parser_state *)parent;
switch (state->s_type) {
case EXPR_TYPE_STMT:
return IVY_ERR_NOT_SUPPORTED;
case EXPR_TYPE_ARITH:
return arith_add_child(parent, child);
default:
return IVY_ERR_NOT_SUPPORTED;
}
}
struct ast_node_type expr_node_ops = {
.n_add_child = add_child,
.n_state_size = sizeof(struct expr_parser_state),
.n_node_size = sizeof(struct ivy_ast_expr_node),
.n_token_parsers = {
TOK_PARSER(IDENT, arith_parse_ident),
TOK_PARSER(INT, arith_parse_operand),
TOK_PARSER(DOUBLE, arith_parse_operand),
TOK_PARSER(ATOM, arith_parse_operand),
TOK_PARSER(STRING, arith_parse_operand),
TOK_PARSER(STR_START, arith_parse_fstring),
TOK_PARSER(SYMBOL, arith_parse_operator),
TOK_PARSER(LABEL, arith_parse_label),
},
.n_symbol_parsers = {
SYM_PARSER(LEFT_PAREN, arith_parse_left_paren),
SYM_PARSER(RIGHT_PAREN, arith_parse_right_paren),
SYM_PARSER(LEFT_BRACE, arith_parse_left_brace),
SYM_PARSER(RIGHT_BRACE, arith_parse_right_brace),
SYM_PARSER(LEFT_BRACKET, arith_parse_left_bracket),
SYM_PARSER(RIGHT_BRACKET, arith_parse_right_bracket),
SYM_PARSER(SEMICOLON, arith_parse_semicolon),
SYM_PARSER(UNDERSCORE, arith_parse_operand),
SYM_PARSER(CARET, arith_parse_caret),
/* treat colons as empty labels */
SYM_PARSER(COLON, arith_parse_label),
SYM_PARSER(COMMA, arith_parse_comma),
SYM_PARSER(DOT, arith_parse_dot),
SYM_PARSER(BANG, arith_parse_bang),
SYM_PARSER(EQUAL_RIGHT_ANGLE, arith_parse_equal_right_angle),
},
.n_keyword_parsers = {
/* statement keywords */
KW_PARSER(FOR, stmt_parse_for),
KW_PARSER(WHILE, stmt_parse_while),
KW_PARSER(BREAK, stmt_parse_break),
KW_PARSER(CONTINUE, stmt_parse_continue),
KW_PARSER(TRY, stmt_parse_try),
KW_PARSER(MATCH, stmt_parse_match),
KW_PARSER(IF, stmt_parse_if),
KW_PARSER(THEN, stmt_parse_end),
KW_PARSER(ELSE, stmt_parse_end),
KW_PARSER(ELIF, stmt_parse_end),
KW_PARSER(CATCH, stmt_parse_end),
KW_PARSER(FINALLY, stmt_parse_end),
KW_PARSER(END, stmt_parse_end),
/* keyword constants */
KW_PARSER(TRUE, arith_parse_operand),
KW_PARSER(FALSE, arith_parse_operand),
KW_PARSER(NULL, arith_parse_operand),
/* operator/block keywords */
KW_PARSER(IN, arith_parse_in),
KW_PARSER(IS, arith_parse_operator),
KW_PARSER(DO, arith_parse_do),
}
};
-183
View File
@@ -1,183 +0,0 @@
#ifndef _AST_EXPR_EXPR_H_
#define _AST_EXPR_EXPR_H_
#include "../ctx.h"
#include "../node.h"
#include <fx/core/queue.h>
#define EXPR_TERMINATOR_MAX 8
struct ivy_ast_node;
struct ivy_ast_msg_node;
enum expr_type {
EXPR_TYPE_NONE = 0,
/* if-else, while/for, match, etc (any expression that ends with an
* 'end' keyword */
EXPR_TYPE_STMT,
/* arithmetic and message-sending expressions (any expression that ends
* implicitly or with an expression separator */
EXPR_TYPE_ARITH,
};
enum expr_subtype {
EXPR_SUBTYPE_NONE = 0,
/* generic parenthesis-enclosed arithmetic expressions */
EXPR_SUBTYPE_PAREN,
/* any kind of message */
EXPR_SUBTYPE_MSG,
/* keyword messages */
EXPR_SUBTYPE_KEYWORD_MSG,
/* expression delimited by labels */
EXPR_SUBTYPE_KEYWORD_ARG,
/* complex messages */
EXPR_SUBTYPE_COMPLEX_MSG,
/* expression delimited by commas */
EXPR_SUBTYPE_COMPLEX_ARG,
/* message cascade operation */
EXPR_SUBTYPE_CASCADE,
};
enum expr_component {
EXPR_CMP_NONE = 0,
EXPR_CMP_OPERATOR,
EXPR_CMP_OPERAND,
EXPR_CMP_MSG,
EXPR_CMP_KEYWORD,
};
struct expr_parser_state {
struct parser_state s_base;
enum expr_type s_type;
enum expr_subtype s_sub_type;
/* this is a return statement (prefixed with a caret) */
bool s_return;
/* for arithmetic expressions, this records whether the previous
* component (either a token or parenthesised group of tokens) is an
* operator, operand, or message */
enum expr_component s_prev_component;
/* the token type/keyword type/symbol type of the last token that was
* encountered */
unsigned int s_prev_token;
/* if this is an arithmetic expression, this variable is the depth
* of parentheses that this sub-expression is at */
unsigned int s_paren_depth;
/* if this expression is parsing a sub-component of a larger expression,
* the depth of the expression is recorded here. */
unsigned int s_subexpr_depth;
/* the expression will be terminated when any token in this list
* is encountered. the token that terminated the expression will
* not be consumed. */
unsigned short s_terminators[EXPR_TERMINATOR_MAX];
unsigned short s_nr_terminators;
fx_queue s_output_queue;
fx_queue s_operator_stack;
/* these variables are for keyword-message expressions */
struct ivy_ast_node *s_recipient;
struct ivy_ast_msg_node *s_msg;
fx_queue s_labels;
union {
/* for keyword-messages, this is a list of arg values. */
fx_queue s_args;
/* for cascade operators, this is a list of messages to send to the recipient. */
fx_queue s_cascade_msg;
};
};
/* general functions */
extern void expr_add_terminator(struct expr_parser_state *state, unsigned short tok);
extern void expr_copy_terminators(
const struct expr_parser_state *src, struct expr_parser_state *dest);
extern bool expr_terminates_at_token(
struct expr_parser_state *state, unsigned short tok);
extern struct token_parse_result expr_finalise(
struct ivy_parser *ctx, struct expr_parser_state *state,
enum ivy_operator_precedence min_precedence, struct ivy_ast_node **expr);
extern struct token_parse_result expr_finalise_and_return(
struct ivy_parser *ctx, struct expr_parser_state *state);
/* arithmetic parser callbacks */
extern void arith_push_operator(
struct expr_parser_state *state, struct ivy_ast_node *node);
extern enum ivy_status arith_push_operand(
struct expr_parser_state *state, struct ivy_token *tok);
extern enum ivy_status arith_add_child(
struct parser_state *parent, struct ivy_ast_node *child);
extern struct token_parse_result arith_parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_fstring(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_operand(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_operator(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_label(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_left_paren(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_right_paren(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_left_brace(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_right_brace(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_left_bracket(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_right_bracket(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_semicolon(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_dot(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_bang(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_caret(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_comma(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_equal_right_angle(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_in(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_is(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result arith_parse_do(
struct ivy_parser *ctx, struct ivy_token *tok);
/* statement parser callbacks */
extern struct token_parse_result stmt_parse_try(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_for(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_while(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_match(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_if(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_then(
struct ivy_parser *ctx, struct ivy_token *tok);
struct token_parse_result stmt_parse_else(
struct ivy_parser *ctx, struct ivy_token *tok);
struct token_parse_result stmt_parse_end(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_break(
struct ivy_parser *ctx, struct ivy_token *tok);
extern struct token_parse_result stmt_parse_continue(
struct ivy_parser *ctx, struct ivy_token *tok);
#endif
-266
View File
@@ -1,266 +0,0 @@
#include "../node.h"
#include "expr.h"
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
#include <ivy/lang/operator.h>
#include <stdio.h>
struct token_parse_result stmt_parse_try(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (expr_terminates_at_token(state, IVY_KW_TRY)) {
/* treat this as a statement terminator. */
struct token_parse_result result
= expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) {
/* try-catch cannot be used inline. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev_token = IVY_KW_TRY;
if (fx_queue_empty(&state->s_operator_stack)
&& fx_queue_empty(&state->s_output_queue)) {
parser_pop_state(ctx, 0);
}
/* if expr is NULL, this is an if-then-else-end statement,
* otherwise, this is an expr-if-else-expr. */
parser_push_state(ctx, IVY_AST_TRY, 0);
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result stmt_parse_for(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (expr_terminates_at_token(state, IVY_KW_FOR)) {
/* treat this as a statement terminator. */
struct token_parse_result result
= expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) {
/* keyword messages have a higher precedence than inline
* conditionals, so treat this as a statement terminator. */
struct token_parse_result result
= expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
struct ivy_ast_node *expr = NULL;
struct token_parse_result result
= expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr);
if (result.r_status != IVY_OK) {
return result;
}
state->s_prev_token = IVY_KW_FOR;
if (fx_queue_empty(&state->s_operator_stack)
&& fx_queue_empty(&state->s_output_queue)) {
parser_pop_state(ctx, 0);
}
/* if expr is NULL, this is an if-then-else-end statement,
* otherwise, this is an expr-if-else-expr. */
parser_push_state(ctx, IVY_AST_FOR_LOOP, (uintptr_t)expr);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
struct token_parse_result stmt_parse_while(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) {
/* keyword messages have a higher precedence than inline
* conditionals, so treat this as a statement terminator. */
struct token_parse_result result
= expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
struct ivy_ast_node *expr = NULL;
struct token_parse_result result
= expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr);
if (result.r_status != IVY_OK) {
return result;
}
state->s_prev_token = IVY_KW_WHILE;
if (fx_queue_empty(&state->s_operator_stack)
&& fx_queue_empty(&state->s_output_queue)) {
parser_pop_state(ctx, 0);
}
/* if expr is NULL, this is an if-then-else-end statement,
* otherwise, this is an expr-if-else-expr. */
parser_push_state(ctx, IVY_AST_WHILE_LOOP, (uintptr_t)expr);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
struct token_parse_result stmt_parse_match(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_prev_component == EXPR_CMP_OPERAND
|| state->s_prev_component == EXPR_CMP_MSG) {
/* match statements are operands. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct ivy_ast_node *expr = NULL;
struct token_parse_result result
= expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr);
if (result.r_status != IVY_OK) {
return result;
}
state->s_prev_token = IVY_KW_MATCH;
if (fx_queue_empty(&state->s_operator_stack)
&& fx_queue_empty(&state->s_output_queue)) {
parser_pop_state(ctx, 0);
}
/* if expr is NULL, this is an if-then-else-end statement,
* otherwise, this is an expr-if-else-expr. */
struct cond_group_parser_state *cond
= (struct cond_group_parser_state *)parser_push_state(
ctx, IVY_AST_MATCH, 0);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
struct token_parse_result stmt_parse_if(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (expr_terminates_at_token(state, IVY_KW_IF)) {
/* treat this as a statement terminator. */
struct token_parse_result result
= expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
if (state->s_sub_type == EXPR_SUBTYPE_KEYWORD_ARG) {
/* keyword messages have a higher precedence than inline
* conditionals, so treat this as a statement terminator. */
struct token_parse_result result
= expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
struct ivy_ast_node *expr = NULL;
struct token_parse_result result
= expr_finalise(ctx, state, IVY_PRECEDENCE_IF_ELSE, &expr);
if (result.r_status != IVY_OK) {
return result;
}
state->s_prev_token = IVY_KW_IF;
if (fx_queue_empty(&state->s_operator_stack)
&& fx_queue_empty(&state->s_output_queue)) {
parser_pop_state(ctx, 0);
}
/* if expr is NULL, this is an if-then-else-end statement,
* otherwise, this is an expr-if-else-expr. */
struct cond_group_parser_state *cond
= (struct cond_group_parser_state *)parser_push_state(
ctx, IVY_AST_COND_GROUP, (uintptr_t)expr);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
struct token_parse_result stmt_parse_then(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
/* treat this as a statement terminator. */
struct token_parse_result result = expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
struct token_parse_result stmt_parse_else(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
/* treat this as a statement terminator. */
struct token_parse_result result = expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
struct token_parse_result stmt_parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
/* treat this as a statement terminator. */
struct token_parse_result result = expr_finalise_and_return(ctx, state);
result.r_flags |= PARSE_REPEAT_TOKEN;
return result;
}
struct token_parse_result stmt_parse_break(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_prev_component != EXPR_CMP_NONE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
arith_push_operand(state, tok);
state->s_prev_component = EXPR_CMP_KEYWORD;
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result stmt_parse_continue(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_prev_component != EXPR_CMP_NONE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
arith_push_operand(state, tok);
state->s_prev_component = EXPR_CMP_KEYWORD;
return PARSE_RESULT(IVY_OK, 0);
}
+1 -262
View File
@@ -1,248 +1,5 @@
#include "block.h"
#include "expr/expr.h"
#include "iterate.h"
struct for_parser_state {
struct parser_state s_base;
bool s_inline;
unsigned int s_prev_token;
struct ivy_ast_node *s_body, *s_iterator, *s_iterable;
struct ivy_ast_node *s_prev_node;
};
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct for_parser_state *state = (struct for_parser_state *)sp;
state->s_prev_node = (struct ivy_ast_node *)arg;
}
struct token_parse_result parse_for(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct for_parser_state *state
= parser_get_state(ctx, struct for_parser_state);
if (state->s_prev_node) {
/* this is an inline for-loop */
state->s_inline = true;
state->s_body = state->s_prev_node;
state->s_prev_node = NULL;
} else {
state->s_inline = false;
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
state->s_prev_token = IVY_KW_FOR;
expr_add_terminator(expr, IVY_KW_IN);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_in(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct for_parser_state *state
= parser_get_state(ctx, struct for_parser_state);
if (state->s_prev_token != IVY_KW_FOR) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
/* previous component was the for iterator */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_iterator = state->s_prev_node;
state->s_prev_node = NULL;
/* next component will be the for iterable. */
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
/* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */
expr->s_subexpr_depth = 1;
expr_add_terminator(expr, IVY_KW_DO);
expr_add_terminator(expr, IVY_SYM_RIGHT_PAREN);
state->s_prev_token = IVY_KW_IN;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_do(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct for_parser_state *state
= parser_get_state(ctx, struct for_parser_state);
if (state->s_inline) {
struct ivy_diag *diag = parser_push_diag(
ctx, IVY_LANG_E_INCORRECT_INLINE_FOR_LOOP,
IVY_LANG_MSG_DO_UNEXPECTED_IN_INLINE_FOR, tok);
ivy_diag_push_msg(
diag, IVY_LANG_MSG_PREVIOUS_EXPRESSION_IS_FOR_BODY);
const struct ivy_char_cell *x = &state->s_body->n_end;
const struct ivy_char_cell *z = &tok->t_end;
const struct ivy_diag_amendment a[] = {
IVY_DIAG_ADD(x->c_row, x->c_col + 1, "."),
};
const size_t nr_a = sizeof a / sizeof a[0];
const struct ivy_diag_highlight hl[] = {
IVY_DIAG_HL(
HINT, x->c_row, x->c_col + 1, x->c_row,
x->c_col + 1),
};
const size_t nr_hl = sizeof hl / sizeof hl[0];
ivy_diag_push_snippet(diag, x->c_row, z->c_row, a, nr_a, hl, nr_hl);
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_IN) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
/* previous component was the for iterable. */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_iterable = state->s_prev_node;
state->s_prev_node = NULL;
/* next component will be a block. */
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_END);
state->s_prev_token = IVY_KW_DO;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_expr_begin(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct for_parser_state *state
= parser_get_state(ctx, struct for_parser_state);
if (state->s_prev_token != IVY_KW_DO) {
/* expression can only follow do keyword. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_END);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static enum ivy_status finalise_for_loop(struct for_parser_state *state)
{
struct ivy_ast_for_loop_node *loop
= (struct ivy_ast_for_loop_node *)state->s_base.s_node;
if (state->s_inline) {
/* we have just reached the end of the for iterable. */
if (!state->s_prev_node) {
/* for condition is empty. */
return IVY_ERR_BAD_SYNTAX;
}
state->s_iterable = state->s_prev_node;
state->s_prev_node = NULL;
loop->n_iterator = state->s_iterator;
loop->n_iterable = state->s_iterable;
loop->n_body = state->s_body;
state->s_iterator = NULL;
state->s_iterable = NULL;
state->s_body = NULL;
return IVY_OK;
}
if (!state->s_prev_node) {
/* for body is empty. */
return IVY_ERR_BAD_SYNTAX;
}
state->s_body = state->s_prev_node;
state->s_prev_node = NULL;
loop->n_iterator = state->s_iterator;
loop->n_iterable = state->s_iterable;
loop->n_body = state->s_body;
state->s_iterator = NULL;
state->s_iterable = NULL;
state->s_body = NULL;
return IVY_OK;
}
static struct token_parse_result parse_punct_terminator(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct for_parser_state *state
= parser_get_state(ctx, struct for_parser_state);
if (!state->s_inline) {
/* only inline for loop can be ended with punctuation. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_for_loop(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct for_parser_state *state
= parser_get_state(ctx, struct for_parser_state);
if (state->s_inline) {
/* inline for loop must be terminated with punctuation. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_for_loop(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct for_parser_state *state = (struct for_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
#include "node.h"
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
@@ -263,24 +20,6 @@ static void collect_children(
}
struct ast_node_type for_loop_node_ops = {
.n_init_state = init_state,
.n_add_child = add_child,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct for_parser_state),
.n_node_size = sizeof(struct ivy_ast_for_loop_node),
.n_keyword_parsers = {
KW_PARSER(FOR, parse_for),
KW_PARSER(IN, parse_in),
KW_PARSER(DO, parse_do),
KW_PARSER(END, parse_end),
},
.n_symbol_parsers = {
SYM_PARSER(DOT, parse_punct_terminator),
SYM_PARSER(COMMA, parse_punct_terminator),
SYM_PARSER(RIGHT_PAREN, parse_punct_terminator),
SYM_PARSER(BANG, parse_punct_terminator),
},
.n_expr_parser = {
.expr_begin = parse_expr_begin,
},
};
-111
View File
@@ -1,108 +1,8 @@
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "node.h"
#include <ivy/lang/ast.h>
struct global_parser_state {
struct parser_state s_base;
unsigned int s_prev_token;
};
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct global_parser_state *state = (struct global_parser_state *)sp;
state->s_prev_token = IVY_KW_GLOBAL;
}
struct token_parse_result parse_ident(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct global_parser_state *state
= parser_get_state(ctx, struct global_parser_state);
if (state->s_prev_token != IVY_KW_GLOBAL) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct expr_parser_state *ident_parse
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(ident_parse, IVY_SYM_EQUAL);
expr_add_terminator(ident_parse, IVY_SYM_DOT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
struct token_parse_result parse_left_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct global_parser_state *state
= parser_get_state(ctx, struct global_parser_state);
if (state->s_prev_token != IVY_KW_GLOBAL) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct expr_parser_state *tuple_ident_parse
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(tuple_ident_parse, IVY_SYM_EQUAL);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
struct token_parse_result parse_equal(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct global_parser_state *state
= parser_get_state(ctx, struct global_parser_state);
struct ivy_ast_global_node *global
= (struct ivy_ast_global_node *)state->s_base.s_node;
if (!global->n_left) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev_token = IVY_SYM_EQUAL;
struct expr_parser_state *val_parse
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(val_parse, IVY_SYM_DOT);
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_dot(struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct global_parser_state *state = (struct global_parser_state *)parent;
struct ivy_ast_global_node *global
= (struct ivy_ast_global_node *)parent->s_node;
switch (state->s_prev_token) {
case IVY_KW_GLOBAL:
if (global->n_left) {
return IVY_ERR_BAD_SYNTAX;
}
global->n_left = child;
break;
case IVY_SYM_EQUAL:
if (global->n_val) {
return IVY_ERR_BAD_SYNTAX;
}
global->n_val = child;
break;
default:
return IVY_ERR_BAD_SYNTAX;
}
return IVY_OK;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -118,17 +18,6 @@ static void collect_children(
}
struct ast_node_type global_node_ops = {
.n_add_child = add_child,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct global_parser_state),
.n_node_size = sizeof(struct ivy_ast_global_node),
.n_init_state = init_state,
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
},
.n_symbol_parsers = {
SYM_PARSER(LEFT_PAREN, parse_left_paren),
SYM_PARSER(EQUAL, parse_equal),
SYM_PARSER(DOT, parse_dot),
},
};
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
@@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
struct ast_node_type ident_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_ident_node),
};
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
@@ -14,6 +13,5 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
struct ast_node_type int_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_int_node),
};
-180
View File
@@ -1,180 +0,0 @@
#include "block.h"
#include "ctx.h"
#include "iterate.h"
#include "node.h"
#include <ivy/lang/lex.h>
struct lambda_parser_state {
struct parser_state s_base;
struct ivy_ast_node *s_prev_node;
unsigned int s_prev;
fx_queue s_args;
struct ivy_ast_node *s_body;
};
static struct token_parse_result parse_expr_begin(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct lambda_parser_state *state
= parser_get_state(ctx, struct lambda_parser_state);
if (state->s_prev != IVY_SYM_LEFT_BRACKET && state->s_prev != IVY_SYM_PIPE) {
/* unexpected expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_SYM_RIGHT_BRACKET);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct lambda_parser_state *state
= parser_get_state(ctx, struct lambda_parser_state);
if (state->s_prev == IVY_SYM_LEFT_BRACKET || state->s_prev == IVY_SYM_PIPE) {
return parse_expr_begin(ctx, tok);
}
if (state->s_prev != IVY_SYM_COLON) {
/* the only idents we're expecting are parameter names,
* which are always preceded with a colon */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct ivy_ast_ident_node *arg
= (struct ivy_ast_ident_node *)ast_node_create(IVY_AST_IDENT);
if (!arg) {
return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0);
}
arg->n_content = tok;
fx_queue_push_back(&state->s_args, &arg->n_base.n_entry);
state->s_prev = IVY_TOK_IDENT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_colon(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct lambda_parser_state *state
= parser_get_state(ctx, struct lambda_parser_state);
if (state->s_prev != IVY_SYM_LEFT_BRACKET
&& state->s_prev != IVY_TOK_IDENT) {
/* colons can only be used before arg names */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_COLON;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_pipe(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct lambda_parser_state *state
= parser_get_state(ctx, struct lambda_parser_state);
if (state->s_prev != IVY_TOK_IDENT) {
/* pipe can only be used after an arg name. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_PIPE;
return PARSE_RESULT(IVY_OK, 0);
}
static void finalise_lambda(struct lambda_parser_state *state)
{
struct ivy_ast_lambda_node *lambda
= (struct ivy_ast_lambda_node *)state->s_base.s_node;
lambda->n_arg = state->s_args;
lambda->n_body = state->s_body;
state->s_args = FX_QUEUE_INIT;
state->s_body = NULL;
}
static struct token_parse_result parse_right_bracket(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct lambda_parser_state *state
= parser_get_state(ctx, struct lambda_parser_state);
if (!state->s_prev_node) {
/* empty lambda */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_body = state->s_prev_node;
state->s_prev_node = NULL;
finalise_lambda(state);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct lambda_parser_state *state = (struct lambda_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct lambda_parser_state *state = (struct lambda_parser_state *)sp;
state->s_prev = IVY_SYM_LEFT_BRACKET;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
struct ivy_ast_lambda_node *lambda = (struct ivy_ast_lambda_node *)node;
fx_queue_entry *entry = fx_queue_first(&lambda->n_arg);
while (entry) {
struct ivy_ast_node *expr
= fx_unbox(struct ivy_ast_node, entry, n_entry);
ast_node_iterator_enqueue_node(iterator, node, expr);
entry = fx_queue_next(entry);
}
if (lambda->n_body) {
ast_node_iterator_enqueue_node(iterator, node, lambda->n_body);
}
}
struct ast_node_type lambda_node_ops = {
.n_add_child = add_child,
.n_init_state = init_state,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct lambda_parser_state),
.n_node_size = sizeof(struct ivy_ast_lambda_node),
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
},
.n_symbol_parsers = {
SYM_PARSER(RIGHT_BRACKET, parse_right_bracket),
SYM_PARSER(PIPE, parse_pipe),
SYM_PARSER(COLON, parse_colon),
},
.n_expr_parser = {
.expr_begin = parse_expr_begin,
},
};
+2 -4
View File
@@ -1,21 +1,19 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
static void to_string(struct ivy_ast_node *node, fx_string *str)
{
fx_string_append_cstrf(str, "%s", ivy_ast_node_type_to_string(node->n_type));
fx_string_append_cstrf(
str, "%s", ivy_ast_node_type_to_string(node->n_type));
}
struct ast_node_type loop_break_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_loop_break_node),
};
struct ast_node_type loop_repeat_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_loop_repeat_node),
};
+2 -269
View File
@@ -1,259 +1,5 @@
#include "block.h"
#include "expr/expr.h"
#include "iterate.h"
struct match_parser_state {
struct parser_state s_base;
unsigned int s_prev_token;
struct ivy_ast_node *s_cond;
struct ivy_ast_cond_node *s_cur_branch;
fx_queue s_branches;
struct ivy_ast_node *s_prev_node;
};
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct match_parser_state *state = (struct match_parser_state *)sp;
state->s_prev_node = (struct ivy_ast_node *)arg;
}
struct token_parse_result parse_match(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
if (state->s_cur_branch || state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch
= (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND);
if (!state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0);
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
state->s_prev_token = IVY_KW_MATCH;
expr->s_subexpr_depth = 1;
expr_add_terminator(expr, IVY_KW_IN);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status flush_current_branch(struct match_parser_state *state)
{
if (!state->s_cur_branch) {
return IVY_ERR_INTERNAL_FAILURE;
}
fx_queue_push_back(&state->s_branches, &state->s_cur_branch->n_base.n_entry);
state->s_cur_branch
= (struct ivy_ast_cond_node *)ast_node_create(IVY_AST_COND);
if (!state->s_cur_branch) {
return IVY_ERR_NO_MEMORY;
}
return IVY_OK;
}
struct token_parse_result parse_in(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
if (!state->s_cur_branch) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_MATCH) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
/* previous component was the match-condition. */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cond = state->s_prev_node;
state->s_prev_node = NULL;
/* next component will be a branch condition. */
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
state->s_prev_token = IVY_KW_IN;
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status finalise_match(struct match_parser_state *state)
{
struct ivy_ast_match_node *match
= (struct ivy_ast_match_node *)state->s_base.s_node;
/* we have just reached the 'end' keyword. */
if (!state->s_cur_branch) {
/* not currently parsing a conditional branch. */
return IVY_ERR_BAD_SYNTAX;
}
match->n_cond = state->s_cond;
match->n_branches = state->s_branches;
state->s_branches = FX_QUEUE_INIT;
return IVY_OK;
}
static struct token_parse_result parse_arrow(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
if (state->s_prev_token != IVY_KW_IN
&& state->s_prev_token != IVY_SYM_COMMA) {
/* this token can only appear after the `in` keyword and an expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_cond = state->s_prev_node;
state->s_prev_node = NULL;
state->s_prev_token = IVY_SYM_EQUAL_RIGHT_ANGLE;
/* the next component is the branch body */
#if 0
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_KW_END);
expr_add_terminator(expr, IVY_SYM_COMMA);
expr->s_subexpr_depth = 1;
#endif
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_comma(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) {
/* this token can only appear after the `=>` symbol and an expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_body = state->s_prev_node;
flush_current_branch(state);
state->s_prev_node = NULL;
state->s_prev_token = IVY_SYM_COMMA;
/* the next component is a branch condition */
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
/* end can only be used after the '=>' symbol and an expression */
if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cur_branch->n_body = state->s_prev_node;
flush_current_branch(state);
state->s_prev_node = NULL;
state->s_prev_token = IVY_KW_END;
enum ivy_status status = finalise_match(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_block(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_expr(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct match_parser_state *state
= parser_get_state(ctx, struct match_parser_state);
if (state->s_prev_token != IVY_SYM_EQUAL_RIGHT_ANGLE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
if (tok->t_type != IVY_TOK_KEYWORD) {
expr_add_terminator(expr, IVY_KW_END);
}
expr_add_terminator(expr, IVY_SYM_COMMA);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct match_parser_state *state = (struct match_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
#include "node.h"
static void match_collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
@@ -267,24 +13,11 @@ static void match_collect_children(
struct ivy_ast_node *branch
= fx_unbox(struct ivy_ast_node, entry, n_entry);
ast_node_iterator_enqueue_node(iterator, node, branch);
entry = fx_queue_next(entry);
}
}
struct ast_node_type match_node_ops = {
.n_init_state = init_state,
.n_add_child = add_child,
.n_collect_children = match_collect_children,
.n_state_size = sizeof(struct match_parser_state),
.n_node_size = sizeof(struct ivy_ast_match_node),
.n_expr_parser = parse_expr,
.n_keyword_parsers = {
KW_PARSER(MATCH, parse_match),
KW_PARSER(IN, parse_in),
KW_PARSER(END, parse_end),
KW_PARSER(DO, parse_block),
},
.n_symbol_parsers = {
SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_arrow),
SYM_PARSER(COMMA, parse_comma),
},
};
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "iterate.h"
#include "node.h"
@@ -27,6 +26,5 @@ static void collect_children(
struct ast_node_type msg_node_ops = {
.n_collect_children = collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_msg_node),
};
-112
View File
@@ -1,5 +1,4 @@
#include "block.h"
#include "ctx.h"
#include "iterate.h"
#include "ivy/status.h"
#include "node.h"
@@ -7,107 +6,6 @@
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
struct msgh_parser_state {
struct parser_state s_base;
bool s_oneline;
unsigned int s_i;
unsigned int s_prev;
};
static struct token_parse_result parse_linefeed(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct msgh_parser_state *state
= parser_get_state(ctx, struct msgh_parser_state);
struct ivy_ast_msgh_node *msgh
= (struct ivy_ast_msgh_node *)state->s_base.s_node;
if (state->s_oneline) {
if (msgh->n_body) {
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!msgh->n_sel) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct block_parser_state *block_state
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block_state, IVY_SYM_BANG);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_bang(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct msgh_parser_state *state
= parser_get_state(ctx, struct msgh_parser_state);
struct ivy_ast_msgh_node *msgh
= (struct ivy_ast_msgh_node *)state->s_base.s_node;
if (!msgh->n_sel || state->s_oneline) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_pipe(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct msgh_parser_state *state
= parser_get_state(ctx, struct msgh_parser_state);
struct ivy_ast_msgh_node *msgh
= (struct ivy_ast_msgh_node *)state->s_base.s_node;
if (!msgh->n_sel || state->s_oneline) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_oneline = true;
parser_push_state(ctx, IVY_AST_EXPR, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct ivy_ast_msgh_node *msgh = (struct ivy_ast_msgh_node *)parent->s_node;
if (child->n_type == IVY_AST_SELECTOR && !msgh->n_sel) {
msgh->n_sel = (struct ivy_ast_selector_node *)child;
return IVY_OK;
}
if (!msgh->n_body) {
msgh->n_body = child;
return IVY_OK;
}
return IVY_OK;
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct msgh_parser_state *state = (struct msgh_parser_state *)sp;
state->s_oneline = false;
state->s_i = 0;
state->s_prev = IVY_SYM_HYPHEN;
parser_push_state(ctx, IVY_AST_SELECTOR, 0);
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -117,16 +15,6 @@ static void collect_children(
}
struct ast_node_type msgh_node_ops = {
.n_add_child = add_child,
.n_init_state = init_state,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct msgh_parser_state),
.n_node_size = sizeof(struct ivy_ast_msgh_node),
.n_token_parsers = {
TOK_PARSER(LINEFEED, parse_linefeed),
},
.n_symbol_parsers = {
SYM_PARSER(BANG, parse_bang),
SYM_PARSER(PIPE, parse_pipe),
},
};
+3 -138
View File
@@ -12,9 +12,9 @@ extern struct ast_node_type unit_import_node_ops;
extern struct ast_node_type class_node_ops;
extern struct ast_node_type msgh_node_ops;
extern struct ast_node_type selector_node_ops;
extern struct ast_node_type expr_node_ops;
extern struct ast_node_type block_node_ops;
extern struct ast_node_type msg_node_ops;
extern struct ast_node_type do_node_ops;
extern struct ast_node_type op_node_ops;
extern struct ast_node_type global_node_ops;
extern struct ast_node_type ident_node_ops;
@@ -34,8 +34,6 @@ extern struct ast_node_type loop_break_node_ops;
extern struct ast_node_type loop_repeat_node_ops;
extern struct ast_node_type return_node_ops;
extern struct ast_node_type property_node_ops;
extern struct ast_node_type lambda_node_ops;
extern struct ast_node_type pkg_node_ops;
extern struct ast_node_type pkg_static_node_ops;
extern struct ast_node_type pkg_static_item_node_ops;
extern struct ast_node_type pkg_dynamic_node_ops;
@@ -53,9 +51,9 @@ static const struct ast_node_type *node_ops[] = {
[IVY_AST_CLASS] = &class_node_ops,
[IVY_AST_MSGH] = &msgh_node_ops,
[IVY_AST_SELECTOR] = &selector_node_ops,
[IVY_AST_EXPR] = &expr_node_ops,
[IVY_AST_BLOCK] = &block_node_ops,
[IVY_AST_MSG] = &msg_node_ops,
[IVY_AST_DO] = &do_node_ops,
[IVY_AST_OP] = &op_node_ops,
[IVY_AST_GLOBAL] = &global_node_ops,
[IVY_AST_IDENT] = &ident_node_ops,
@@ -75,8 +73,6 @@ static const struct ast_node_type *node_ops[] = {
[IVY_AST_LOOP_REPEAT] = &loop_repeat_node_ops,
[IVY_AST_RETURN] = &return_node_ops,
[IVY_AST_PROPERTY] = &property_node_ops,
[IVY_AST_LAMBDA] = &lambda_node_ops,
[IVY_AST_PKG] = &pkg_node_ops,
[IVY_AST_PKG_STATIC] = &pkg_static_node_ops,
[IVY_AST_PKG_ITEM] = &pkg_static_item_node_ops,
[IVY_AST_PKG_DYNAMIC] = &pkg_dynamic_node_ops,
@@ -98,135 +94,6 @@ const struct ast_node_type *get_ast_node_type(enum ivy_ast_node_type type)
return node_ops[type];
}
enum token_expr_type get_token_expr_type(struct ivy_token *tok)
{
const struct ivy_operator *op = NULL;
switch (tok->t_type) {
case IVY_TOK_IDENT:
case IVY_TOK_INT:
case IVY_TOK_DOUBLE:
case IVY_TOK_STRING:
case IVY_TOK_STR_START:
case IVY_TOK_ATOM:
return TOK_EXPR_BEGIN;
case IVY_TOK_SYMBOL:
switch (tok->t_symbol) {
case IVY_SYM_LEFT_PAREN:
case IVY_SYM_LEFT_BRACKET:
case IVY_SYM_LEFT_BRACE:
case IVY_SYM_CARET:
case IVY_SYM_UNDERSCORE:
return TOK_EXPR_BEGIN;
case IVY_SYM_COMMA:
return TOK_EXPR_ANY;
default:
op = ivy_operator_get_by_token(tok->t_symbol);
return op ? TOK_EXPR_ANY : TOK_EXPR_NONE;
}
case IVY_TOK_KEYWORD:
switch (tok->t_keyword) {
case IVY_KW_IF:
case IVY_KW_ELSE:
case IVY_KW_MATCH:
case IVY_KW_FOR:
case IVY_KW_WHILE:
case IVY_KW_BREAK:
case IVY_KW_CONTINUE:
case IVY_KW_TRY:
case IVY_KW_THROW:
case IVY_KW_TRUE:
case IVY_KW_FALSE:
case IVY_KW_NULL:
return TOK_EXPR_BEGIN;
default:
op = ivy_operator_get_by_token(tok->t_keyword);
return op ? TOK_EXPR_ANY : TOK_EXPR_NONE;
return TOK_EXPR_NONE;
}
default:
return TOK_EXPR_NONE;
}
}
token_parse_function get_token_parser(
struct ivy_ast_node *context, struct ivy_token *tok)
{
token_parse_function type_parser = NULL;
token_parse_function type_fallback_parser = NULL;
token_parse_function token_parser = NULL;
token_parse_function expr_begin_parser = NULL;
token_parse_function expr_other_parser = NULL;
token_parse_function expr_parser = NULL;
token_parse_function token_fallback_parser = NULL;
const struct ast_node_type *type = get_ast_node_type(context->n_type);
if (!type) {
return NULL;
}
token_parser = type->n_token_parsers[__TOK_PARSER_INDEX(tok->t_type)];
token_fallback_parser = type->n_token_parsers[__TOK_PARSER_FALLBACK_INDEX];
token_parse_function better_parser = NULL;
switch (tok->t_type) {
case IVY_TOK_KEYWORD:
type_parser
= type->n_keyword_parsers[__KW_PARSER_INDEX(tok->t_keyword)];
if (type->n_keyword_parsers[__KW_PARSER_FALLBACK_INDEX]) {
type_fallback_parser
= type->n_keyword_parsers[__KW_PARSER_FALLBACK_INDEX];
}
break;
case IVY_TOK_SYMBOL:
type_parser
= type->n_symbol_parsers[__SYM_PARSER_INDEX(tok->t_symbol)];
if (type->n_symbol_parsers[__SYM_PARSER_FALLBACK_INDEX]) {
type_fallback_parser
= type->n_symbol_parsers[__SYM_PARSER_FALLBACK_INDEX];
}
break;
default:
break;
}
enum token_expr_type expr_type = get_token_expr_type(tok);
switch (expr_type) {
case TOK_EXPR_BEGIN:
expr_begin_parser = type->n_expr_parser.expr_begin;
expr_parser = type->n_expr_parser.expr_all;
break;
case TOK_EXPR_ANY:
expr_other_parser = type->n_expr_parser.expr_other;
expr_parser = type->n_expr_parser.expr_all;
break;
default:
break;
}
bool token_has_sub_id
= (tok->t_type == IVY_TOK_KEYWORD || tok->t_type == IVY_TOK_SYMBOL);
if (type_parser)
return type_parser;
if (token_parser && !token_has_sub_id)
return token_parser;
if (expr_begin_parser)
return expr_begin_parser;
if (expr_other_parser)
return expr_other_parser;
if (expr_parser)
return expr_parser;
if (type_fallback_parser)
return type_fallback_parser;
if (token_parser && token_has_sub_id)
return token_parser;
if (token_fallback_parser)
return token_fallback_parser;
return NULL;
}
struct ivy_ast_node *ivy_ast_node_create(enum ivy_ast_node_type type)
{
return ast_node_create(type);
@@ -352,13 +219,12 @@ const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v)
ENUM_STR(IVY_AST_NONE);
ENUM_STR(IVY_AST_UNIT);
ENUM_STR(IVY_AST_OP);
ENUM_STR(IVY_AST_DO);
ENUM_STR(IVY_AST_MSG);
ENUM_STR(IVY_AST_CLASS);
ENUM_STR(IVY_AST_MSGH);
ENUM_STR(IVY_AST_PROPERTY);
ENUM_STR(IVY_AST_SELECTOR);
ENUM_STR(IVY_AST_EXPR);
ENUM_STR(IVY_AST_LAMBDA);
ENUM_STR(IVY_AST_UNIT_PACKAGE);
ENUM_STR(IVY_AST_UNIT_IMPORT);
ENUM_STR(IVY_AST_DISCARD);
@@ -379,7 +245,6 @@ const char *ivy_ast_node_type_to_string(enum ivy_ast_node_type v)
ENUM_STR(IVY_AST_COND);
ENUM_STR(IVY_AST_TUPLE);
ENUM_STR(IVY_AST_BLOCK);
ENUM_STR(IVY_AST_PKG);
ENUM_STR(IVY_AST_PKG_STATIC);
ENUM_STR(IVY_AST_PKG_ITEM);
ENUM_STR(IVY_AST_PKG_DYNAMIC);
-54
View File
@@ -5,71 +5,17 @@
#include <ivy/lang/ast.h>
#include <ivy/lang/lex.h>
struct parser_state;
#define PARSE_RESULT(status, flags) \
((struct token_parse_result) {.r_status = (status), .r_flags = (flags)})
#define __TOK_PARSER_INDEX(x) ((x) - __IVY_TOK_INDEX_BASE)
#define __SYM_PARSER_INDEX(x) ((x) - __IVY_SYM_INDEX_BASE)
#define __KW_PARSER_INDEX(x) ((x) - __IVY_KW_INDEX_BASE)
#define __TOK_PARSER_FALLBACK_INDEX IVY_TOK_NONE
#define __SYM_PARSER_FALLBACK_INDEX IVY_SYM_NONE
#define __KW_PARSER_FALLBACK_INDEX IVY_KW_NONE
#define TOK_PARSER(id, func) [__TOK_PARSER_INDEX(IVY_TOK_##id)] = func
#define SYM_PARSER(id, func) [__SYM_PARSER_INDEX(IVY_SYM_##id)] = func
#define KW_PARSER(id, func) [__KW_PARSER_INDEX(IVY_KW_##id)] = func
#define TOK_PARSER_FALLBACK(func) [__TOK_PARSER_FALLBACK_INDEX] = func
#define SYM_PARSER_FALLBACK(func) [__SYM_PARSER_FALLBACK_INDEX] = func
#define KW_PARSER_FALLBACK(func) [__KW_PARSER_FALLBACK_INDEX] = func
enum token_parse_flags {
PARSE_REPEAT_TOKEN = 0x01u,
};
enum token_expr_type {
TOK_EXPR_NONE = 0,
TOK_EXPR_BEGIN,
TOK_EXPR_ANY,
};
struct token_parse_result {
enum ivy_status r_status;
enum token_parse_flags r_flags;
};
typedef struct token_parse_result (*token_parse_function)(
struct ivy_parser *, struct ivy_token *);
struct ast_node_type {
enum ivy_status (*n_add_child)(
struct parser_state *, struct ivy_ast_node *);
void (*n_to_string)(struct ivy_ast_node *, fx_string *);
void (*n_init_state)(struct ivy_parser *, struct parser_state *, uintptr_t);
void (*n_collect_children)(
struct ivy_ast_node *, struct ivy_ast_node_iterator *);
void (*n_destroy)(struct ivy_ast_node *);
size_t n_state_size;
size_t n_node_size;
token_parse_function n_token_parsers[__TOK_PARSER_INDEX(__IVY_TOK_INDEX_LIMIT)];
token_parse_function n_keyword_parsers[__KW_PARSER_INDEX(__IVY_KW_INDEX_LIMIT)];
token_parse_function n_symbol_parsers[__SYM_PARSER_INDEX(__IVY_SYM_INDEX_LIMIT)];
struct {
token_parse_function expr_begin;
token_parse_function expr_other;
token_parse_function expr_all;
} n_expr_parser;
};
extern const struct ast_node_type *get_ast_node_type(enum ivy_ast_node_type type);
extern token_parse_function get_token_parser(
struct ivy_ast_node *context, struct ivy_token *tok);
extern enum token_expr_type get_token_expr_type(struct ivy_token *tok);
extern struct ivy_ast_node *ast_node_create(enum ivy_ast_node_type type);
extern enum ivy_status ast_node_add_child(
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "iterate.h"
#include "node.h"
@@ -30,6 +29,5 @@ static void collect_children(
struct ast_node_type op_node_ops = {
.n_to_string = to_string,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_op_node),
};
-399
View File
@@ -1,373 +1,10 @@
#include "block.h"
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "node.h"
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
enum package_type {
PACKAGE_NONE = 0,
/* package constructed using a list of key-value pairs. */
PACKAGE_STATIC,
/* package constructed using an (X for X in Y if Z) pattern. */
PACKAGE_DYNAMIC,
};
struct package_parser_state {
struct parser_state s_base;
enum package_type s_type;
struct ivy_ast_node *s_prev_node;
unsigned int s_prev;
/* only used for PACKAGE_STATIC */
fx_queue s_items;
struct ivy_ast_node *s_next_index;
unsigned int s_next_implicit_index;
/* only used for PACKAGE_DYNAMIC */
struct ivy_ast_node *s_transform;
struct ivy_ast_node *s_item;
struct ivy_ast_node *s_source;
struct ivy_ast_node *s_cond;
};
static enum ivy_status add_package_item(
struct package_parser_state *state, struct ivy_ast_node *index,
struct ivy_ast_node *value)
{
struct ivy_ast_pkg_static_item_node *item
= (struct ivy_ast_pkg_static_item_node *)ast_node_create(
IVY_AST_PKG_ITEM);
if (!item) {
return IVY_ERR_NO_MEMORY;
}
item->n_value = value;
if (index) {
item->n_index = index;
} else {
item->n_implicit_index = state->s_next_implicit_index++;
}
fx_queue_push_back(&state->s_items, &item->n_base.n_entry);
state->s_next_index = NULL;
state->s_prev_node = NULL;
return IVY_OK;
}
static struct ivy_ast_node *finalise_package(struct package_parser_state *state)
{
struct ivy_ast_pkg_static_node *s = NULL;
struct ivy_ast_pkg_dynamic_node *d = NULL;
switch (state->s_type) {
case PACKAGE_STATIC:
s = (struct ivy_ast_pkg_static_node *)ast_node_create(
IVY_AST_PKG_STATIC);
if (!s) {
return NULL;
}
s->n_items = state->s_items;
state->s_items = FX_QUEUE_INIT;
return (struct ivy_ast_node *)s;
case PACKAGE_DYNAMIC:
d = (struct ivy_ast_pkg_dynamic_node *)ast_node_create(
IVY_AST_PKG_DYNAMIC);
if (!d) {
return NULL;
}
d->n_transform = state->s_transform;
d->n_item = state->s_item;
d->n_source = state->s_source;
d->n_cond = state->s_cond;
state->s_transform = NULL;
state->s_item = NULL;
state->s_source = NULL;
state->s_cond = NULL;
return (struct ivy_ast_node *)d;
default:
return NULL;
}
}
static struct token_parse_result parse_equal_right_angle(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct package_parser_state *state
= parser_get_state(ctx, struct package_parser_state);
if (state->s_type == PACKAGE_NONE) {
state->s_type = PACKAGE_STATIC;
}
if (state->s_type != PACKAGE_STATIC) {
/* this token cannot be used in this context. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA) {
/* token unexpected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty index expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_EQUAL_RIGHT_ANGLE;
state->s_next_index = state->s_prev_node;
state->s_prev_node = NULL;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_COMMA);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_comma(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct package_parser_state *state
= parser_get_state(ctx, struct package_parser_state);
if (state->s_type == PACKAGE_NONE) {
state->s_type = PACKAGE_STATIC;
}
if (state->s_type != PACKAGE_STATIC) {
/* this token cannot be used in this context. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA
&& state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) {
/* token unexpected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty value expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = add_package_item(
state, state->s_next_index, state->s_prev_node);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
state->s_prev = IVY_SYM_COMMA;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_EQUAL_RIGHT_ANGLE);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_right_brace(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct package_parser_state *state
= parser_get_state(ctx, struct package_parser_state);
if (state->s_type == PACKAGE_NONE) {
state->s_type = PACKAGE_STATIC;
}
enum ivy_status status = IVY_OK;
switch (state->s_type) {
case PACKAGE_STATIC:
if (state->s_prev != IVY_SYM_LEFT_BRACE && state->s_prev != IVY_SYM_COMMA
&& state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) {
/* token unexpected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_node) {
status = add_package_item(
state, state->s_next_index, state->s_prev_node);
}
break;
case PACKAGE_DYNAMIC:
if (!state->s_prev_node) {
/* empty expression */
status = IVY_ERR_BAD_SYNTAX;
break;
}
switch (state->s_prev) {
case IVY_KW_IN:
state->s_source = state->s_prev_node;
break;
case IVY_KW_IF:
state->s_cond = state->s_prev_node;
break;
default:
/* token unexpected at this time. */
status = IVY_ERR_BAD_SYNTAX;
break;
}
break;
default:
/* not sure how we got here. */
status = IVY_ERR_INTERNAL_FAILURE;
break;
}
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
struct ivy_ast_node *pkg = finalise_package(state);
if (!pkg) {
return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0);
}
parser_replace_current_node(ctx, pkg);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_for(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct package_parser_state *state
= parser_get_state(ctx, struct package_parser_state);
if (state->s_type == PACKAGE_NONE) {
state->s_type = PACKAGE_DYNAMIC;
}
if (state->s_type != PACKAGE_DYNAMIC) {
/* this token cannot be used in this context. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_SYM_LEFT_BRACE) {
/* token unexpected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_KW_FOR;
state->s_transform = state->s_prev_node;
state->s_prev_node = NULL;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_KW_IN);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_in(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct package_parser_state *state
= parser_get_state(ctx, struct package_parser_state);
if (state->s_type != PACKAGE_DYNAMIC) {
/* this token cannot be used in this context. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_KW_FOR) {
/* token unexpected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_KW_IN;
state->s_item = state->s_prev_node;
state->s_prev_node = NULL;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_KW_IF);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_if(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct package_parser_state *state
= parser_get_state(ctx, struct package_parser_state);
if (state->s_type != PACKAGE_DYNAMIC) {
/* this token cannot be used in this context. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_KW_IN) {
/* token unexpected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_KW_IF;
state->s_source = state->s_prev_node;
state->s_prev_node = NULL;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_RIGHT_BRACE);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct package_parser_state *state = (struct package_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
static void pkg_static_collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -433,54 +70,18 @@ static void pkg_dynamic_collect_children(
}
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct package_parser_state *state = (struct package_parser_state *)sp;
state->s_type = PACKAGE_NONE;
state->s_prev = IVY_SYM_LEFT_BRACE;
state->s_next_implicit_index = 0;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_KW_FOR);
expr->s_subexpr_depth = 1;
}
struct ast_node_type pkg_node_ops = {
.n_init_state = init_state,
.n_add_child = add_child,
.n_state_size = sizeof(struct package_parser_state),
/* placeholder node, will be replaced with either ivy_ast_pkg_static_node
* or ivy_ast_pkg_dynamic_node when finished. */
.n_node_size = sizeof(struct ivy_ast_node),
.n_keyword_parsers = {
KW_PARSER(FOR, parse_for),
KW_PARSER(IN, parse_in),
KW_PARSER(IF, parse_if),
},
.n_symbol_parsers = {
SYM_PARSER(COMMA, parse_comma),
SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_equal_right_angle),
SYM_PARSER(RIGHT_BRACE, parse_right_brace),
},
};
struct ast_node_type pkg_static_node_ops = {
.n_collect_children = pkg_static_collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_pkg_static_node),
};
struct ast_node_type pkg_static_item_node_ops = {
.n_to_string = pkg_static_item_to_string,
.n_collect_children = pkg_static_item_collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_pkg_static_item_node),
};
struct ast_node_type pkg_dynamic_node_ops = {
.n_collect_children = pkg_dynamic_collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_pkg_dynamic_node),
};
-368
View File
@@ -1,8 +1,4 @@
#include "block.h"
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "ivy/status.h"
#include "node.h"
#include <fx/ds/string.h>
@@ -11,352 +7,6 @@
#define PROPERTY_TYPE(flags) (flags & (PROPERTY_FULL | PROPERTY_AUTO))
enum property_flags {
PROPERTY_NONE = 0x00u,
/* a property defined across multiple lines using get/set => syntax */
PROPERTY_FULL = 0x01u,
/* a property defined across a single line lines (get, set) syntax */
PROPERTY_AUTO = 0x02u,
/* property has getter defined. */
PROPERTY_GET = 0x04u,
/* property has setter defined. */
PROPERTY_SET = 0x08u,
};
struct property_parser_state {
struct parser_state s_base;
enum property_flags s_flags;
struct ivy_ast_node *s_prev_node;
struct ivy_token *s_ident;
struct ivy_ast_node *s_get, *s_set;
/* one of either 0, PROPERTY_GET, or PROPERTY_SET, depending on which
* part of the property is currently being parsed. */
unsigned int s_cur_component;
unsigned int s_prev;
};
static void finalise_property(struct property_parser_state *state)
{
struct ivy_ast_property_node *prop
= (struct ivy_ast_property_node *)state->s_base.s_node;
if (state->s_flags & PROPERTY_GET) {
prop->n_flags |= IVY_AST_PROPERTY_GET;
}
if (state->s_flags & PROPERTY_SET) {
prop->n_flags |= IVY_AST_PROPERTY_SET;
}
prop->n_ident = state->s_ident;
prop->n_get = state->s_get;
prop->n_set = state->s_set;
state->s_ident = NULL;
state->s_get = NULL;
state->s_set = NULL;
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (state->s_prev != IVY_SYM_DOLLAR) {
/* the only ident we're looking for is the property name, which
* can only occur after the $ symbol. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_ident = tok;
state->s_prev = IVY_TOK_IDENT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_pipe(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (state->s_prev != IVY_TOK_IDENT) {
/* the only pipe we're looking for is the property
* name/implementation separator, which can only occur after
* the property name. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (PROPERTY_TYPE(state->s_flags) != PROPERTY_NONE) {
/* we've already determined what kind of syntax is being used
* to define this property (which is what the pipe symbol is
* for). */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_PIPE;
state->s_flags |= PROPERTY_FULL;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_left_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (state->s_prev != IVY_TOK_IDENT) {
/* the only left paren we're looking for comes after the
* property name */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (PROPERTY_TYPE(state->s_flags) != PROPERTY_NONE) {
/* we've already determined what kind of syntax is being used
* to define this property (which is what this symbol is
* for). */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_LEFT_PAREN;
state->s_flags |= PROPERTY_AUTO;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_right_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (PROPERTY_TYPE(state->s_flags) != PROPERTY_AUTO) {
/* can only use parenthesis in auto-properties. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_KW_GET && state->s_prev != IVY_KW_SET) {
/* the only left paren we're looking for comes after an expression */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if ((state->s_flags & (PROPERTY_GET | PROPERTY_SET)) == 0) {
/* auto-property with neither a getter nor a setter. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
finalise_property(state);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_equal_right_arrow(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (PROPERTY_TYPE(state->s_flags) != PROPERTY_FULL) {
/* this symbol cannot be used in auto-properties. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_KW_GET && state->s_prev != IVY_KW_SET) {
/* this symbol can only be used after get or set */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_EQUAL_RIGHT_ANGLE;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_COMMA);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_comma(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (PROPERTY_TYPE(state->s_flags) == PROPERTY_FULL
&& state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) {
/* this symbol can only be used after get or set */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_cur_component != PROPERTY_GET
&& state->s_cur_component != PROPERTY_SET) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_COMMA;
if (PROPERTY_TYPE(state->s_flags) == PROPERTY_AUTO) {
state->s_cur_component = 0;
return PARSE_RESULT(IVY_OK, 0);
}
if (!state->s_prev_node) {
/* empty getter/setter expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
switch (state->s_cur_component) {
case PROPERTY_GET:
state->s_get = state->s_prev_node;
break;
case PROPERTY_SET:
state->s_set = state->s_prev_node;
break;
default:
/* this case is handled at the start of this function. */
break;
}
state->s_cur_component = 0;
state->s_prev_node = NULL;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_dot(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (PROPERTY_TYPE(state->s_flags) != PROPERTY_FULL) {
/* this symbol cannot be used in auto-properties. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_cur_component != PROPERTY_GET
&& state->s_cur_component != PROPERTY_SET) {
/* not actually parsing a getter or setter */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_SYM_EQUAL_RIGHT_ANGLE) {
/* this symbol can only be used after => and an expression */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty expression. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
switch (state->s_cur_component) {
case PROPERTY_GET:
state->s_get = state->s_prev_node;
break;
case PROPERTY_SET:
state->s_set = state->s_prev_node;
break;
default:
/* this case is handled at the start of this function. */
break;
}
state->s_cur_component = 0;
finalise_property(state);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_get(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (state->s_flags & PROPERTY_GET) {
/* property already has getter defined */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (PROPERTY_TYPE(state->s_flags) == PROPERTY_FULL
&& state->s_prev != IVY_SYM_PIPE && state->s_prev != IVY_SYM_COMMA) {
/* getter is not expected here. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (PROPERTY_TYPE(state->s_flags) == PROPERTY_AUTO
&& state->s_prev != IVY_SYM_LEFT_PAREN
&& state->s_prev != IVY_SYM_COMMA) {
/* getter is not expected here. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_flags |= PROPERTY_GET;
state->s_cur_component = PROPERTY_GET;
state->s_prev = IVY_KW_GET;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_set(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct property_parser_state *state
= parser_get_state(ctx, struct property_parser_state);
if (state->s_flags & PROPERTY_SET) {
/* property already has setter defined */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (PROPERTY_TYPE(state->s_flags) == PROPERTY_FULL
&& state->s_prev != IVY_SYM_PIPE && state->s_prev != IVY_SYM_COMMA) {
/* setter is not expected here. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (PROPERTY_TYPE(state->s_flags) == PROPERTY_AUTO
&& state->s_prev != IVY_SYM_LEFT_PAREN
&& state->s_prev != IVY_SYM_COMMA) {
/* setter is not expected here. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_flags |= PROPERTY_SET;
state->s_cur_component = PROPERTY_SET;
state->s_prev = IVY_KW_SET;
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct property_parser_state *state
= (struct property_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct property_parser_state *state = (struct property_parser_state *)sp;
state->s_flags = PROPERTY_NONE;
state->s_prev = IVY_SYM_DOLLAR;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -397,24 +47,6 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
struct ast_node_type property_node_ops = {
.n_to_string = to_string,
.n_add_child = add_child,
.n_init_state = init_state,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct property_parser_state),
.n_node_size = sizeof(struct ivy_ast_property_node),
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
},
.n_keyword_parsers = {
KW_PARSER(GET, parse_get),
KW_PARSER(SET, parse_set),
},
.n_symbol_parsers = {
SYM_PARSER(PIPE, parse_pipe),
SYM_PARSER(EQUAL_RIGHT_ANGLE, parse_equal_right_arrow),
SYM_PARSER(COMMA, parse_comma),
SYM_PARSER(DOT, parse_dot),
SYM_PARSER(LEFT_PAREN, parse_left_paren),
SYM_PARSER(RIGHT_PAREN, parse_right_paren),
},
};
-2
View File
@@ -1,4 +1,3 @@
#include "ctx.h"
#include "iterate.h"
#include "node.h"
@@ -14,6 +13,5 @@ static void collect_children(
struct ast_node_type return_node_ops = {
.n_collect_children = collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_return_node),
};
+1 -241
View File
@@ -1,228 +1,9 @@
#include "ctx.h"
#include "ivy/status.h"
#include "node.h"
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
#include <stdio.h>
struct selector_parser_state {
struct parser_state s_base;
unsigned int s_prev;
bool s_complete;
};
#define CHECK_SELECTOR_COMPLETE() \
do { \
if (state->s_complete) { \
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT); \
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN); \
} \
} while (0)
static struct token_parse_result parse_plus(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
if (sel->n_recipient != IVY_SELECTOR_RECIPIENT_NONE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
sel->n_recipient = IVY_SELECTOR_RECIPIENT_CLASS;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_hyphen(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
if (sel->n_recipient != IVY_SELECTOR_RECIPIENT_NONE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
sel->n_recipient = IVY_SELECTOR_RECIPIENT_OBJECT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
CHECK_SELECTOR_COMPLETE();
if (state->s_prev == 0) {
/* message name */
sel->n_msg_name = tok;
state->s_prev = IVY_TOK_IDENT;
state->s_complete = true;
return PARSE_RESULT(IVY_OK, 0);
}
if (state->s_prev == IVY_TOK_LABEL) {
/* internal parameter name */
fx_queue_push_back(&sel->n_arg_names, &tok->t_entry);
state->s_prev = IVY_TOK_IDENT;
state->s_complete = true;
return PARSE_RESULT(IVY_OK, 0);
}
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
static struct token_parse_result parse_label(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
if (sel->n_recipient == IVY_SELECTOR_RECIPIENT_NONE
&& state->s_prev != IVY_TOK_IDENT
&& state->s_prev != IVY_SYM_LEFT_PAREN) {
/* if recipient is not NONE, this selector appears at the beginning of a message
* handler. only then is a label without a preceding identifier allowed. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
fx_queue_push_back(&sel->n_arg_labels, &tok->t_entry);
state->s_prev = IVY_TOK_LABEL;
state->s_complete = false;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_linefeed(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
CHECK_SELECTOR_COMPLETE();
if (!fx_queue_empty(&sel->n_arg_labels)
&& state->s_prev != IVY_SYM_RIGHT_PAREN) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev != IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
state->s_prev = IVY_TOK_LINEFEED;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_left_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
if (state->s_prev != IVY_TOK_IDENT || !fx_queue_empty(&sel->n_arg_labels)) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_LEFT_PAREN;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_right_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
if (state->s_prev != IVY_TOK_IDENT || fx_queue_empty(&sel->n_arg_labels)) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev = IVY_SYM_RIGHT_PAREN;
state->s_complete = true;
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_pipe(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
switch (state->s_prev) {
case IVY_SYM_RIGHT_PAREN:
/* this looks like a complex message selector */
if (fx_queue_empty(&sel->n_arg_labels)
|| fx_queue_empty(&sel->n_arg_names)) {
/* no message args */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!sel->n_msg_name) {
/* no message name */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
break;
case IVY_TOK_IDENT:
/* this looks like a unary or keyword message. */
if (!fx_queue_empty(&sel->n_arg_labels)
&& fx_queue_empty(&sel->n_arg_names)) {
/* keyword message with no arg names. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
break;
default:
/* not sure what we're parsing. unknown token at end of selector. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_other(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct selector_parser_state *state
= parser_get_state(ctx, struct selector_parser_state);
struct ivy_ast_selector_node *sel
= (struct ivy_ast_selector_node *)state->s_base.s_node;
CHECK_SELECTOR_COMPLETE();
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
static void to_string(struct ivy_ast_node *node, fx_string *str)
{
struct ivy_ast_selector_node *sel = (struct ivy_ast_selector_node *)node;
@@ -291,28 +72,7 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
fx_string_append_cstr(str, "]");
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct selector_parser_state *state = (struct selector_parser_state *)sp;
state->s_prev = 0;
state->s_complete = false;
}
struct ast_node_type selector_node_ops = {
.n_init_state = init_state,
.n_to_string = to_string,
.n_state_size = sizeof(struct selector_parser_state),
.n_node_size = sizeof(struct ivy_ast_selector_node),
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
TOK_PARSER(LABEL, parse_label),
TOK_PARSER_FALLBACK(parse_other),
},
.n_symbol_parsers = {
SYM_PARSER(PLUS, parse_plus),
SYM_PARSER(HYPHEN, parse_hyphen),
SYM_PARSER(LEFT_PAREN, parse_left_paren),
SYM_PARSER(RIGHT_PAREN, parse_right_paren),
SYM_PARSER(PIPE, parse_pipe),
},
.n_node_size = sizeof(struct ivy_ast_selector_node),
};
-64
View File
@@ -1,5 +1,3 @@
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "node.h"
@@ -13,57 +11,6 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
s->n_value->t_str);
}
struct token_parse_result parse_string(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct parser_state *state = parser_get_state_generic(ctx);
struct ivy_ast_fstring_node *parent
= (struct ivy_ast_fstring_node *)state->s_node;
struct ivy_ast_string_node *child
= (struct ivy_ast_string_node *)ast_node_create(IVY_AST_STRING);
if (!child) {
return PARSE_RESULT(IVY_ERR_NO_MEMORY, 0);
}
child->n_value = tok;
fx_queue_push_back(&parent->n_value, &child->n_base.n_entry);
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_left_brace(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_RIGHT_BRACE);
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_right_brace(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_str_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct ivy_ast_fstring_node *str
= (struct ivy_ast_fstring_node *)parent->s_node;
fx_queue_push_back(&str->n_value, &child->n_entry);
return IVY_OK;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -79,21 +26,10 @@ static void collect_children(
struct ast_node_type string_node_ops = {
.n_to_string = to_string,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_string_node),
};
struct ast_node_type fstring_node_ops = {
.n_add_child = add_child,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_fstring_node),
.n_token_parsers = {
TOK_PARSER(STRING, parse_string),
TOK_PARSER(STR_END, parse_str_end),
},
.n_symbol_parsers = {
SYM_PARSER(LEFT_BRACE, parse_left_brace),
SYM_PARSER(RIGHT_BRACE, parse_right_brace),
},
};
+2 -240
View File
@@ -1,233 +1,5 @@
#include "block.h"
#include "expr/expr.h"
#include "iterate.h"
struct try_parser_state {
struct parser_state s_base;
unsigned int s_prev_token;
struct ivy_ast_node *s_prev_node;
struct ivy_ast_block_node *s_try, *s_finally;
fx_queue s_catch_branches;
struct ivy_ast_try_catch_node *s_cur_catch_branch;
};
static enum ivy_status flush_catch_branch(struct try_parser_state *state)
{
fx_queue_push_back(
&state->s_catch_branches,
&state->s_cur_catch_branch->n_base.n_entry);
state->s_cur_catch_branch
= (struct ivy_ast_try_catch_node *)ast_node_create(
IVY_AST_TRY_CATCH);
if (!state->s_cur_catch_branch) {
return IVY_ERR_NO_MEMORY;
}
return IVY_OK;
}
static enum ivy_status finalise_try(struct try_parser_state *state)
{
struct ivy_ast_try_node *try
= (struct ivy_ast_try_node *)state->s_base.s_node;
try->n_try = (struct ivy_ast_node *)state->s_try;
try->n_finally = (struct ivy_ast_node *)state->s_finally;
try->n_catch = state->s_catch_branches;
state->s_try = NULL;
state->s_finally = NULL;
state->s_catch_branches = FX_QUEUE_INIT;
return IVY_OK;
}
struct token_parse_result parse_catch(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct try_parser_state *try
= parser_get_state(ctx, struct try_parser_state);
if (!try->s_prev_node || try->s_prev_node->n_type != IVY_AST_BLOCK) {
/* there must always be a block between a catch and the keyword
* that came before it */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = IVY_OK;
if (try->s_prev_token == IVY_KW_TRY) {
try->s_try = (struct ivy_ast_block_node *)try->s_prev_node;
try->s_prev_node = NULL;
} else if (try->s_prev_token == IVY_KW_IN) {
try->s_cur_catch_branch->n_block = try->s_prev_node;
try->s_prev_node = NULL;
status = flush_catch_branch(try);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
} else {
/* catch can only come after `try` or `in` */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
/* next input should be the catch pattern */
struct expr_parser_state *pattern
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(pattern, IVY_KW_IN);
try->s_prev_token = IVY_KW_CATCH;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_in(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct try_parser_state *try
= parser_get_state(ctx, struct try_parser_state);
if (try->s_prev_token != IVY_KW_CATCH) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!try->s_prev_node) {
/* there must always be an expression between catch and in */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
try->s_cur_catch_branch->n_pattern = try->s_prev_node;
try->s_prev_node = NULL;
try->s_prev_token = IVY_KW_IN;
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_CATCH);
block_add_terminator(block, IVY_KW_FINALLY);
block_add_terminator(block, IVY_KW_END);
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_finally(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct try_parser_state *try
= parser_get_state(ctx, struct try_parser_state);
if (try->s_prev_token != IVY_KW_IN && try->s_prev_token != IVY_KW_TRY) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!try->s_prev_node || try->s_prev_node->n_type != IVY_AST_BLOCK) {
/* there must always be a block between a catch and the keyword
* that came before it */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = IVY_OK;
if (try->s_prev_token == IVY_KW_TRY) {
try->s_try = (struct ivy_ast_block_node *)try->s_prev_node;
try->s_prev_node = NULL;
} else if (try->s_prev_token == IVY_KW_IN) {
try->s_cur_catch_branch->n_block = try->s_prev_node;
try->s_prev_node = NULL;
status = flush_catch_branch(try);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
} else {
/* finally can only come after `try` or `in` */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
try->s_prev_token = IVY_KW_FINALLY;
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_END);
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_end(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct try_parser_state *try
= parser_get_state(ctx, struct try_parser_state);
if (!try->s_prev_node || try->s_prev_node->n_type != IVY_AST_BLOCK) {
/* there must always be a block between an end and the keyword
* that came before it */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = IVY_OK;
if (try->s_prev_token == IVY_KW_TRY) {
try->s_try = (struct ivy_ast_block_node *)try->s_prev_node;
try->s_prev_node = NULL;
} else if (try->s_prev_token == IVY_KW_FINALLY) {
try->s_finally = (struct ivy_ast_block_node *)try->s_prev_node;
try->s_prev_node = NULL;
} else if (try->s_prev_token == IVY_KW_IN) {
try->s_cur_catch_branch->n_block = try->s_prev_node;
status = flush_catch_branch(try);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
} else {
/* catch can only come after `try`, `in`, or `finally` */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
finalise_try(try);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct try_parser_state *state = (struct try_parser_state *)sp;
state->s_prev_token = IVY_KW_TRY;
state->s_cur_catch_branch
= (struct ivy_ast_try_catch_node *)ast_node_create(
IVY_AST_TRY_CATCH);
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_CATCH);
block_add_terminator(block, IVY_KW_FINALLY);
block_add_terminator(block, IVY_KW_END);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct try_parser_state *state = (struct try_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
#include "node.h"
static void try_collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
@@ -260,21 +32,11 @@ static void try_catch_collect_children(
}
struct ast_node_type try_node_ops = {
.n_init_state = init_state,
.n_add_child = add_child,
.n_collect_children = try_collect_children,
.n_state_size = sizeof(struct try_parser_state),
.n_node_size = sizeof(struct ivy_ast_try_node),
.n_keyword_parsers = {
KW_PARSER(CATCH, parse_catch),
KW_PARSER(IN, parse_in),
KW_PARSER(FINALLY, parse_finally),
KW_PARSER(END, parse_end),
},
};
struct ast_node_type try_catch_node_ops = {
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_try_catch_node),
.n_collect_children = try_catch_collect_children,
.n_node_size = sizeof(struct ivy_ast_try_catch_node),
};
-113
View File
@@ -1,5 +1,3 @@
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "ivy/status.h"
#include "node.h"
@@ -8,110 +6,6 @@
#include <ivy/lang/lex.h>
#include <stdio.h>
struct tuple_parser_state {
struct parser_state s_base;
struct ivy_ast_node *s_prev_node;
unsigned int s_prev;
fx_queue s_items;
};
static void finalise_tuple(struct tuple_parser_state *state)
{
struct ivy_ast_tuple_node *tuple
= (struct ivy_ast_tuple_node *)state->s_base.s_node;
tuple->n_members = state->s_items;
state->s_items = FX_QUEUE_INIT;
}
struct token_parse_result parse_comma(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct tuple_parser_state *state
= parser_get_state(ctx, struct tuple_parser_state);
if (state->s_prev != IVY_SYM_LEFT_PAREN && state->s_prev != IVY_SYM_COMMA) {
/* token not expected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty tuple member */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
fx_queue_push_back(&state->s_items, &state->s_prev_node->n_entry);
state->s_prev_node = NULL;
state->s_prev = IVY_SYM_COMMA;
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_COMMA);
expr_add_terminator(expr, IVY_SYM_RIGHT_PAREN);
expr->s_subexpr_depth = 1;
return PARSE_RESULT(IVY_OK, 0);
}
struct token_parse_result parse_right_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct tuple_parser_state *state
= parser_get_state(ctx, struct tuple_parser_state);
if (state->s_prev != IVY_SYM_COMMA) {
/* token not expected at this time. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (!state->s_prev_node) {
/* empty tuple member */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
fx_queue_push_back(&state->s_items, &state->s_prev_node->n_entry);
state->s_prev_node = NULL;
state->s_prev = IVY_SYM_RIGHT_PAREN;
finalise_tuple(state);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct tuple_parser_state *state = (struct tuple_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct tuple_parser_state *state = (struct tuple_parser_state *)sp;
state->s_prev = IVY_SYM_LEFT_PAREN;
if (arg) {
/* arg is the first node in the tuple */
struct ivy_ast_node *item = (struct ivy_ast_node *)arg;
fx_queue_push_back(&state->s_items, &item->n_entry);
state->s_prev = IVY_SYM_COMMA;
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
expr_add_terminator(expr, IVY_SYM_COMMA);
expr_add_terminator(expr, IVY_SYM_RIGHT_PAREN);
expr->s_subexpr_depth = 1;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -127,13 +21,6 @@ static void collect_children(
}
struct ast_node_type tuple_node_ops = {
.n_add_child = add_child,
.n_init_state = init_state,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct tuple_parser_state),
.n_node_size = sizeof(struct ivy_ast_tuple_node),
.n_symbol_parsers = {
SYM_PARSER(COMMA, parse_comma),
SYM_PARSER(RIGHT_PAREN, parse_right_paren),
},
};
-70
View File
@@ -1,62 +1,9 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
#include <stdio.h>
struct unit_import_parser_state {
struct parser_state s_base;
int s_prev_token;
};
static struct token_parse_result parse_dot(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct unit_import_parser_state *state
= parser_get_state(ctx, struct unit_import_parser_state);
if (state->s_prev_token != IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev_token = IVY_SYM_DOT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct unit_import_parser_state *state
= parser_get_state(ctx, struct unit_import_parser_state);
struct ivy_ast_unit_import_node *node
= (struct ivy_ast_unit_import_node *)(state->s_base.s_node);
if (state->s_prev_token == IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
fx_queue_push_back(&node->n_ident, &tok->t_entry);
state->s_prev_token = IVY_TOK_IDENT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_linefeed(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct unit_import_parser_state *state
= parser_get_state(ctx, struct unit_import_parser_state);
if (state->s_prev_token != IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static void to_string(struct ivy_ast_node *node, fx_string *str)
{
struct ivy_ast_unit_import_node *unit_import
@@ -84,24 +31,7 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
fx_string_append_cstr(str, ")");
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct unit_import_parser_state *state
= (struct unit_import_parser_state *)sp;
state->s_prev_token = IVY_KW_PACKAGE;
}
struct ast_node_type unit_import_node_ops = {
.n_to_string = to_string,
.n_init_state = init_state,
.n_state_size = sizeof(struct unit_import_parser_state),
.n_node_size = sizeof(struct ivy_ast_unit_import_node),
.n_symbol_parsers = {
SYM_PARSER(DOT, parse_dot),
},
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
TOK_PARSER(LINEFEED, parse_linefeed),
}
};
-70
View File
@@ -1,62 +1,9 @@
#include "ctx.h"
#include "node.h"
#include <fx/ds/string.h>
#include <ivy/lang/lex.h>
#include <stdio.h>
struct unit_package_parser_state {
struct parser_state s_base;
int s_prev_token;
};
static struct token_parse_result parse_dot(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct unit_package_parser_state *state
= parser_get_state(ctx, struct unit_package_parser_state);
if (state->s_prev_token != IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_prev_token = IVY_SYM_DOT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct unit_package_parser_state *state
= parser_get_state(ctx, struct unit_package_parser_state);
struct ivy_ast_unit_package_node *node
= (struct ivy_ast_unit_package_node *)(state->s_base.s_node);
if (state->s_prev_token == IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
fx_queue_push_back(&node->n_ident, &tok->t_entry);
state->s_prev_token = IVY_TOK_IDENT;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_linefeed(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct unit_package_parser_state *state
= parser_get_state(ctx, struct unit_package_parser_state);
if (state->s_prev_token != IVY_TOK_IDENT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static void to_string(struct ivy_ast_node *node, fx_string *str)
{
struct ivy_ast_unit_package_node *unit_package
@@ -83,24 +30,7 @@ static void to_string(struct ivy_ast_node *node, fx_string *str)
fx_string_append_cstr(str, ")");
}
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct unit_package_parser_state *state
= (struct unit_package_parser_state *)sp;
state->s_prev_token = IVY_KW_PACKAGE;
}
struct ast_node_type unit_package_node_ops = {
.n_to_string = to_string,
.n_init_state = init_state,
.n_state_size = sizeof(struct unit_package_parser_state),
.n_node_size = sizeof(struct ivy_ast_unit_package_node),
.n_symbol_parsers = {
SYM_PARSER(DOT, parse_dot),
},
.n_token_parsers = {
TOK_PARSER(IDENT, parse_ident),
TOK_PARSER(LINEFEED, parse_linefeed),
}
};
-65
View File
@@ -1,59 +1,8 @@
#include "ctx.h"
#include "expr/expr.h"
#include "iterate.h"
#include "node.h"
#include <ivy/lang/ast.h>
static struct token_parse_result parse_package_keyword(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_push_state(ctx, IVY_AST_UNIT_PACKAGE, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_use_keyword(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_push_state(ctx, IVY_AST_UNIT_IMPORT, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_global_keyword(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_push_state(ctx, IVY_AST_GLOBAL, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_class_keyword(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_push_state(ctx, IVY_AST_CLASS, 0);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_expr_begin(
struct ivy_parser *ctx, struct ivy_token *tok)
{
parser_push_state(ctx, IVY_AST_EXPR, 0);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_dot(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct ivy_ast_unit_node *unit = (struct ivy_ast_unit_node *)parent->s_node;
fx_queue_push_back(&unit->n_children, &child->n_entry);
return IVY_OK;
}
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
{
@@ -68,20 +17,6 @@ static void collect_children(
}
struct ast_node_type unit_node_ops = {
.n_add_child = add_child,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct parser_state),
.n_node_size = sizeof(struct ivy_ast_unit_node),
.n_keyword_parsers = {
KW_PARSER(PACKAGE, parse_package_keyword),
KW_PARSER(CLASS, parse_class_keyword),
KW_PARSER(USE, parse_use_keyword),
KW_PARSER(GLOBAL, parse_global_keyword),
},
.n_symbol_parsers = {
SYM_PARSER(DOT, parse_dot),
},
.n_expr_parser = {
.expr_begin = parse_expr_begin,
},
};
+2 -196
View File
@@ -1,184 +1,7 @@
#include "block.h"
#include "expr/expr.h"
#include "iterate.h"
#include "node.h"
struct while_parser_state {
struct parser_state s_base;
bool s_inline;
unsigned int s_prev_token;
struct ivy_ast_node *s_body, *s_cond;
struct ivy_ast_node *s_prev_node;
};
static void init_state(struct ivy_parser *ctx, struct parser_state *sp, uintptr_t arg)
{
struct while_parser_state *state = (struct while_parser_state *)sp;
state->s_prev_node = (struct ivy_ast_node *)arg;
}
struct token_parse_result parse_while(struct ivy_parser *ctx, struct ivy_token *tok)
{
struct while_parser_state *state
= parser_get_state(ctx, struct while_parser_state);
if (state->s_prev_node) {
/* this is an inline while-loop */
state->s_inline = true;
state->s_body = state->s_prev_node;
state->s_prev_node = NULL;
} else {
state->s_inline = false;
}
struct expr_parser_state *expr
= (struct expr_parser_state *)parser_push_state(
ctx, IVY_AST_EXPR, 0);
state->s_prev_token = IVY_KW_WHILE;
expr->s_subexpr_depth = 1;
expr_add_terminator(expr, IVY_KW_DO);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_do(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct while_parser_state *state
= parser_get_state(ctx, struct while_parser_state);
if (state->s_inline) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
if (state->s_prev_token != IVY_KW_WHILE) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
/* previous component was the while-condition. */
if (!state->s_prev_node) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
state->s_cond = state->s_prev_node;
state->s_prev_node = NULL;
/* next component will be a block. */
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
/* set the sub-expression depth to be non-zero so the expression parser doesn't consume the expression separator. */
block_add_terminator(block, IVY_KW_END);
state->s_prev_token = IVY_KW_DO;
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_expr_begin(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct while_parser_state *state
= parser_get_state(ctx, struct while_parser_state);
if (state->s_prev_token != IVY_KW_DO) {
/* expression can only follow else and then keywords. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct block_parser_state *block
= (struct block_parser_state *)parser_push_state(
ctx, IVY_AST_BLOCK, 0);
block_add_terminator(block, IVY_KW_END);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static enum ivy_status finalise_while_loop(struct while_parser_state *state)
{
struct ivy_ast_while_loop_node *loop
= (struct ivy_ast_while_loop_node *)state->s_base.s_node;
if (state->s_inline) {
/* we have just reached the end of either the while condition. */
if (!state->s_prev_node) {
/* while condition is empty. */
return IVY_ERR_BAD_SYNTAX;
}
/* the condition and body are parsed in reverse order for inline loops. */
loop->n_cond = state->s_prev_node;
loop->n_body = state->s_body;
state->s_prev_node = NULL;
return IVY_OK;
}
if (!state->s_prev_node) {
/* while body is empty. */
return IVY_ERR_BAD_SYNTAX;
}
loop->n_cond = state->s_cond;
loop->n_body = state->s_prev_node;
state->s_cond = NULL;
state->s_prev_node = NULL;
return IVY_OK;
}
static struct token_parse_result parse_punct_terminator(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct while_parser_state *state
= parser_get_state(ctx, struct while_parser_state);
if (!state->s_inline) {
/* only inline while loop can be ended with punctuation. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_while_loop(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct while_parser_state *state
= parser_get_state(ctx, struct while_parser_state);
if (state->s_inline) {
/* inline while loop must be terminated with punctuation. */
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_while_loop(state);
if (status != IVY_OK) {
return PARSE_RESULT(status, 0);
}
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(IVY_OK, 0);
}
static enum ivy_status add_child(
struct parser_state *parent, struct ivy_ast_node *child)
{
struct while_parser_state *state = (struct while_parser_state *)parent;
if (state->s_prev_node) {
return IVY_ERR_BAD_SYNTAX;
}
state->s_prev_node = child;
return IVY_OK;
}
#include <ivy/lang/ast.h>
static void collect_children(
struct ivy_ast_node *node, struct ivy_ast_node_iterator *iterator)
@@ -196,23 +19,6 @@ static void collect_children(
}
struct ast_node_type while_loop_node_ops = {
.n_init_state = init_state,
.n_add_child = add_child,
.n_collect_children = collect_children,
.n_state_size = sizeof(struct while_parser_state),
.n_node_size = sizeof(struct ivy_ast_while_loop_node),
.n_keyword_parsers = {
KW_PARSER(WHILE, parse_while),
KW_PARSER(DO, parse_do),
KW_PARSER(END, parse_end),
},
.n_symbol_parsers = {
SYM_PARSER(DOT, parse_punct_terminator),
SYM_PARSER(COMMA, parse_punct_terminator),
SYM_PARSER(RIGHT_PAREN, parse_punct_terminator),
SYM_PARSER(BANG, parse_punct_terminator),
},
.n_expr_parser = {
.expr_begin = parse_expr_begin,
},
};