lang: replace stack-based parser with a recursive parser
This commit is contained in:
@@ -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
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
@@ -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
@@ -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),
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
@@ -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
@@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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
@@ -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),
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -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
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -352,7 +352,6 @@ static bool node_is_expr(struct ivy_ast_node *node)
|
||||
switch (node->n_type) {
|
||||
case IVY_AST_OP:
|
||||
case IVY_AST_MSG:
|
||||
case IVY_AST_LAMBDA:
|
||||
case IVY_AST_DISCARD:
|
||||
case IVY_AST_INT:
|
||||
case IVY_AST_DOUBLE:
|
||||
|
||||
@@ -744,7 +744,6 @@ struct code_generator expr_generator = {
|
||||
NODE_CODEGEN(INT, gen_int),
|
||||
NODE_CODEGEN(OP, gen_op),
|
||||
NODE_CODEGEN(MSG, gen_msg),
|
||||
NODE_CODEGEN(LAMBDA, gen_lambda),
|
||||
NODE_CODEGEN(STRING, gen_string),
|
||||
NODE_CODEGEN(FSTRING, gen_fstring),
|
||||
NODE_CODEGEN(IDENT, gen_var_reference),
|
||||
|
||||
@@ -8,7 +8,6 @@ extern const struct code_generator expr_generator;
|
||||
extern const struct code_generator global_generator;
|
||||
extern const struct code_generator msg_generator;
|
||||
extern const struct code_generator fstring_generator;
|
||||
extern const struct code_generator lambda_generator;
|
||||
extern const struct code_generator return_generator;
|
||||
extern const struct code_generator cond_generator;
|
||||
extern const struct code_generator cond_group_generator;
|
||||
@@ -23,7 +22,6 @@ static const struct code_generator *code_generators[] = {
|
||||
[CODE_GENERATOR_GLOBAL] = &global_generator,
|
||||
[CODE_GENERATOR_MSG] = &msg_generator,
|
||||
[CODE_GENERATOR_FSTRING] = &fstring_generator,
|
||||
[CODE_GENERATOR_LAMBDA] = &lambda_generator,
|
||||
[CODE_GENERATOR_RETURN] = &return_generator,
|
||||
[CODE_GENERATOR_COND] = &cond_generator,
|
||||
[CODE_GENERATOR_COND_GROUP] = &cond_group_generator,
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
#include "codegen.h"
|
||||
|
||||
#include <mie/ir/block.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum lambda_part {
|
||||
LAMBDA_NONE,
|
||||
LAMBDA_START,
|
||||
LAMBDA_ARG,
|
||||
LAMBDA_BLOCK,
|
||||
};
|
||||
|
||||
struct lambda_codegen_state {
|
||||
struct code_generator_state s_base;
|
||||
enum lambda_part s_prev_part;
|
||||
struct mie_func *s_func;
|
||||
struct mie_value *s_ctx_internal;
|
||||
struct mie_value *s_ctx_external;
|
||||
struct mie_block *s_outer_block;
|
||||
struct codegen_var_map s_args;
|
||||
struct codegen_var_map s_captured_vars;
|
||||
};
|
||||
|
||||
static enum ivy_status switch_to_lambda_func(
|
||||
struct ivy_codegen *gen, struct lambda_codegen_state *lambda)
|
||||
{
|
||||
#if 0
|
||||
if (!lambda->s_outer_block) {
|
||||
lambda->s_outer_block
|
||||
= mie_builder_get_current_block(gen->c_builder);
|
||||
}
|
||||
|
||||
struct mie_block *block = mie_func_get_last_block(lambda->s_func);
|
||||
if (!block) {
|
||||
block = mie_func_create_block(lambda->s_func, "entry");
|
||||
mie_func_insert_block(lambda->s_func, block, NULL);
|
||||
}
|
||||
|
||||
if (mie_block_is_terminated(block)) {
|
||||
block = mie_func_create_block(lambda->s_func, NULL);
|
||||
mie_func_insert_block(lambda->s_func, block, NULL);
|
||||
}
|
||||
|
||||
mie_builder_set_insert_point(gen->c_builder, block);
|
||||
|
||||
return IVY_OK;
|
||||
#endif
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static enum ivy_status switch_to_outer_block(
|
||||
struct ivy_codegen *gen, struct lambda_codegen_state *lambda)
|
||||
{
|
||||
#if 0
|
||||
mie_builder_set_insert_point(gen->c_builder, lambda->s_outer_block);
|
||||
return IVY_OK;
|
||||
#endif
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static struct code_generator_result gen_lambda(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node, size_t depth)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
#if 0
|
||||
if (lambda->s_prev_part != LAMBDA_NONE) {
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
|
||||
}
|
||||
|
||||
struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
|
||||
struct mie_type *func_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_FUNC);
|
||||
|
||||
lambda->s_prev_part = LAMBDA_START;
|
||||
lambda->s_func = mie_func_create(MIE_FUNC_STATIC, id);
|
||||
lambda->s_ctx_internal = mie_func_add_arg(lambda->s_func, id, "ctx");
|
||||
|
||||
struct mie_value *lambda_class
|
||||
= mie_builder_get_data_ptr(gen->c_builder, "Lambda");
|
||||
struct mie_value *sel = mie_ctx_get_selector(gen->c_ctx, "_M3new4funcE");
|
||||
struct mie_value *func_value = mie_builder_load(
|
||||
gen->c_builder, func_type, MIE_VALUE(lambda->s_func), NULL);
|
||||
struct mie_value *args[] = {
|
||||
func_value,
|
||||
};
|
||||
|
||||
lambda->s_ctx_external = mie_builder_msg(
|
||||
gen->c_builder, id, lambda_class, sel, args,
|
||||
sizeof args / sizeof args[0], 0, NULL);
|
||||
|
||||
switch_to_lambda_func(gen, lambda);
|
||||
|
||||
return CODEGEN_RESULT_OK(0);
|
||||
#endif
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static struct code_generator_result gen_ident(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node, size_t depth)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
#if 0
|
||||
if (lambda->s_prev_part != LAMBDA_START
|
||||
&& lambda->s_prev_part != LAMBDA_ARG) {
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
|
||||
}
|
||||
|
||||
lambda->s_prev_part = LAMBDA_ARG;
|
||||
|
||||
struct ivy_ast_ident_node *ident = (struct ivy_ast_ident_node *)node;
|
||||
const char *arg_name = ident->n_content->t_str;
|
||||
struct mie_type *id = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID);
|
||||
struct mie_value *arg = mie_func_add_arg(lambda->s_func, id, arg_name);
|
||||
|
||||
struct codegen_var arg_var = {
|
||||
.v_node = node,
|
||||
.v_type = id,
|
||||
.v_value = arg,
|
||||
};
|
||||
|
||||
codegen_var_map_put(&lambda->s_args, arg_name, &arg_var);
|
||||
|
||||
return CODEGEN_RESULT_OK(0);
|
||||
#endif
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
static struct code_generator_result gen_block(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct ivy_ast_node *node, size_t depth)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
if (lambda->s_prev_part != LAMBDA_START
|
||||
&& lambda->s_prev_part != LAMBDA_ARG) {
|
||||
return CODEGEN_RESULT_ERR(IVY_ERR_BAD_SYNTAX);
|
||||
}
|
||||
|
||||
codegen_push_generator(gen, CODE_GENERATOR_BLOCK, 0, NULL);
|
||||
|
||||
return CODEGEN_RESULT_OK(0);
|
||||
}
|
||||
|
||||
static enum ivy_status state_init(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
uintptr_t argv, void *argp)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
codegen_var_map_init(&lambda->s_args);
|
||||
codegen_var_map_init(&lambda->s_captured_vars);
|
||||
lambda->s_prev_part = LAMBDA_NONE;
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
static enum ivy_status state_fini(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
struct code_generator_value *result)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
|
||||
#if 0
|
||||
switch_to_outer_block(gen, lambda);
|
||||
mie_module_add_function(gen->c_module, lambda->s_func, ".anon");
|
||||
result->v_type = CODE_GENERATOR_VALUE_MIE_VALUE;
|
||||
result->v_value.mie_value = MIE_VALUE(lambda->s_ctx_external);
|
||||
|
||||
codegen_var_map_fini(&lambda->s_args);
|
||||
codegen_var_map_fini(&lambda->s_captured_vars);
|
||||
|
||||
return IVY_OK;
|
||||
#endif
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static enum ivy_status resolve_var(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
const char *ident, struct codegen_var *var)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
struct codegen_var *result = NULL;
|
||||
enum ivy_status status
|
||||
= codegen_var_map_get(&lambda->s_args, ident, &result);
|
||||
|
||||
if (status == IVY_OK) {
|
||||
memcpy(var, result, sizeof *var);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = codegen_var_map_get(&lambda->s_captured_vars, ident, &result);
|
||||
|
||||
if (status == IVY_OK) {
|
||||
memcpy(var, result, sizeof *var);
|
||||
return status;
|
||||
}
|
||||
|
||||
return IVY_ERR_NO_ENTRY;
|
||||
}
|
||||
|
||||
static enum ivy_status capture_var(
|
||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||
const char *ident, struct codegen_var *var)
|
||||
{
|
||||
struct lambda_codegen_state *lambda = (struct lambda_codegen_state *)state;
|
||||
|
||||
#if 0
|
||||
struct mie_type *str_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_STR);
|
||||
struct mie_type *void_type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_VOID);
|
||||
struct mie_value *ident_ptr
|
||||
= mie_builder_get_string_ptr(gen->c_builder, ident);
|
||||
|
||||
switch_to_outer_block(gen, lambda);
|
||||
|
||||
struct mie_value *ident_str
|
||||
= mie_builder_load(gen->c_builder, str_type, ident_ptr, NULL);
|
||||
|
||||
struct mie_value *capture_value = codegen_load_variable(gen, var);
|
||||
struct mie_value *put_sel
|
||||
= mie_ctx_get_selector(gen->c_ctx, "_M02at3putE");
|
||||
struct mie_value *put_args[] = {
|
||||
ident_str,
|
||||
capture_value,
|
||||
};
|
||||
|
||||
struct mie_value *capture_store = mie_builder_msg(
|
||||
gen->c_builder, void_type, lambda->s_ctx_external, put_sel,
|
||||
put_args, sizeof put_args / sizeof put_args[0],
|
||||
MIE_BUILDER_IGNORE_RESULT, NULL);
|
||||
|
||||
switch_to_lambda_func(gen, lambda);
|
||||
|
||||
struct codegen_var capture = {
|
||||
.v_type = var->v_type,
|
||||
.v_node = var->v_node,
|
||||
.v_flags = CODEGEN_VAR_F_CAPTURE | CODEGEN_VAR_F_PTR,
|
||||
};
|
||||
|
||||
ident_str = mie_builder_load(gen->c_builder, str_type, ident_ptr, NULL);
|
||||
|
||||
struct mie_value *at_sel = mie_ctx_get_selector(gen->c_ctx, "_M02atE");
|
||||
struct mie_value *at_args[] = {
|
||||
ident_str,
|
||||
};
|
||||
|
||||
struct mie_value *stack_ptr
|
||||
= mie_builder_alloca(gen->c_builder, var->v_type, ident);
|
||||
|
||||
struct mie_value *value = mie_builder_msg(
|
||||
gen->c_builder, var->v_type, lambda->s_ctx_internal, at_sel,
|
||||
at_args, sizeof at_args / sizeof at_args[0], 0, NULL);
|
||||
mie_builder_store(gen->c_builder, value, stack_ptr);
|
||||
|
||||
capture.v_value = stack_ptr;
|
||||
|
||||
*var = capture;
|
||||
|
||||
return IVY_OK;
|
||||
#endif
|
||||
return IVY_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
struct code_generator lambda_generator = {
|
||||
.g_type = CODE_GENERATOR_LAMBDA,
|
||||
.g_state_size = sizeof(struct lambda_codegen_state),
|
||||
.g_state_init = state_init,
|
||||
.g_state_fini = state_fini,
|
||||
.g_resolve_var = resolve_var,
|
||||
.g_capture_var = capture_var,
|
||||
.g_node_generators = {
|
||||
NODE_CODEGEN(LAMBDA, gen_lambda),
|
||||
NODE_CODEGEN(IDENT, gen_ident),
|
||||
NODE_CODEGEN(BLOCK, gen_block),
|
||||
},
|
||||
};
|
||||
@@ -70,7 +70,6 @@ static struct code_generator_result value_received(
|
||||
}
|
||||
|
||||
ret->s_value = value->v_value.mie_value;
|
||||
ret->s_prev_node = IVY_AST_EXPR;
|
||||
|
||||
return CODEGEN_RESULT_OK(CODEGEN_R_POP_GENERATOR);
|
||||
}
|
||||
|
||||
+13
-36
@@ -10,7 +10,6 @@
|
||||
|
||||
struct ivy_diag_ctx;
|
||||
struct ivy_token;
|
||||
struct ivy_parser;
|
||||
struct fx_string;
|
||||
|
||||
enum ivy_ast_node_type {
|
||||
@@ -24,11 +23,11 @@ enum ivy_ast_node_type {
|
||||
IVY_AST_BLOCK,
|
||||
IVY_AST_SELECTOR,
|
||||
IVY_AST_PROPERTY,
|
||||
IVY_AST_LAMBDA,
|
||||
IVY_AST_UNIT_PACKAGE,
|
||||
IVY_AST_UNIT_IMPORT,
|
||||
IVY_AST_GLOBAL,
|
||||
IVY_AST_DISCARD,
|
||||
IVY_AST_DO,
|
||||
IVY_AST_INT,
|
||||
IVY_AST_DOUBLE,
|
||||
IVY_AST_STRING,
|
||||
@@ -54,12 +53,6 @@ enum ivy_ast_node_type {
|
||||
IVY_AST_C_FALSE,
|
||||
IVY_AST_C_NULL,
|
||||
|
||||
/* these are pseudo-types. a finished AST will never have these nodes in
|
||||
* it, but they are necessary to identifier AST parsers that will
|
||||
* produce nodes of other, related types. */
|
||||
IVY_AST_PKG,
|
||||
IVY_AST_EXPR,
|
||||
|
||||
IVY_AST_TYPE_COUNT,
|
||||
};
|
||||
|
||||
@@ -143,7 +136,7 @@ struct ivy_ast_class_node {
|
||||
struct ivy_ast_msgh_node {
|
||||
struct ivy_ast_node n_base;
|
||||
struct ivy_ast_selector_node *n_sel;
|
||||
/* expressions to evaluate when lambda is executed. */
|
||||
/* expressions to evaluate when block is executed. */
|
||||
struct ivy_ast_node *n_body;
|
||||
};
|
||||
|
||||
@@ -159,26 +152,26 @@ struct ivy_ast_property_node {
|
||||
} n_flags;
|
||||
|
||||
/* one of either:
|
||||
* a) a lambda. the lambda is executed to get the property value; or,
|
||||
* a) a block. the block is executed to get the property value; or,
|
||||
* b) a constant value. the constant is returned as the property
|
||||
* value. c) NULL. the property is write-only.
|
||||
*/
|
||||
struct ivy_ast_node *n_get;
|
||||
/* one of either:
|
||||
* a) a lambda. the lambda is executed with the provided value as a
|
||||
* a) a block. the block is executed with the provided value as a
|
||||
* parameter to set the property value; or,
|
||||
* b) NULL. the property is read-only.
|
||||
*/
|
||||
struct ivy_ast_node *n_set;
|
||||
};
|
||||
|
||||
struct ivy_ast_lambda_node {
|
||||
struct ivy_ast_block_node {
|
||||
struct ivy_ast_node n_base;
|
||||
/* queue of struct ivy_ast_ident_node; contains the names of the lambda
|
||||
/* queue of struct ivy_ast_ident_node; contains the names of the block
|
||||
* parameters. */
|
||||
fx_queue n_arg;
|
||||
/* expressions to evaluate when lambda is executed. */
|
||||
struct ivy_ast_node *n_body;
|
||||
/* expressions to evaluate when block is executed. */
|
||||
fx_queue n_expr;
|
||||
};
|
||||
|
||||
struct ivy_ast_unit_package_node {
|
||||
@@ -202,6 +195,11 @@ struct ivy_ast_discard_node {
|
||||
struct ivy_ast_node n_base;
|
||||
};
|
||||
|
||||
struct ivy_ast_do_node {
|
||||
struct ivy_ast_node n_base;
|
||||
struct ivy_ast_node *n_block;
|
||||
};
|
||||
|
||||
struct ivy_ast_int_node {
|
||||
struct ivy_ast_node n_base;
|
||||
/* lex token of type IVY_TOK_INT. */
|
||||
@@ -336,31 +334,10 @@ struct ivy_ast_pkg_dynamic_node {
|
||||
struct ivy_ast_node *n_cond;
|
||||
};
|
||||
|
||||
struct ivy_ast_block_node {
|
||||
struct ivy_ast_node n_base;
|
||||
/* queue of struct ivy_ast_node. expressions to evaluate when the do node itself is evaluated. */
|
||||
fx_queue n_expr;
|
||||
};
|
||||
|
||||
typedef enum ivy_status (*ivy_ast_node_iteration_callback)(
|
||||
struct ivy_ast_node *, enum ivy_ast_iteration_type,
|
||||
struct ivy_ast_node_iterator *, void *);
|
||||
|
||||
IVY_API enum ivy_status ivy_parser_create(struct ivy_parser **parser);
|
||||
IVY_API void ivy_parser_destroy(
|
||||
struct ivy_parser *parser, struct ivy_ast_node **result);
|
||||
|
||||
IVY_API enum ivy_status ivy_parser_set_diag_ctx(
|
||||
struct ivy_parser *parser, struct ivy_diag_ctx *ctx);
|
||||
IVY_API enum ivy_status ivy_parser_get_status(struct ivy_parser *parser);
|
||||
IVY_API bool ivy_parser_is_node_complete(struct ivy_parser *parser);
|
||||
IVY_API struct ivy_ast_node *ivy_parser_root_node(struct ivy_parser *parser);
|
||||
IVY_API struct ivy_ast_node *ivy_parser_dequeue_node(struct ivy_parser *parser);
|
||||
|
||||
IVY_API enum ivy_status ivy_parser_push_token(
|
||||
struct ivy_parser *parser, struct ivy_token *tok);
|
||||
IVY_API enum ivy_status ivy_parser_push_eof(struct ivy_parser *parser);
|
||||
|
||||
IVY_API struct ivy_ast_node *ivy_ast_node_create(enum ivy_ast_node_type type);
|
||||
IVY_API enum ivy_status ivy_ast_node_iterate(
|
||||
struct ivy_ast_node *node, struct ivy_ast_node_iterator *it,
|
||||
|
||||
@@ -151,6 +151,7 @@ IVY_API struct ivy_token *ivy_lexer_peek(struct ivy_lexer *lex);
|
||||
IVY_API struct ivy_token *ivy_lexer_read(struct ivy_lexer *lex);
|
||||
IVY_API bool ivy_lexer_tokens_available(struct ivy_lexer *lex);
|
||||
|
||||
IVY_API struct ivy_token *ivy_token_create_discard(void);
|
||||
IVY_API struct ivy_token *ivy_token_create_ident(const char *s);
|
||||
IVY_API void ivy_token_destroy(struct ivy_token *tok);
|
||||
|
||||
@@ -163,6 +164,7 @@ static inline bool ivy_token_is_keyword(struct ivy_token *tok, enum ivy_keyword
|
||||
return (tok->t_type == IVY_TOK_KEYWORD && tok->t_keyword == kw);
|
||||
}
|
||||
|
||||
IVY_API const char *ivy_token_to_string(const struct ivy_token *tok);
|
||||
IVY_API const char *ivy_lex_token_type_to_string(enum ivy_token_type type);
|
||||
IVY_API const char *ivy_keyword_to_string(enum ivy_keyword keyword);
|
||||
IVY_API const char *ivy_symbol_to_string(enum ivy_symbol sym);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef IVY_LANG_PARSE_H_
|
||||
#define IVY_LANG_PARSE_H_
|
||||
|
||||
#include <ivy/misc.h>
|
||||
#include <ivy/status.h>
|
||||
|
||||
struct ivy_lexer;
|
||||
struct ivy_parser;
|
||||
struct ivy_ast_node;
|
||||
struct ivy_diag_ctx;
|
||||
|
||||
IVY_API enum ivy_status ivy_parser_create(struct ivy_parser **parser);
|
||||
IVY_API void ivy_parser_destroy(struct ivy_parser *parser);
|
||||
|
||||
IVY_API enum ivy_status ivy_parser_set_diag_ctx(
|
||||
struct ivy_parser *parser, struct ivy_diag_ctx *ctx);
|
||||
IVY_API enum ivy_status ivy_parser_get_status(struct ivy_parser *parser);
|
||||
|
||||
IVY_API enum ivy_status ivy_parser_parse(
|
||||
struct ivy_parser *parser, struct ivy_lexer *src,
|
||||
struct ivy_ast_node **out);
|
||||
|
||||
#endif
|
||||
+40
-4
@@ -1,11 +1,11 @@
|
||||
#include "lex.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fx/core/hash.h>
|
||||
#include <fx/core/queue.h>
|
||||
#include <fx/ds/dict.h>
|
||||
#include <fx/ds/number.h>
|
||||
#include <fx/ds/string.h>
|
||||
#include <ctype.h>
|
||||
#include <ivy/diag.h>
|
||||
#include <ivy/lang/diag.h>
|
||||
#include <ivy/lang/lex.h>
|
||||
@@ -132,6 +132,7 @@ static void report_unrecognised_char(struct ivy_lexer *lex, int c)
|
||||
diag, lex->lex_cursor_row, lex->lex_cursor_row, NULL, 0, hl, nr_hl);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void report_missing_whitespace(struct ivy_lexer *lex, int msg)
|
||||
{
|
||||
struct ivy_diag *diag = ivy_diag_ctx_create_diag(
|
||||
@@ -150,6 +151,7 @@ static void report_missing_whitespace(struct ivy_lexer *lex, int msg)
|
||||
ivy_diag_push_snippet(
|
||||
diag, lex->lex_cursor_row, lex->lex_cursor_row, NULL, 0, hl, nr_hl);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct lexer_state *push_lexer_state(
|
||||
struct ivy_lexer *lex, enum lexer_state_type state_type)
|
||||
@@ -490,7 +492,7 @@ static int advance(struct ivy_lexer *lex)
|
||||
lex->lex_cur_char = lex->lex_linebuf[lex->lex_linebuf_ptr];
|
||||
|
||||
lex->lex_cursor_col++;
|
||||
if (lex->lex_cur_char == '\n') {
|
||||
if (lex->lex_prev_char == '\n') {
|
||||
lex->lex_cursor_col = 1;
|
||||
lex->lex_cursor_row++;
|
||||
}
|
||||
@@ -1014,12 +1016,14 @@ static enum ivy_status read_symbol(struct ivy_lexer *lex)
|
||||
return read_number(lex, true);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if ((node->s_def->flags & LEX_TOK_REQUIRES_WHITESPACE)
|
||||
&& (!isspace(prev) || !isspace(prefix))) {
|
||||
report_missing_whitespace(
|
||||
lex, IVY_LANG_MSG_WHITESPACE_REQUIRED_AROUND_BINARY_OP);
|
||||
return IVY_ERR_BAD_SYNTAX;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (node->s_def->id) {
|
||||
case IVY_SYM_SQUOTE:
|
||||
@@ -1080,8 +1084,11 @@ static enum ivy_status read_ident(struct ivy_lexer *lex)
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '-' && prev == '-') {
|
||||
return IVY_ERR_BAD_SYNTAX;
|
||||
if (c == '-') {
|
||||
char next = peek_next(lex);
|
||||
if (!isalnum(next)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char s[2] = {c, 0};
|
||||
@@ -1245,6 +1252,21 @@ struct ivy_token *ivy_token_create_ident(const char *s)
|
||||
return tok;
|
||||
}
|
||||
|
||||
struct ivy_token *ivy_token_create_discard(void)
|
||||
{
|
||||
struct ivy_token *tok = malloc(sizeof *tok);
|
||||
|
||||
if (!tok) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(tok, 0x0, sizeof *tok);
|
||||
|
||||
tok->t_type = IVY_TOK_NONE;
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
void ivy_token_destroy(struct ivy_token *tok)
|
||||
{
|
||||
switch (tok->t_type) {
|
||||
@@ -1382,3 +1404,17 @@ const char *ivy_symbol_to_string(enum ivy_symbol sym)
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const char *ivy_token_to_string(const struct ivy_token *tok)
|
||||
{
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_SYMBOL:
|
||||
return ivy_symbol_to_string(tok->t_symbol);
|
||||
case IVY_TOK_IDENT:
|
||||
return tok->t_str;
|
||||
case IVY_TOK_KEYWORD:
|
||||
return ivy_keyword_to_string(tok->t_keyword);
|
||||
default:
|
||||
return ivy_lex_token_type_to_string(tok->t_type);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -96,8 +96,8 @@ static const struct ivy_operator *operator_symbols[] = {
|
||||
SYM_OP(BINARY_XOR_ASSIGN, CARET_EQUAL),
|
||||
SYM_OP(RANGE, DOUBLE_DOT),
|
||||
SYM_OP(RANGE_INCLUSIVE, DOUBLE_DOT_EQUAL),
|
||||
SYM_OP(SELF_ACCESS, DOUBLE_COLON),
|
||||
SYM_OP(PKG_ACCESS, HYPHEN_RIGHT_ANGLE),
|
||||
SYM_OP(SELF_ACCESS, HYPHEN_RIGHT_ANGLE),
|
||||
SYM_OP(PKG_ACCESS, DOT),
|
||||
|
||||
/* parser-internal pseudo-operators. */
|
||||
SYM_OP(LEFT_PAREN, LEFT_PAREN),
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
static bool parse_block_params(
|
||||
struct ivy_parser *parser, struct ivy_ast_block_node *block)
|
||||
{
|
||||
while (1) {
|
||||
if (parse_symbol(parser, IVY_SYM_PIPE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_COLON)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `|`, or `:` followed by parameter "
|
||||
"name");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_token *ident = NULL;
|
||||
if (!parse_word(parser, &ident)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected parameter identifier after `:`");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_ident_node *ident_node = create_node(IVY_AST_IDENT);
|
||||
ident_node->n_content = ident;
|
||||
fx_queue_push_back(&block->n_arg, &ident_node->n_base.n_entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_block(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
parse_trace(parser, "expected `[` before block contents");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_block_node *block = create_node(IVY_AST_BLOCK);
|
||||
if (!block) {
|
||||
parser->p_status = IVY_ERR_NO_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
if (peek_symbol(parser, IVY_SYM_COLON)) {
|
||||
result = parse_block_params(parser, block);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
parse_trace(parser, "invalid block parameter list");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool prev_was_expr = false;
|
||||
|
||||
while (1) {
|
||||
struct ivy_ast_node *child = NULL;
|
||||
if (parse_linefeed(parser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (prev_was_expr) {
|
||||
if (!parse_symbol(parser, IVY_SYM_DOT)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `.` after expression");
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
prev_was_expr = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peek_expr_start(parser)) {
|
||||
result = parse_expr(parser, EXPR_PARSE_NORMAL, &child);
|
||||
prev_was_expr = true;
|
||||
} else {
|
||||
parse_trace(parser, "expected `]` or expression");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result || !child) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&block->n_expr, &child->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(block);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_cascade(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *first_msg,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!peek_symbol(parser, IVY_SYM_SEMICOLON)) {
|
||||
parse_trace(parser, "expected `;`");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_msg_node *first = (struct ivy_ast_msg_node *)first_msg;
|
||||
if (first->n_base.n_type != IVY_AST_MSG) {
|
||||
parse_trace(parser, "cascade operand is not a message");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_cascade_node *cascade = create_node(IVY_AST_CASCADE);
|
||||
cascade->n_recipient = first->n_recipient;
|
||||
first->n_recipient = NULL;
|
||||
fx_queue_push_back(&cascade->n_msg, &first->n_base.n_entry);
|
||||
|
||||
bool ok = true;
|
||||
while (ok) {
|
||||
parse_linefeed(parser);
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_SEMICOLON)) {
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
fx_queue_entry *entry = NULL;
|
||||
struct ivy_ast_msg_node *msg = NULL;
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok) {
|
||||
break;
|
||||
}
|
||||
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_LABEL:
|
||||
ok = parse_keyword_msg(
|
||||
parser, cascade->n_recipient,
|
||||
EXPR_PARSE_STOP_SEMICOLON,
|
||||
(struct ivy_ast_node **)&msg);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case IVY_TOK_IDENT:
|
||||
ok = parse_unary_msg(
|
||||
parser, cascade->n_recipient,
|
||||
(struct ivy_ast_node **)&msg);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (peek_symbol(parser, IVY_SYM_LEFT_PAREN)) {
|
||||
ok = parse_complex_msg(
|
||||
parser, generic_node(msg),
|
||||
(struct ivy_ast_node **)&msg);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
parse_trace(parser, "expected message after `;`");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
msg->n_recipient = NULL;
|
||||
fx_queue_push_back(&cascade->n_msg, &msg->n_base.n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(cascade);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
static bool parse_named_selector(
|
||||
struct ivy_parser *parser, struct ivy_ast_selector_node *sel)
|
||||
{
|
||||
struct ivy_token *tok = NULL;
|
||||
if (!parse_word(parser, &tok)) {
|
||||
parse_trace(NULL, "expected selector name");
|
||||
return false;
|
||||
}
|
||||
|
||||
sel->n_msg_name = tok;
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
while (1) {
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_token *label = NULL, *arg = NULL;
|
||||
if (!fx_queue_empty(&sel->n_arg_labels)
|
||||
&& !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(NULL, "expected comma after selector arg");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_label(parser, &label)) {
|
||||
parse_trace(NULL, "expected selector arg label");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_word(parser, &arg)) {
|
||||
parse_trace(NULL, "expected selector arg name");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&sel->n_arg_labels, &label->t_entry);
|
||||
fx_queue_push_back(&sel->n_arg_names, &arg->t_entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_unnamed_selector(
|
||||
struct ivy_parser *parser, struct ivy_ast_selector_node *sel)
|
||||
{
|
||||
bool ok = true;
|
||||
while (1) {
|
||||
struct ivy_token *label = NULL, *arg = NULL;
|
||||
if (!parse_label(parser, &label)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_word(parser, &arg)) {
|
||||
parse_trace(NULL, "expected selector arg name");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&sel->n_arg_labels, &label->t_entry);
|
||||
fx_queue_push_back(&sel->n_arg_names, &arg->t_entry);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_selector(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
struct ivy_ast_selector_node *sel = create_node(IVY_AST_SELECTOR);
|
||||
if (parse_symbol(parser, IVY_SYM_PLUS)) {
|
||||
sel->n_recipient = IVY_SELECTOR_RECIPIENT_CLASS;
|
||||
} else if (parse_symbol(parser, IVY_SYM_HYPHEN)) {
|
||||
sel->n_recipient = IVY_SELECTOR_RECIPIENT_OBJECT;
|
||||
} else {
|
||||
parse_trace(NULL, "invalid selector prefix");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
if (peek_word(parser)) {
|
||||
ok = parse_named_selector(parser, sel);
|
||||
} else {
|
||||
ok = parse_unnamed_selector(parser, sel);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(sel);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_msg(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
struct ivy_ast_node *sel = NULL;
|
||||
if (!parse_selector(parser, &sel)) {
|
||||
parse_trace(NULL, "invalid message handler selector");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_msgh_node *msgh = create_node(IVY_AST_MSGH);
|
||||
msgh->n_sel = (struct ivy_ast_selector_node *)sel;
|
||||
|
||||
bool ok = true;
|
||||
struct ivy_ast_node *body = NULL;
|
||||
if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
ok = parse_block(parser, &body);
|
||||
} else if (parse_symbol(parser, IVY_SYM_PIPE)) {
|
||||
ok = parse_expr(parser, EXPR_PARSE_NORMAL, &body);
|
||||
ok = ok && parse_symbol(parser, IVY_SYM_DOT);
|
||||
} else {
|
||||
parse_trace(NULL, "expected message handler body");
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
msgh->n_body = body;
|
||||
*out = generic_node(msgh);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_default_property(
|
||||
struct ivy_parser *parser, struct ivy_ast_property_node *prop)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) {
|
||||
parse_trace(parser, "expected '('");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
while (ok) {
|
||||
parse_linefeed(parser);
|
||||
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
int access_types_set
|
||||
= prop->n_flags
|
||||
& (IVY_AST_PROPERTY_SET | IVY_AST_PROPERTY_GET);
|
||||
|
||||
if (access_types_set != 0 && !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(
|
||||
NULL,
|
||||
"expected `,` or `)` after property access "
|
||||
"type");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
|
||||
int access_type = 0;
|
||||
if (parse_keyword(parser, IVY_KW_GET)) {
|
||||
access_type = IVY_AST_PROPERTY_GET;
|
||||
} else if (parse_keyword(parser, IVY_KW_SET)) {
|
||||
access_type = IVY_AST_PROPERTY_SET;
|
||||
} else {
|
||||
parse_trace(parser, "unknown property access type");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
|
||||
if (prop->n_flags & access_type) {
|
||||
parse_trace(parser, "property access type already set");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
prop->n_flags |= access_type;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_property(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
struct ivy_token *tok = NULL;
|
||||
if (!parse_word(parser, &tok)) {
|
||||
parse_trace(NULL, "expected property name");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_property_node *prop = create_node(IVY_AST_PROPERTY);
|
||||
prop->n_ident = tok;
|
||||
|
||||
if (peek_symbol(parser, IVY_SYM_LEFT_PAREN)) {
|
||||
return parse_default_property(parser, prop);
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_PIPE)) {
|
||||
parse_trace(NULL, "expected `|` after property name");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
while (ok) {
|
||||
if (parse_symbol(parser, IVY_SYM_DOT)) {
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
|
||||
if ((prop->n_get || prop->n_set)
|
||||
&& !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(
|
||||
NULL,
|
||||
"expected `,` or `.` after property "
|
||||
"branch");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
|
||||
int access_type = 0;
|
||||
if (parse_keyword(parser, IVY_KW_GET)) {
|
||||
access_type = IVY_AST_PROPERTY_GET;
|
||||
} else if (parse_keyword(parser, IVY_KW_SET)) {
|
||||
access_type = IVY_AST_PROPERTY_SET;
|
||||
} else {
|
||||
parse_trace(NULL, "unknown property access type");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_EQUAL_RIGHT_ANGLE)) {
|
||||
parse_trace(
|
||||
NULL,
|
||||
"expected `=>` after property branch "
|
||||
"type");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
parse_linefeed(parser);
|
||||
|
||||
struct ivy_ast_node *body = NULL;
|
||||
if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
ok = parse_block(parser, &body);
|
||||
} else {
|
||||
ok = parse_expr(parser, EXPR_PARSE_STOP_COMMA, &body);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
parse_trace(parser, "invalid property value");
|
||||
break;
|
||||
}
|
||||
|
||||
prop->n_flags |= access_type;
|
||||
switch (access_type) {
|
||||
case IVY_AST_PROPERTY_GET:
|
||||
if (prop->n_get) {
|
||||
parse_trace(NULL, "property getter already set");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
prop->n_get = body;
|
||||
break;
|
||||
case IVY_AST_PROPERTY_SET:
|
||||
if (prop->n_set) {
|
||||
parse_trace(NULL, "property setter already set");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
prop->n_set = body;
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(prop);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_class(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_CLASS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_token *ident = NULL;
|
||||
if (!parse_word(parser, &ident)) {
|
||||
parse_trace(NULL, "expected class identifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
parse_trace(NULL, "expected `[` after class identifier");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_class_node *class = create_node(IVY_AST_CLASS);
|
||||
if (!class) {
|
||||
parser->p_status = IVY_ERR_NO_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
class->n_ident = ident;
|
||||
|
||||
bool result = true;
|
||||
while (1) {
|
||||
struct ivy_ast_node *msg = NULL, *property = NULL;
|
||||
if (parse_linefeed(parser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (peek_symbol(parser, IVY_SYM_HYPHEN)) {
|
||||
result = parse_msg(parser, &msg);
|
||||
} else if (peek_symbol(parser, IVY_SYM_PLUS)) {
|
||||
result = parse_msg(parser, &msg);
|
||||
} else if (peek_word(parser)) {
|
||||
result = parse_property(parser, &property);
|
||||
} else {
|
||||
parse_trace(
|
||||
parser, "unexpected token %s in class",
|
||||
ivy_token_to_string(peek_token(parser)));
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg) {
|
||||
fx_queue_push_back(&class->n_msg_handlers, &msg->n_entry);
|
||||
} else if (property) {
|
||||
fx_queue_push_back(
|
||||
&class->n_msg_handlers, &property->n_entry);
|
||||
}
|
||||
}
|
||||
|
||||
*out = generic_node(class);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/parse.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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 = out;
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
void ivy_parser_destroy(struct ivy_parser *parser)
|
||||
{
|
||||
free(parser);
|
||||
}
|
||||
|
||||
enum ivy_status ivy_parser_set_diag_ctx(
|
||||
struct ivy_parser *parser, struct ivy_diag_ctx *ctx)
|
||||
{
|
||||
parser->p_diag = ctx;
|
||||
return IVY_OK;
|
||||
}
|
||||
|
||||
enum ivy_status ivy_parser_get_status(struct ivy_parser *parser)
|
||||
{
|
||||
return parser->p_status;
|
||||
}
|
||||
|
||||
enum ivy_status ivy_parser_parse(
|
||||
struct ivy_parser *parser, struct ivy_lexer *src, struct ivy_ast_node **out)
|
||||
{
|
||||
parser->p_src = src;
|
||||
enum ivy_status status = parse_unit(parser, out);
|
||||
if (status == IVY_ERR_EOF && *out != NULL) {
|
||||
status = IVY_OK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
struct ivy_token *peek_token(struct ivy_parser *parser)
|
||||
{
|
||||
fx_queue_entry *entry = fx_queue_first(&parser->p_tokens);
|
||||
if (!entry) {
|
||||
return ivy_lexer_peek(parser->p_src);
|
||||
}
|
||||
|
||||
return fx_unbox(struct ivy_token, entry, t_entry);
|
||||
}
|
||||
|
||||
struct ivy_token *peek_next_token(struct ivy_parser *parser)
|
||||
{
|
||||
if (fx_queue_empty(&parser->p_tokens)) {
|
||||
struct ivy_token *tok = parse_token(parser);
|
||||
fx_queue_push_back(&parser->p_tokens, &tok->t_entry);
|
||||
return ivy_lexer_peek(parser->p_src);
|
||||
}
|
||||
|
||||
fx_queue_entry *buf = fx_queue_first(&parser->p_tokens);
|
||||
if (buf) {
|
||||
buf = fx_queue_next(buf);
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
return fx_unbox(struct ivy_token, buf, t_entry);
|
||||
}
|
||||
|
||||
return ivy_lexer_peek(parser->p_src);
|
||||
}
|
||||
|
||||
struct ivy_token *parse_token(struct ivy_parser *parser)
|
||||
{
|
||||
fx_queue_entry *entry = fx_queue_pop_front(&parser->p_tokens);
|
||||
if (!entry) {
|
||||
return ivy_lexer_read(parser->p_src);
|
||||
}
|
||||
|
||||
return fx_unbox(struct ivy_token, entry, t_entry);
|
||||
}
|
||||
|
||||
void discard_token(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = parse_token(parser);
|
||||
if (tok) {
|
||||
ivy_token_destroy(tok);
|
||||
}
|
||||
}
|
||||
|
||||
void __parse_trace(
|
||||
struct ivy_parser *parser, const char *func, int line,
|
||||
const char *format, ...)
|
||||
{
|
||||
struct ivy_token *tok = NULL;
|
||||
if (parser) {
|
||||
tok = peek_token(parser);
|
||||
if (tok) {
|
||||
fprintf(stderr, "[%zu:%zu] ", tok->t_start.c_row,
|
||||
tok->t_start.c_col);
|
||||
} else {
|
||||
fprintf(stderr, "[EOF] ");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "[UNK] ");
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s:%d: ", func, line);
|
||||
|
||||
if (tok) {
|
||||
fprintf(stderr, "(%s) ", ivy_token_to_string(tok));
|
||||
}
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vfprintf(stderr, format, va);
|
||||
va_end(va);
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#ifndef _LANG_PARSE_CTX_H_
|
||||
#define _LANG_PARSE_CTX_H_
|
||||
|
||||
#include <ivy/lang/lex.h>
|
||||
#include <ivy/status.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define parse_trace(p, ...) \
|
||||
__parse_trace(p, __FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
|
||||
struct ivy_lexer;
|
||||
struct ivy_diag_ctx;
|
||||
struct ivy_ast_node;
|
||||
|
||||
struct ivy_parser {
|
||||
struct ivy_lexer *p_src;
|
||||
struct ivy_diag_ctx *p_diag;
|
||||
enum ivy_status p_status;
|
||||
fx_queue p_tokens;
|
||||
};
|
||||
|
||||
#define create_node(type) ((void *)ivy_ast_node_create(type))
|
||||
#define destroy_node(p) ivy_ast_node_destroy((struct ivy_ast_node *)(p))
|
||||
#define generic_node(p) ((struct ivy_ast_node *)(p))
|
||||
|
||||
enum expr_parse_flags {
|
||||
EXPR_PARSE_NORMAL = 0,
|
||||
EXPR_PARSE_CONSUME_TERMINATOR = 0x01u,
|
||||
EXPR_PARSE_STOP_KW_CONTROL = 0x02u,
|
||||
EXPR_PARSE_STOP_KW_IN = 0x04u,
|
||||
EXPR_PARSE_STOP_COMMA = 0x08u,
|
||||
EXPR_PARSE_STOP_LABEL = 0x10u,
|
||||
EXPR_PARSE_STOP_LEFT_BRACKET = 0x20u,
|
||||
EXPR_PARSE_STOP_TUPLE_TERMINATOR = 0x40u,
|
||||
EXPR_PARSE_STOP_SEMICOLON = 0x80u,
|
||||
};
|
||||
|
||||
extern bool is_tuple_terminator(struct ivy_token *tok);
|
||||
|
||||
extern const struct ivy_operator *get_operator_from_token(struct ivy_token *tok);
|
||||
extern struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok);
|
||||
extern const struct ivy_operator *get_operator_from_node(struct ivy_ast_node *n);
|
||||
|
||||
extern struct ivy_token *peek_token(struct ivy_parser *parser);
|
||||
extern struct ivy_token *peek_next_token(struct ivy_parser *parser);
|
||||
extern struct ivy_token *parse_token(struct ivy_parser *parser);
|
||||
extern void discard_token(struct ivy_parser *parser);
|
||||
|
||||
extern bool peek_word(struct ivy_parser *parser);
|
||||
extern bool peek_keyword(struct ivy_parser *parser, enum ivy_keyword kw);
|
||||
extern bool peek_symbol(struct ivy_parser *parser, enum ivy_symbol sym);
|
||||
extern bool peek_linefeed(struct ivy_parser *parser);
|
||||
|
||||
extern bool parse_eof(struct ivy_parser *parser);
|
||||
extern bool parse_keyword(struct ivy_parser *parser, enum ivy_keyword kw);
|
||||
extern bool parse_symbol(struct ivy_parser *parser, enum ivy_symbol sym);
|
||||
extern bool parse_word(struct ivy_parser *parser, struct ivy_token **out);
|
||||
extern bool parse_string(struct ivy_parser *parser, struct ivy_token **out);
|
||||
extern bool parse_label(struct ivy_parser *parser, struct ivy_token **out);
|
||||
extern bool parse_str_start(struct ivy_parser *parser);
|
||||
extern bool parse_str_end(struct ivy_parser *parser);
|
||||
extern bool parse_linefeed(struct ivy_parser *parser);
|
||||
|
||||
extern bool peek_expr_start(struct ivy_parser *parser);
|
||||
|
||||
extern bool parse_tuple(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *first_item,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_cascade(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *first_msg,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_unary_msg(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *recipient,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_keyword_msg(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *recipient,
|
||||
enum expr_parse_flags flags, struct ivy_ast_node **out);
|
||||
extern bool parse_complex_msg(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *unary_msg,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_fstring(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_index(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *container,
|
||||
struct ivy_ast_node **out);
|
||||
|
||||
extern bool parse_unit(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_block(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_class(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_package(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_match(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_for(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_for_inline(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *body,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_while(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_while_inline(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *body,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_if(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_if_inline(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *body,
|
||||
struct ivy_ast_node **out);
|
||||
extern bool parse_try(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_package_id(struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
extern bool parse_package_import(
|
||||
struct ivy_parser *parser, struct ivy_ast_node **out);
|
||||
|
||||
extern bool parse_expr(
|
||||
struct ivy_parser *parser, enum expr_parse_flags flags,
|
||||
struct ivy_ast_node **out);
|
||||
|
||||
extern void __parse_trace(
|
||||
struct ivy_parser *parser, const char *func, int line,
|
||||
const char *format, ...);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool parse_eof(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
return (!tok && ivy_lexer_get_status(parser->p_src) == IVY_ERR_EOF);
|
||||
}
|
||||
@@ -0,0 +1,966 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
enum expr_component {
|
||||
EXPR_C_NONE = 0,
|
||||
EXPR_C_BINARY_OP,
|
||||
EXPR_C_UNARY_OP,
|
||||
EXPR_C_OPERAND,
|
||||
};
|
||||
|
||||
struct expr_parse_ctx {
|
||||
fx_queue expr_operator_stack, expr_out_queue;
|
||||
enum expr_component expr_prev;
|
||||
enum expr_parse_flags expr_flags;
|
||||
};
|
||||
|
||||
static bool finalise_expr(
|
||||
struct expr_parse_ctx *ctx, struct ivy_ast_node **out,
|
||||
enum ivy_operator_precedence minimum_precedence);
|
||||
|
||||
bool peek_expr_start(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_INT:
|
||||
case IVY_TOK_ATOM:
|
||||
case IVY_TOK_DOUBLE:
|
||||
case IVY_TOK_IDENT:
|
||||
case IVY_TOK_STRING:
|
||||
case IVY_TOK_STR_START:
|
||||
return true;
|
||||
case IVY_TOK_KEYWORD:
|
||||
switch (tok->t_keyword) {
|
||||
case IVY_KW_IF:
|
||||
case IVY_KW_WHILE:
|
||||
case IVY_KW_FOR:
|
||||
case IVY_KW_TRY:
|
||||
case IVY_KW_UNLESS:
|
||||
case IVY_KW_CONTINUE:
|
||||
case IVY_KW_BREAK:
|
||||
case IVY_KW_MATCH:
|
||||
case IVY_KW_TRUE:
|
||||
case IVY_KW_FALSE:
|
||||
case IVY_KW_NULL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case IVY_TOK_SYMBOL:
|
||||
switch (tok->t_symbol) {
|
||||
case IVY_SYM_LEFT_BRACE:
|
||||
case IVY_SYM_LEFT_BRACKET:
|
||||
case IVY_SYM_LEFT_PAREN:
|
||||
case IVY_SYM_CARET:
|
||||
case IVY_SYM_UNDERSCORE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static struct ivy_ast_node *pop_operand(
|
||||
struct expr_parse_ctx *expr, enum ivy_operator_precedence min_precedence)
|
||||
{
|
||||
struct ivy_ast_node *out = NULL;
|
||||
bool ok = finalise_expr(expr, &out, min_precedence);
|
||||
if (!ok) {
|
||||
parse_trace(NULL, "sub-expression is invalid");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool parse_simple_operand(
|
||||
struct ivy_parser *parser, struct expr_parse_ctx *expr)
|
||||
{
|
||||
if (expr->expr_prev == EXPR_C_OPERAND) {
|
||||
parse_trace(parser, "encountered two operands in a row");
|
||||
return false;
|
||||
}
|
||||
|
||||
expr->expr_prev = EXPR_C_OPERAND;
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_INT: {
|
||||
struct ivy_ast_int_node *v = create_node(IVY_AST_INT);
|
||||
v->n_value = parse_token(parser);
|
||||
fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry);
|
||||
return true;
|
||||
}
|
||||
case IVY_TOK_DOUBLE: {
|
||||
struct ivy_ast_double_node *v = create_node(IVY_AST_DOUBLE);
|
||||
v->n_value = parse_token(parser);
|
||||
fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry);
|
||||
return true;
|
||||
}
|
||||
case IVY_TOK_STRING: {
|
||||
struct ivy_ast_string_node *v = create_node(IVY_AST_STRING);
|
||||
v->n_value = parse_token(parser);
|
||||
fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry);
|
||||
return true;
|
||||
}
|
||||
case IVY_TOK_IDENT: {
|
||||
struct ivy_ast_ident_node *v = create_node(IVY_AST_IDENT);
|
||||
v->n_content = parse_token(parser);
|
||||
fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry);
|
||||
return true;
|
||||
}
|
||||
case IVY_TOK_ATOM: {
|
||||
struct ivy_ast_atom_node *v = create_node(IVY_AST_ATOM);
|
||||
v->n_content = parse_token(parser);
|
||||
fx_queue_push_back(&expr->expr_out_queue, &v->n_base.n_entry);
|
||||
return true;
|
||||
}
|
||||
case IVY_TOK_SYMBOL:
|
||||
switch (tok->t_symbol) {
|
||||
case IVY_SYM_UNDERSCORE: {
|
||||
struct ivy_ast_discard_node *v
|
||||
= create_node(IVY_AST_DISCARD);
|
||||
discard_token(parser);
|
||||
fx_queue_push_back(
|
||||
&expr->expr_out_queue, &v->n_base.n_entry);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
parse_trace(
|
||||
parser, "token %s is not a simple operand",
|
||||
ivy_symbol_to_string(tok->t_symbol));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parse_trace(
|
||||
parser, "token %s is not a simple operand",
|
||||
ivy_lex_token_type_to_string(tok->t_type));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void arith_push_operator(struct expr_parse_ctx *state, struct ivy_ast_node *node)
|
||||
{
|
||||
const struct ivy_operator *op = get_operator_from_node(node);
|
||||
if (!op) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
fx_queue_entry *top = fx_queue_last(&state->expr_operator_stack);
|
||||
if (!top) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *top_node
|
||||
= fx_unbox(struct ivy_ast_node, top, n_entry);
|
||||
const struct ivy_operator *top_op = NULL;
|
||||
|
||||
switch (top_node->n_type) {
|
||||
case IVY_AST_OP: {
|
||||
struct ivy_ast_op_node *op_node
|
||||
= (struct ivy_ast_op_node *)top_node;
|
||||
top_op = op_node->n_op;
|
||||
break;
|
||||
}
|
||||
case IVY_AST_MSG: {
|
||||
struct ivy_ast_msg_node *msg_node
|
||||
= (struct ivy_ast_msg_node *)top_node;
|
||||
top_op = ivy_operator_get_by_id(IVY_OP_MSG);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (top_op->op_precedence < op->op_precedence
|
||||
|| (top_op->op_precedence == op->op_precedence
|
||||
&& op->op_associativity != IVY_ASSOCIATIVITY_LEFT)) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_delete(&state->expr_operator_stack, top);
|
||||
fx_queue_push_back(&state->expr_out_queue, top);
|
||||
}
|
||||
|
||||
fx_queue_push_back(&state->expr_operator_stack, &node->n_entry);
|
||||
}
|
||||
|
||||
static bool parse_binary_operator(
|
||||
struct ivy_parser *parser, struct expr_parse_ctx *expr)
|
||||
{
|
||||
struct ivy_token *tok = parse_token(parser);
|
||||
|
||||
if (expr->expr_prev != EXPR_C_OPERAND) {
|
||||
parse_trace(parser, "expected operand before binary operator");
|
||||
return false;
|
||||
}
|
||||
|
||||
expr->expr_prev = EXPR_C_BINARY_OP;
|
||||
|
||||
struct ivy_ast_node *op_node = create_operator_node_from_token(tok);
|
||||
if (!op_node) {
|
||||
parse_trace(parser, "unrecognised binary operator");
|
||||
return false;
|
||||
}
|
||||
|
||||
arith_push_operator(expr, op_node);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool expr_is_empty(struct expr_parse_ctx *expr)
|
||||
{
|
||||
return fx_queue_empty(&expr->expr_out_queue)
|
||||
&& fx_queue_empty(&expr->expr_operator_stack);
|
||||
}
|
||||
|
||||
static bool op_node_is_complete(struct ivy_ast_op_node *node)
|
||||
{
|
||||
if (!node->n_op) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (node->n_op->op_arity) {
|
||||
case IVY_OP_UNARY:
|
||||
return node->n_right != NULL;
|
||||
case IVY_OP_BINARY:
|
||||
return (node->n_left != NULL && node->n_right != NULL);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool finalise_expr(
|
||||
struct expr_parse_ctx *ctx, struct ivy_ast_node **out,
|
||||
enum ivy_operator_precedence minimum_precedence)
|
||||
{
|
||||
fx_queue_entry *entry = NULL;
|
||||
while (true) {
|
||||
entry = fx_queue_pop_back(&ctx->expr_operator_stack);
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *node
|
||||
= fx_unbox(struct ivy_ast_node, entry, n_entry);
|
||||
if (!node) {
|
||||
/* this should never happen */
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct ivy_operator *op = NULL;
|
||||
|
||||
switch (node->n_type) {
|
||||
case IVY_AST_OP: {
|
||||
struct ivy_ast_op_node *n = (struct ivy_ast_op_node *)node;
|
||||
op = n->n_op;
|
||||
break;
|
||||
}
|
||||
case IVY_AST_MSG:
|
||||
/* all unary message operators have the same
|
||||
* pre-defined precedence */
|
||||
op = ivy_operator_get_by_id(IVY_OP_MSG);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* if we aren't processing operators below a certain precedence
|
||||
* then leave them on the stack and stop here. */
|
||||
if (op->op_precedence < minimum_precedence) {
|
||||
fx_queue_push_back(&ctx->expr_operator_stack, entry);
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&ctx->expr_out_queue, entry);
|
||||
}
|
||||
|
||||
fx_queue q = FX_QUEUE_INIT;
|
||||
fx_queue_entry *tmp = NULL;
|
||||
entry = fx_queue_first(&ctx->expr_out_queue);
|
||||
int i = 0;
|
||||
|
||||
while (entry) {
|
||||
struct ivy_ast_node *item
|
||||
= fx_unbox(struct ivy_ast_node, entry, n_entry);
|
||||
fx_queue_entry *next = fx_queue_next(entry);
|
||||
fx_queue_delete(&ctx->expr_out_queue, entry);
|
||||
|
||||
/* if the node is an operand, just push it to a
|
||||
* temporary queue and come back to it later. */
|
||||
if (item->n_type != IVY_AST_OP && item->n_type != IVY_AST_MSG) {
|
||||
/* operand */
|
||||
fx_queue_push_back(&q, &item->n_entry);
|
||||
goto next;
|
||||
}
|
||||
|
||||
const struct ivy_operator *op = NULL;
|
||||
|
||||
if (item->n_type == IVY_AST_MSG) {
|
||||
struct ivy_ast_msg_node *msg
|
||||
= (struct ivy_ast_msg_node *)item;
|
||||
/* if the message has no recipient, it is a unary message,
|
||||
* and the recipient is located on the operand stack.
|
||||
*
|
||||
* if the message DOES have a recipient, it is a
|
||||
* self-contained keyword message, and can be pushed to
|
||||
* the operand queue as-is. */
|
||||
if (!msg->n_recipient) {
|
||||
tmp = fx_queue_pop_back(&q);
|
||||
msg->n_recipient = fx_unbox(
|
||||
struct ivy_ast_node, tmp, n_entry);
|
||||
}
|
||||
fx_queue_push_back(&q, &msg->n_base.n_entry);
|
||||
goto next;
|
||||
}
|
||||
|
||||
struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)item;
|
||||
/* if an operator node is already complete (i.e. it
|
||||
* already has all the operands it needs, it can be
|
||||
* pushed to the operand queue as-is */
|
||||
if (op_node_is_complete(op_node)) {
|
||||
fx_queue_push_back(&q, &item->n_entry);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/* otherwise, pop the relevant operands from the operand
|
||||
* queue... */
|
||||
op = op_node->n_op;
|
||||
tmp = fx_queue_pop_back(&q);
|
||||
op_node->n_right = fx_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
|
||||
if (op_node->n_right) {
|
||||
op_node->n_right->n_parent = (struct ivy_ast_node *)op_node;
|
||||
|
||||
ivy_ast_node_extend_bounds_recursive(
|
||||
(struct ivy_ast_node *)op_node,
|
||||
(struct ivy_ast_node *)tmp);
|
||||
}
|
||||
|
||||
if (op->op_arity == IVY_OP_BINARY) {
|
||||
tmp = fx_queue_pop_back(&q);
|
||||
op_node->n_left
|
||||
= fx_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
|
||||
if (op_node->n_left) {
|
||||
op_node->n_left->n_parent
|
||||
= (struct ivy_ast_node *)op_node;
|
||||
|
||||
ivy_ast_node_extend_bounds_recursive(
|
||||
(struct ivy_ast_node *)op_node,
|
||||
(struct ivy_ast_node *)tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* ...and push the newly-completed operator node to the
|
||||
* operand queue */
|
||||
fx_queue_push_back(&q, &op_node->n_base.n_entry);
|
||||
next:
|
||||
entry = next;
|
||||
}
|
||||
|
||||
#if 0
|
||||
debug_printf("** after hierarchisation:\n");
|
||||
print_expr_queues(state);
|
||||
#endif
|
||||
|
||||
/* if we are not processing operators below a certain precedence,
|
||||
* i.e. when determining the recipient of a keyword-message), these
|
||||
* operators will still be on the parser state's operator stack, but
|
||||
* their operands have just been moved to the temporary operand stack
|
||||
* used above. move them back to the parser state's output queue here
|
||||
* so they can be used later. */
|
||||
entry = fx_queue_first(&ctx->expr_operator_stack);
|
||||
while (entry) {
|
||||
fx_queue_entry *entry2 = fx_queue_pop_front(&q);
|
||||
if (!entry2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&ctx->expr_out_queue, entry2);
|
||||
entry = fx_queue_next(entry);
|
||||
}
|
||||
|
||||
#if 0
|
||||
debug_printf("** after de-linearisation:\n");
|
||||
print_expr_queues(state);
|
||||
ivy_ast_node_print(*expr_tree);
|
||||
debug_printf("------\n");
|
||||
#endif
|
||||
|
||||
/* the final node remaining on the temp operand stack is the
|
||||
* root node of the new expression tree */
|
||||
tmp = fx_queue_pop_back(&q);
|
||||
*out = fx_unbox(struct ivy_ast_node, tmp, n_entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_call(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *target,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) {
|
||||
parse_trace(parser, "expected `(` before call arguments");
|
||||
}
|
||||
|
||||
struct ivy_ast_msg_node *call = create_node(IVY_AST_MSG);
|
||||
call->n_recipient = target;
|
||||
call->n_sel = create_node(IVY_AST_SELECTOR);
|
||||
|
||||
call->n_sel->n_msg_name = ivy_token_create_ident("call");
|
||||
|
||||
bool ok = true;
|
||||
while (ok) {
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fx_queue_empty(&call->n_arg)
|
||||
&& !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `,` or `)` after call argument");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *arg = NULL;
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_COMMA, &arg)) {
|
||||
parse_trace(parser, "invalid call argument");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_token *label = ivy_token_create_discard();
|
||||
fx_queue_push_back(&call->n_sel->n_arg_labels, &label->t_entry);
|
||||
fx_queue_push_back(&call->n_arg, &arg->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(call);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cleanup_expr(struct expr_parse_ctx *ctx)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_expr(
|
||||
struct ivy_parser *parser, enum expr_parse_flags flags,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
struct expr_parse_ctx ctx = {0};
|
||||
ctx.expr_flags = flags;
|
||||
bool ok = true;
|
||||
bool done = false;
|
||||
bool return_expr = false;
|
||||
bool end_without_dot = false;
|
||||
|
||||
while (ok && !done) {
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ((flags & EXPR_PARSE_STOP_TUPLE_TERMINATOR)
|
||||
&& is_tuple_terminator(tok)) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_LINEFEED:
|
||||
discard_token(parser);
|
||||
break;
|
||||
case IVY_TOK_IDENT:
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
struct ivy_ast_node *msg = NULL;
|
||||
ok = parse_unary_msg(parser, NULL, &msg);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue, &msg->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
} else {
|
||||
ok = parse_simple_operand(parser, &ctx);
|
||||
}
|
||||
break;
|
||||
case IVY_TOK_INT:
|
||||
case IVY_TOK_STRING:
|
||||
case IVY_TOK_DOUBLE:
|
||||
case IVY_TOK_ATOM:
|
||||
ok = parse_simple_operand(parser, &ctx);
|
||||
break;
|
||||
case IVY_TOK_STR_START: {
|
||||
struct ivy_ast_node *v = NULL;
|
||||
ok = parse_fstring(parser, &v);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
|
||||
case IVY_TOK_LABEL: {
|
||||
if (flags & EXPR_PARSE_STOP_LABEL) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *recipient
|
||||
= pop_operand(&ctx, IVY_PRECEDENCE_KEYWORD_MSG);
|
||||
if (!recipient) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"no valid recipient for keyword msg");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *v = NULL;
|
||||
ok = parse_keyword_msg(
|
||||
parser, recipient, ctx.expr_flags, &v);
|
||||
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
case IVY_TOK_KEYWORD: {
|
||||
struct ivy_ast_node *operand = NULL;
|
||||
if (expr_is_empty(&ctx)) {
|
||||
end_without_dot = true;
|
||||
}
|
||||
|
||||
switch (tok->t_keyword) {
|
||||
case IVY_KW_ELSE:
|
||||
case IVY_KW_CATCH:
|
||||
done = true;
|
||||
break;
|
||||
case IVY_KW_MATCH:
|
||||
ok = parse_match(parser, &operand);
|
||||
break;
|
||||
case IVY_KW_DO: {
|
||||
discard_token(parser);
|
||||
struct ivy_ast_do_node *do_node
|
||||
= create_node(IVY_AST_DO);
|
||||
ok = parse_block(parser, &do_node->n_block);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
operand = generic_node(do_node);
|
||||
break;
|
||||
}
|
||||
case IVY_KW_IF:
|
||||
if (flags & EXPR_PARSE_STOP_KW_CONTROL) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
struct ivy_ast_node *body = pop_operand(
|
||||
&ctx, IVY_PRECEDENCE_IF_ELSE);
|
||||
if (!body) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"invalid "
|
||||
"inline-if "
|
||||
"body");
|
||||
}
|
||||
|
||||
ok = parse_if_inline(parser, body, &operand);
|
||||
} else {
|
||||
ok = parse_if(parser, &operand);
|
||||
}
|
||||
break;
|
||||
case IVY_KW_FOR:
|
||||
if (flags & EXPR_PARSE_STOP_KW_CONTROL) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
struct ivy_ast_node *body = pop_operand(
|
||||
&ctx, IVY_PRECEDENCE_IF_ELSE);
|
||||
if (!body) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"invalid "
|
||||
"inline-for "
|
||||
"body");
|
||||
}
|
||||
|
||||
ok = parse_for_inline(
|
||||
parser, body, &operand);
|
||||
} else {
|
||||
ok = parse_for(parser, &operand);
|
||||
}
|
||||
|
||||
break;
|
||||
case IVY_KW_WHILE:
|
||||
if (flags & EXPR_PARSE_STOP_KW_CONTROL) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
struct ivy_ast_node *body = pop_operand(
|
||||
&ctx, IVY_PRECEDENCE_IF_ELSE);
|
||||
if (!body) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"invalid "
|
||||
"inline-while "
|
||||
"body");
|
||||
}
|
||||
|
||||
ok = parse_while_inline(
|
||||
parser, body, &operand);
|
||||
} else {
|
||||
ok = parse_while(parser, &operand);
|
||||
}
|
||||
break;
|
||||
case IVY_KW_IN:
|
||||
if (flags & EXPR_PARSE_STOP_KW_IN) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case IVY_KW_IS:
|
||||
ok = parse_binary_operator(parser, &ctx);
|
||||
break;
|
||||
case IVY_KW_TRY:
|
||||
if (flags & EXPR_PARSE_STOP_KW_CONTROL) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = parse_try(parser, &operand);
|
||||
break;
|
||||
default:
|
||||
parse_trace(
|
||||
parser, "unrecognised keyword %s",
|
||||
ivy_keyword_to_string(tok->t_keyword));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ok && operand) {
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue, &operand->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
|
||||
if (end_without_dot && parse_linefeed(parser)) {
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case IVY_TOK_SYMBOL:
|
||||
switch (tok->t_symbol) {
|
||||
case IVY_SYM_DOUBLE_COLON:
|
||||
case IVY_SYM_PLUS:
|
||||
case IVY_SYM_HYPHEN:
|
||||
case IVY_SYM_FORWARD_SLASH:
|
||||
case IVY_SYM_ASTERISK:
|
||||
case IVY_SYM_PERCENT:
|
||||
case IVY_SYM_AMPERSAND:
|
||||
case IVY_SYM_EQUAL:
|
||||
case IVY_SYM_HYPHEN_RIGHT_ANGLE:
|
||||
case IVY_SYM_DOUBLE_EQUAL:
|
||||
case IVY_SYM_LEFT_ANGLE:
|
||||
case IVY_SYM_RIGHT_ANGLE:
|
||||
case IVY_SYM_DOUBLE_LEFT_ANGLE:
|
||||
case IVY_SYM_DOUBLE_RIGHT_ANGLE:
|
||||
case IVY_SYM_LEFT_ANGLE_EQUAL:
|
||||
case IVY_SYM_RIGHT_ANGLE_EQUAL:
|
||||
case IVY_SYM_DOUBLE_LEFT_ANGLE_EQUAL:
|
||||
case IVY_SYM_DOUBLE_RIGHT_ANGLE_EQUAL:
|
||||
case IVY_SYM_PLUS_EQUAL:
|
||||
case IVY_SYM_HYPHEN_EQUAL:
|
||||
case IVY_SYM_FORWARD_SLASH_EQUAL:
|
||||
case IVY_SYM_ASTERISK_EQUAL:
|
||||
case IVY_SYM_AMPERSAND_EQUAL:
|
||||
case IVY_SYM_PIPE_EQUAL:
|
||||
case IVY_SYM_PERCENT_EQUAL:
|
||||
case IVY_SYM_CARET_EQUAL:
|
||||
case IVY_SYM_BANG_EQUAL:
|
||||
ok = parse_binary_operator(parser, &ctx);
|
||||
break;
|
||||
case IVY_SYM_EQUAL_RIGHT_ANGLE:
|
||||
done = true;
|
||||
break;
|
||||
case IVY_SYM_UNDERSCORE:
|
||||
ok = parse_simple_operand(parser, &ctx);
|
||||
break;
|
||||
case IVY_SYM_COMMA: {
|
||||
if (flags & EXPR_PARSE_STOP_COMMA) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *first = pop_operand(
|
||||
&ctx, IVY_PRECEDENCE_KEYWORD_MSG);
|
||||
if (!first) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"no valid item for tuple");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *v = NULL;
|
||||
ok = parse_tuple(parser, first, &v);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
|
||||
case IVY_SYM_SEMICOLON: {
|
||||
if (flags & EXPR_PARSE_STOP_SEMICOLON) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *first = pop_operand(
|
||||
&ctx, IVY_PRECEDENCE_CASCADE);
|
||||
if (!first) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"no valid recipient for "
|
||||
"cascade");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *v = NULL;
|
||||
ok = parse_cascade(parser, first, &v);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&ctx.expr_out_queue, &v->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
|
||||
case IVY_SYM_LEFT_PAREN: {
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
fx_queue_entry *entry = fx_queue_pop_back(
|
||||
&ctx.expr_out_queue);
|
||||
if (!entry) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"no valid recipient "
|
||||
"for complex msg");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *target = fx_unbox(
|
||||
struct ivy_ast_node, entry,
|
||||
n_entry);
|
||||
if (target->n_type == IVY_AST_MSG) {
|
||||
ok = parse_complex_msg(
|
||||
parser, target, &target);
|
||||
} else {
|
||||
ok = parse_call(
|
||||
parser, target, &target);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue,
|
||||
&target->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *subexpr = NULL;
|
||||
discard_token(parser);
|
||||
ok = parse_expr(parser, EXPR_PARSE_NORMAL, &subexpr);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `)` after "
|
||||
"parenthesized "
|
||||
"expression");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue, &subexpr->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
|
||||
case IVY_SYM_LEFT_BRACKET: {
|
||||
if (flags & EXPR_PARSE_STOP_LEFT_BRACKET) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
struct ivy_ast_node *container = pop_operand(
|
||||
&ctx, IVY_PRECEDENCE_SUBSCRIPT);
|
||||
if (!container) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"invalid subscript "
|
||||
"container");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *v = NULL;
|
||||
ok = parse_index(parser, container, &v);
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue, &v->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *block = NULL;
|
||||
ok = parse_block(parser, &block);
|
||||
if (ok) {
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue,
|
||||
&block->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case IVY_SYM_LEFT_BRACE: {
|
||||
if (ctx.expr_prev == EXPR_C_OPERAND) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"package cannot be "
|
||||
"used after "
|
||||
"operand");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *pkg = NULL;
|
||||
ok = parse_package(parser, &pkg);
|
||||
if (ok) {
|
||||
fx_queue_push_back(
|
||||
&ctx.expr_out_queue, &pkg->n_entry);
|
||||
ctx.expr_prev = EXPR_C_OPERAND;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IVY_SYM_DOT: {
|
||||
struct ivy_token *dot = tok;
|
||||
struct ivy_token *next = peek_next_token(parser);
|
||||
if (next && next->t_type == IVY_TOK_LINEFEED) {
|
||||
if (flags & EXPR_PARSE_CONSUME_TERMINATOR) {
|
||||
discard_token(parser);
|
||||
}
|
||||
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = parse_binary_operator(parser, &ctx);
|
||||
break;
|
||||
}
|
||||
case IVY_SYM_CARET: {
|
||||
if (expr_is_empty(&ctx)) {
|
||||
if (return_expr) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"`^` can only "
|
||||
"be used "
|
||||
"once in "
|
||||
"an "
|
||||
"expression");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
discard_token(parser);
|
||||
return_expr = true;
|
||||
break;
|
||||
}
|
||||
|
||||
ok = parse_binary_operator(parser, &ctx);
|
||||
break;
|
||||
}
|
||||
case IVY_SYM_RIGHT_PAREN:
|
||||
case IVY_SYM_RIGHT_BRACE:
|
||||
case IVY_SYM_RIGHT_BRACKET:
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
parse_trace(
|
||||
parser, "unrecognised symbol %s",
|
||||
ivy_symbol_to_string(tok->t_symbol));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
parse_trace(
|
||||
parser, "unrecognised token %s",
|
||||
ivy_lex_token_type_to_string(tok->t_type));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
cleanup_expr(&ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
ok = finalise_expr(&ctx, out, IVY_PRECEDENCE_ASSIGN);
|
||||
if (!ok) {
|
||||
cleanup_expr(&ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (return_expr) {
|
||||
struct ivy_ast_return_node *ret = create_node(IVY_AST_RETURN);
|
||||
ret->n_val = *out;
|
||||
*out = generic_node(ret);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_for(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_FOR)) {
|
||||
parse_trace(parser, "expected `for` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_for_loop_node *for_node = create_node(IVY_AST_FOR_LOOP);
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_KW_IN, &for_node->n_iterator)) {
|
||||
parse_trace(parser, "invalid for-loop iterator");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_keyword(parser, IVY_KW_IN)) {
|
||||
parse_trace(parser, "expected `in` after for-loop iterator");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &for_node->n_iterable)) {
|
||||
parse_trace(parser, "invalid for-loop iterable");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_block(parser, &for_node->n_body)) {
|
||||
parse_trace(parser, "invalid for-loop body");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(for_node);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_for_inline(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *body,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_FOR)) {
|
||||
parse_trace(parser, "expected `for` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_for_loop_node *for_node = create_node(IVY_AST_FOR_LOOP);
|
||||
for_node->n_body = body;
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_KW_IN, &for_node->n_iterator)) {
|
||||
parse_trace(parser, "invalid for-loop iterator");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_keyword(parser, IVY_KW_IN)) {
|
||||
parse_trace(parser, "expected `in` after for-loop iterator");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &for_node->n_iterable)) {
|
||||
parse_trace(parser, "invalid for-loop iterable");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(for_node);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_fstring(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_str_start(parser)) {
|
||||
parse_trace(parser, "expected STR_START");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_fstring_node *fstring = create_node(IVY_AST_FSTRING);
|
||||
bool ok = true;
|
||||
|
||||
while (1) {
|
||||
if (parse_str_end(parser)) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_token *tok = NULL;
|
||||
if (parse_string(parser, &tok)) {
|
||||
struct ivy_ast_string_node *string
|
||||
= create_node(IVY_AST_STRING);
|
||||
string->n_value = tok;
|
||||
fx_queue_push_back(
|
||||
&fstring->n_value, &string->n_base.n_entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (parse_symbol(parser, IVY_SYM_LEFT_BRACE)) {
|
||||
struct ivy_ast_node *expr = NULL;
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &expr)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"invalid expression in fstring");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_RIGHT_BRACE)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `}` after expression in "
|
||||
"fstring");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&fstring->n_value, &expr->n_entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
parse_trace(parser, "unexpected token in fstring");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
*out = generic_node(fstring);
|
||||
return ok;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_if(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_IF)) {
|
||||
parse_trace(parser, "expected `if` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_cond_group_node *cond_group
|
||||
= create_node(IVY_AST_COND_GROUP);
|
||||
struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND);
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &cond->n_cond)) {
|
||||
parse_trace(parser, "invalid if predicate");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_block(parser, &cond->n_body)) {
|
||||
parse_trace(parser, "invalid if body");
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry);
|
||||
|
||||
bool ok = true;
|
||||
while (1) {
|
||||
struct ivy_ast_node *branch_pred = NULL;
|
||||
struct ivy_ast_node *branch_block = NULL;
|
||||
if (parse_keyword(parser, IVY_KW_ELIF)) {
|
||||
if (!parse_expr(
|
||||
parser, EXPR_PARSE_STOP_LEFT_BRACKET,
|
||||
&branch_pred)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"invalid elif branch predicate");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
} else if (!parse_keyword(parser, IVY_KW_ELSE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_block(parser, &branch_block)) {
|
||||
parse_trace(parser, "invalid branch body");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND);
|
||||
cond->n_cond = branch_pred;
|
||||
cond->n_body = branch_block;
|
||||
fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry);
|
||||
|
||||
if (!branch_pred) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*out = generic_node(cond_group);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_if_inline(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *body,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_IF)) {
|
||||
parse_trace(parser, "expected `if` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_cond_group_node *cond_group
|
||||
= create_node(IVY_AST_COND_GROUP);
|
||||
struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND);
|
||||
cond->n_body = body;
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &cond->n_cond)) {
|
||||
parse_trace(parser, "invalid if predicate");
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry);
|
||||
|
||||
if (parse_keyword(parser, IVY_KW_ELSE)) {
|
||||
struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND);
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &cond->n_body)) {
|
||||
parse_trace(parser, "invalid else body");
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&cond_group->n_branches, &cond->n_base.n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(cond_group);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_index(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *container,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
parse_trace(parser, "expected `[` before subscript value");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *subscript = NULL;
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &subscript)) {
|
||||
parse_trace(parser, "invalid subscript value");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) {
|
||||
parse_trace(parser, "expected `]` after subscript value");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_op_node *op_node = create_node(IVY_AST_OP);
|
||||
if (!op_node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
op_node->n_op = ivy_operator_get_by_id(IVY_OP_SUBSCRIPT);
|
||||
op_node->n_left = container;
|
||||
op_node->n_right = subscript;
|
||||
|
||||
*out = generic_node(op_node);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool peek_keyword(struct ivy_parser *parser, enum ivy_keyword kw)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_KEYWORD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tok->t_keyword != kw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_keyword(struct ivy_parser *parser, enum ivy_keyword kw)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_KEYWORD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tok->t_keyword != kw) {
|
||||
return false;
|
||||
}
|
||||
|
||||
parse_token(parser);
|
||||
ivy_token_destroy(tok);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool peek_label(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
return (!tok || tok->t_type == IVY_TOK_LABEL);
|
||||
}
|
||||
|
||||
bool parse_label(struct ivy_parser *parser, struct ivy_token **out)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_LABEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = parse_token(parser);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool peek_linefeed(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
return (tok && tok->t_type == IVY_TOK_LINEFEED);
|
||||
}
|
||||
|
||||
bool parse_linefeed(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_LINEFEED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ivy_lexer_read(parser->p_src);
|
||||
ivy_token_destroy(tok);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_match(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_MATCH)) {
|
||||
parse_trace(parser, "expected `match` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_match_node *match = create_node(IVY_AST_MATCH);
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &match->n_cond)) {
|
||||
parse_trace(parser, "invalid match predicate");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
parse_trace(parser, "expected `[` after match predicate");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
while (1) {
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_BRACKET)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fx_queue_empty(&match->n_branches)
|
||||
&& !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `,` or `]` after match branch value");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *branch_pred = NULL;
|
||||
struct ivy_ast_node *branch_value = NULL;
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &branch_pred)) {
|
||||
parse_trace(parser, "invalid match branch predicate");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_EQUAL_RIGHT_ANGLE)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `=>` after match branch predicate");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (peek_symbol(parser, IVY_SYM_LEFT_BRACKET)) {
|
||||
ok = parse_block(parser, &branch_value);
|
||||
} else {
|
||||
ok = parse_expr(
|
||||
parser, EXPR_PARSE_STOP_COMMA, &branch_value);
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
parse_trace(parser, "invalid match branch value");
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_cond_node *cond = create_node(IVY_AST_COND);
|
||||
cond->n_cond = branch_pred;
|
||||
cond->n_body = branch_value;
|
||||
fx_queue_push_back(&match->n_branches, &cond->n_base.n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(match);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_unary_msg(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *recipient,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
struct ivy_token *selector_tok = NULL;
|
||||
if (!parse_word(parser, &selector_tok)) {
|
||||
parse_trace(parser, "expected unary message selector");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_selector_node *sel = create_node(IVY_AST_SELECTOR);
|
||||
sel->n_msg_name = selector_tok;
|
||||
|
||||
struct ivy_ast_msg_node *msg = create_node(IVY_AST_MSG);
|
||||
msg->n_sel = sel;
|
||||
msg->n_recipient = recipient;
|
||||
|
||||
*out = generic_node(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_keyword_msg(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *recipient,
|
||||
enum expr_parse_flags flags, struct ivy_ast_node **out)
|
||||
{
|
||||
#if 0
|
||||
if (!recipient) {
|
||||
recipient = pop_operand(expr, IVY_PRECEDENCE_KEYWORD_MSG);
|
||||
}
|
||||
|
||||
if (!recipient) {
|
||||
parse_trace(parser, "no valid recipient for keyword msg");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ivy_ast_selector_node *sel = create_node(IVY_AST_SELECTOR);
|
||||
struct ivy_ast_msg_node *msg = create_node(IVY_AST_MSG);
|
||||
msg->n_recipient = recipient;
|
||||
msg->n_sel = sel;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
while (1) {
|
||||
struct ivy_token *label = NULL;
|
||||
if (!parse_label(parser, &label)) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *value = NULL;
|
||||
flags |= EXPR_PARSE_STOP_LABEL;
|
||||
flags |= EXPR_PARSE_STOP_SEMICOLON;
|
||||
flags |= EXPR_PARSE_STOP_KW_CONTROL;
|
||||
flags &= ~EXPR_PARSE_CONSUME_TERMINATOR;
|
||||
|
||||
if (!parse_expr(parser, flags, &value)) {
|
||||
parse_trace(parser, "invalid keyword msg arg value");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&sel->n_arg_labels, &label->t_entry);
|
||||
fx_queue_push_back(&msg->n_arg, &value->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_complex_msg(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *msg_node,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_PAREN)) {
|
||||
parse_trace(parser, "expected `(` before complex msg arg list");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!msg) {
|
||||
fx_queue_entry *entry = fx_queue_pop_back(&expr->expr_out_queue);
|
||||
if (!entry) {
|
||||
parse_trace(
|
||||
parser, "no valid recipient for complex msg");
|
||||
return false;
|
||||
}
|
||||
|
||||
msg = fx_unbox(struct ivy_ast_msg_node, entry, n_base.n_entry);
|
||||
if (msg->n_base.n_type != IVY_AST_MSG) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"previous expression is not a unary message");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ivy_ast_msg_node *msg = (struct ivy_ast_msg_node *)msg_node;
|
||||
struct ivy_ast_selector_node *sel = msg->n_sel;
|
||||
msg->n_sel = sel;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
while (1) {
|
||||
struct ivy_token *label = NULL;
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_PAREN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fx_queue_empty(&msg->n_arg)
|
||||
&& !parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(
|
||||
parser, "expected `,` after complex msg arg");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (parse_label(parser, &label)) {
|
||||
fx_queue_push_back(&sel->n_arg_labels, &label->t_entry);
|
||||
} else {
|
||||
label = ivy_token_create_discard();
|
||||
fx_queue_push_back(&sel->n_arg_labels, &label->t_entry);
|
||||
}
|
||||
|
||||
struct ivy_ast_node *value = NULL;
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_COMMA, &value)) {
|
||||
parse_trace(parser, "invalid complex msg arg value");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&msg->n_arg, &value->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
#include <ivy/lang/operator.h>
|
||||
|
||||
const struct ivy_operator *get_operator_from_token(struct ivy_token *tok)
|
||||
{
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_SYMBOL:
|
||||
return ivy_operator_get_by_token(tok->t_symbol);
|
||||
case IVY_TOK_KEYWORD:
|
||||
return ivy_operator_get_by_token(tok->t_keyword);
|
||||
default:
|
||||
return ivy_operator_get_by_token(tok->t_type);
|
||||
}
|
||||
}
|
||||
|
||||
struct ivy_ast_node *create_operator_node_from_token(struct ivy_token *tok)
|
||||
{
|
||||
const struct ivy_operator *op = get_operator_from_token(tok);
|
||||
if (!op) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ivy_ast_op_node *op_node = create_node(IVY_AST_OP);
|
||||
op_node->n_op = op;
|
||||
ivy_ast_node_set_bounds_from_token(generic_node(op_node), tok);
|
||||
return generic_node(op_node);
|
||||
}
|
||||
|
||||
const struct ivy_operator *get_operator_from_node(struct ivy_ast_node *n)
|
||||
{
|
||||
switch (n->n_type) {
|
||||
case IVY_AST_OP: {
|
||||
struct ivy_ast_op_node *op = (struct ivy_ast_op_node *)n;
|
||||
return op->n_op;
|
||||
}
|
||||
case IVY_AST_MSG:
|
||||
return ivy_operator_get_by_id(IVY_OP_MSG);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_package_id(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_PACKAGE)) {
|
||||
parse_trace(NULL, "expected `package` before package statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_unit_package_node *unit_pkg
|
||||
= create_node(IVY_AST_UNIT_PACKAGE);
|
||||
|
||||
struct ivy_token *tok = NULL;
|
||||
if (!parse_word(parser, &tok)) {
|
||||
parse_trace(NULL, "expected word after `package` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&unit_pkg->n_ident, &tok->t_entry);
|
||||
|
||||
while (1) {
|
||||
if (parse_linefeed(parser)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_DOT)) {
|
||||
parse_trace(
|
||||
NULL,
|
||||
"expected linefeed or `.` after package "
|
||||
"identifier word");
|
||||
destroy_node(unit_pkg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_word(parser, &tok)) {
|
||||
parse_trace(
|
||||
NULL, "expected word after `package` keyword");
|
||||
destroy_node(unit_pkg);
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&unit_pkg->n_ident, &tok->t_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(unit_pkg);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_package_import(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_USE)) {
|
||||
parse_trace(
|
||||
NULL, "expected `use` before package import statement");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_unit_import_node *unit_import
|
||||
= create_node(IVY_AST_UNIT_IMPORT);
|
||||
|
||||
struct ivy_token *tok = NULL;
|
||||
if (!parse_word(parser, &tok)) {
|
||||
parse_trace(NULL, "expected word after `use` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&unit_import->n_ident, &tok->t_entry);
|
||||
|
||||
while (1) {
|
||||
if (parse_linefeed(parser)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_DOT)) {
|
||||
parse_trace(
|
||||
NULL,
|
||||
"expected linefeed or `.` after package "
|
||||
"identifier word");
|
||||
destroy_node(unit_import);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_word(parser, &tok)) {
|
||||
parse_trace(NULL, "expected word after `use` keyword");
|
||||
destroy_node(unit_import);
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&unit_import->n_ident, &tok->t_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(unit_import);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
static bool parse_dynamic_package(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *expr,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_FOR)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `for` after package comprehension "
|
||||
"expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_pkg_dynamic_node *pkg = create_node(IVY_AST_PKG_DYNAMIC);
|
||||
pkg->n_transform = expr;
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_KW_IN, &pkg->n_item)) {
|
||||
parse_trace(parser, "invalid package comprehension item");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_keyword(parser, IVY_KW_IN)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `in` after package comprehension item");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &pkg->n_item)) {
|
||||
parse_trace(parser, "invalid package comprehension container");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_RIGHT_BRACE)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `}` after package comprehension container");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(pkg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_package(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_symbol(parser, IVY_SYM_LEFT_BRACE)) {
|
||||
parse_trace(parser, "expected `{`");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *item = NULL;
|
||||
if (!parse_expr(
|
||||
parser, EXPR_PARSE_STOP_COMMA | EXPR_PARSE_STOP_KW_CONTROL,
|
||||
&item)) {
|
||||
parse_trace(parser, "invalid package item");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (peek_keyword(parser, IVY_KW_FOR)) {
|
||||
return parse_dynamic_package(parser, item, out);
|
||||
}
|
||||
|
||||
struct ivy_ast_pkg_static_node *pkg = create_node(IVY_AST_PKG_STATIC);
|
||||
if (item) {
|
||||
fx_queue_push_back(&pkg->n_items, &item->n_entry);
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
while (ok) {
|
||||
parse_linefeed(parser);
|
||||
|
||||
if (parse_symbol(parser, IVY_SYM_RIGHT_BRACE)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(
|
||||
parser,
|
||||
"expected `,` or `}` after package item");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_expr(
|
||||
parser,
|
||||
EXPR_PARSE_STOP_COMMA | EXPR_PARSE_STOP_KW_CONTROL,
|
||||
&item)) {
|
||||
parse_trace(parser, "invalid package item");
|
||||
return false;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&pkg->n_items, &item->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(pkg);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool parse_string(struct ivy_parser *parser, struct ivy_token **out)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_STRING) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = parse_token(parser);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_str_start(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (tok->t_type != IVY_TOK_STR_START) {
|
||||
return false;
|
||||
}
|
||||
|
||||
parse_token(parser);
|
||||
ivy_token_destroy(tok);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_str_end(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (tok->t_type != IVY_TOK_STR_END) {
|
||||
return false;
|
||||
}
|
||||
|
||||
parse_token(parser);
|
||||
ivy_token_destroy(tok);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool peek_symbol(struct ivy_parser *parser, enum ivy_symbol sym)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_SYMBOL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tok->t_symbol != sym) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_symbol(struct ivy_parser *parser, enum ivy_symbol sym)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_SYMBOL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tok->t_symbol != sym) {
|
||||
return false;
|
||||
}
|
||||
|
||||
parse_token(parser);
|
||||
ivy_token_destroy(tok);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_try(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_TRY)) {
|
||||
parse_trace(parser, "expected `try` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_try_node *try = create_node(IVY_AST_TRY);
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_KW_CONTROL, &try->n_try)) {
|
||||
parse_trace(parser, "invalid try block");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
while (1) {
|
||||
if (!parse_keyword(parser, IVY_KW_CATCH)) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *catch_guard = NULL;
|
||||
struct ivy_ast_node *catch_block = NULL;
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &catch_guard)) {
|
||||
parse_trace(parser, "invalid catch guard");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_block(parser, &catch_block)) {
|
||||
parse_trace(parser, "invalid catch block");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_try_catch_node *catch
|
||||
= create_node(IVY_AST_TRY_CATCH);
|
||||
catch->n_pattern = catch_guard;
|
||||
catch->n_block = catch_block;
|
||||
fx_queue_push_back(&try->n_catch, &catch->n_base.n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(try);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool is_tuple_terminator(struct ivy_token *tok)
|
||||
{
|
||||
const struct ivy_operator *op = get_operator_from_token(tok);
|
||||
switch (tok->t_type) {
|
||||
case IVY_TOK_SYMBOL:
|
||||
switch (tok->t_symbol) {
|
||||
case IVY_SYM_DOT:
|
||||
case IVY_SYM_RIGHT_PAREN:
|
||||
case IVY_SYM_RIGHT_BRACE:
|
||||
case IVY_SYM_RIGHT_BRACKET:
|
||||
return true;
|
||||
default:
|
||||
op = get_operator_from_token(tok);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (op && op->op_precedence < IVY_PRECEDENCE_KEYWORD_MSG) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_tuple(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *first_item,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
struct ivy_ast_tuple_node *tuple = create_node(IVY_AST_TUPLE);
|
||||
fx_queue_push_back(&tuple->n_members, &first_item->n_entry);
|
||||
|
||||
bool ok = true;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok) {
|
||||
parse_trace(
|
||||
parser, "unexpected EOF while parsing tuple");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_tuple_terminator(tok)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!parse_symbol(parser, IVY_SYM_COMMA)) {
|
||||
parse_trace(parser, "expected `,` after tuple item");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
struct ivy_ast_node *value = NULL;
|
||||
if (!parse_expr(
|
||||
parser,
|
||||
EXPR_PARSE_STOP_COMMA | EXPR_PARSE_STOP_TUPLE_TERMINATOR,
|
||||
&value)) {
|
||||
parse_trace(parser, "invalid tuple item");
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&tuple->n_members, &value->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(tuple);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_unit(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
struct ivy_ast_unit_node *unit
|
||||
= (struct ivy_ast_unit_node *)ivy_ast_node_create(IVY_AST_UNIT);
|
||||
if (!unit) {
|
||||
parser->p_status = IVY_ERR_NO_MEMORY;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
bool prev_was_expr = false;
|
||||
while (1) {
|
||||
struct ivy_ast_node *child = NULL;
|
||||
|
||||
if (parse_eof(parser)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (parse_linefeed(parser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peek_keyword(parser, IVY_KW_PACKAGE)) {
|
||||
result = parse_package_id(parser, &child);
|
||||
} else if (peek_keyword(parser, IVY_KW_USE)) {
|
||||
result = parse_package_import(parser, &child);
|
||||
} else if (peek_keyword(parser, IVY_KW_CLASS)) {
|
||||
result = parse_class(parser, &child);
|
||||
} else if (peek_expr_start(parser)) {
|
||||
result = parse_expr(
|
||||
parser, EXPR_PARSE_CONSUME_TERMINATOR, &child);
|
||||
} else {
|
||||
parse_trace(parser, "unexpected token");
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result || !child) {
|
||||
break;
|
||||
}
|
||||
|
||||
fx_queue_push_back(&unit->n_children, &child->n_entry);
|
||||
}
|
||||
|
||||
*out = generic_node(unit);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include "ctx.h"
|
||||
|
||||
#include <ivy/lang/ast.h>
|
||||
|
||||
bool parse_while(struct ivy_parser *parser, struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_WHILE)) {
|
||||
parse_trace(parser, "expected `while` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_while_loop_node *while_node
|
||||
= create_node(IVY_AST_WHILE_LOOP);
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_STOP_LEFT_BRACKET, &while_node->n_cond)) {
|
||||
parse_trace(parser, "invalid while condition");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_block(parser, &while_node->n_body)) {
|
||||
parse_trace(parser, "invalid while body");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(while_node);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_while_inline(
|
||||
struct ivy_parser *parser, struct ivy_ast_node *body,
|
||||
struct ivy_ast_node **out)
|
||||
{
|
||||
if (!parse_keyword(parser, IVY_KW_WHILE)) {
|
||||
parse_trace(parser, "expected `while` keyword");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ivy_ast_while_loop_node *while_node
|
||||
= create_node(IVY_AST_WHILE_LOOP);
|
||||
while_node->n_body = body;
|
||||
|
||||
if (!parse_expr(parser, EXPR_PARSE_NORMAL, &while_node->n_cond)) {
|
||||
parse_trace(parser, "invalid while condition");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = generic_node(while_node);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "ctx.h"
|
||||
|
||||
bool peek_word(struct ivy_parser *parser)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
return (!tok || tok->t_type == IVY_TOK_IDENT);
|
||||
}
|
||||
|
||||
bool parse_word(struct ivy_parser *parser, struct ivy_token **out)
|
||||
{
|
||||
struct ivy_token *tok = peek_token(parser);
|
||||
if (!tok || tok->t_type != IVY_TOK_IDENT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = parse_token(parser);
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user