lang: replace stack-based parser with a recursive parser

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