Files
ivy/lang/ast/expr.c

474 lines
11 KiB
C
Raw Normal View History

#include "ctx.h"
#include "node.h"
#include <blue/object/string.h>
#include <ivy/lang/operator.h>
#include <ivy/lang/lex.h>
#include <stdio.h>
enum expr_end {
EXPR_END_NONE = 0,
/* arithmetic expressions, terminated with a dot (.) */
EXPR_END_DOT,
/* keyword expressions (if-else, while/for loops, match, etc), terminated with the end keyword. */
EXPR_END_KEYWORD,
};
enum expr_part {
EXPR_NONE = 0,
EXPR_OPERATOR,
EXPR_OPERAND,
};
struct expr_parser_state {
struct parser_state s_base;
enum expr_end s_end;
enum ivy_keyword s_type;
unsigned int s_prev_tok;
enum expr_part s_prev_part;
b_queue s_operand_queue;
b_queue s_operator_stack;
};
static enum ivy_status add_child(
struct ivy_ast_node *parent, struct ivy_ast_node *child)
{
struct ivy_ast_expr_node *expr = (struct ivy_ast_expr_node *)parent;
if (!expr->n_child) {
expr->n_child = child;
return IVY_OK;
}
return IVY_ERR_NOT_SUPPORTED;
}
static void set_previous(struct expr_parser_state *state, struct ivy_token *tok)
{
switch (tok->t_type) {
case IVY_TOK_SYMBOL:
state->s_prev_tok = tok->t_symbol;
state->s_prev_part = EXPR_OPERATOR;
break;
case IVY_TOK_KEYWORD:
state->s_prev_tok = tok->t_keyword;
state->s_prev_part = EXPR_OPERATOR;
break;
default:
state->s_prev_tok = tok->t_type;
state->s_prev_part = EXPR_OPERAND;
break;
}
}
static void print_token(struct ivy_token *tok)
{
switch (tok->t_type) {
case IVY_TOK_IDENT:
printf("%s", tok->t_str);
break;
case IVY_TOK_INT:
printf("%llu", tok->t_int);
break;
case IVY_TOK_DOUBLE:
printf("%.2lf", tok->t_double);
break;
case IVY_TOK_SYMBOL:
printf("%s", ivy_symbol_to_string(tok->t_symbol));
break;
case IVY_TOK_KEYWORD:
printf("%s", ivy_keyword_to_string(tok->t_keyword));
break;
case IVY_TOK_STRING:
printf("\"%s\"", tok->t_str);
break;
default:
printf("<token>");
break;
}
}
static enum ivy_status finalise_expr(struct expr_parser_state *state)
{
b_queue_iterator it = {0};
int i = 0;
b_queue_foreach (&it, &state->s_operand_queue) {
struct ivy_token *operand = b_unbox(struct ivy_token, it.entry, t_entry);
if (i > 0) {
printf(" ");
}
print_token(operand);
i++;
}
b_queue_foreach (&it, &state->s_operator_stack) {
struct ivy_token *operator = b_unbox(struct ivy_token, it.entry, t_entry);
if (i > 0) {
printf(" ");
}
print_token(operator);
i++;
}
printf("\n");
return IVY_OK;
}
static struct token_parse_result parse_ident(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_DOT;
}
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_atom(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_DOT;
}
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_string(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_DOT;
}
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_str_start(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_str_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_label(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_int(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_DOT;
}
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_double(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_DOT;
}
b_queue_push_back(&state->s_operand_queue, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct ivy_operator *get_operator(struct ivy_token *tok)
{
switch (tok->t_type) {
case IVY_TOK_KEYWORD:
return ivy_operator_get(tok->t_keyword);
case IVY_TOK_SYMBOL:
return ivy_operator_get(tok->t_symbol);
default:
return NULL;
}
}
static struct token_parse_result parse_symbol(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end != EXPR_END_DOT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
struct ivy_operator *op = ivy_operator_get(tok->t_symbol);
if (!op) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
while (true) {
b_queue_entry *top_entry = b_queue_last(&state->s_operator_stack);
if (!top_entry) {
break;
}
struct ivy_token *top = b_unbox(struct ivy_token, top_entry, t_entry);
if (ivy_token_is_symbol(top, IVY_SYM_LEFT_PAREN)) {
break;
}
struct ivy_operator *top_op = get_operator(top);
if (top_op->op_precedence < op->op_precedence) {
break;
}
if (top_op->op_precedence == op->op_precedence && op->op_associativity != IVY_ASSOCIATIVITY_LEFT) {
break;
}
b_queue_delete(&state->s_operator_stack, top_entry);
b_queue_push_back(&state->s_operand_queue, top_entry);
}
b_queue_push_back(&state->s_operator_stack, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_left_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_DOT;
}
b_queue_push_back(&state->s_operator_stack, &tok->t_entry);
set_previous(state, tok);
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_right_paren(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_if(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end == EXPR_END_NONE) {
state->s_end = EXPR_END_KEYWORD;
}
return PARSE_RESULT(IVY_OK, 0);
}
static struct token_parse_result parse_else(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_end(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_while(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_for(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_match(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_try(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_catch(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_throw(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_understands(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_in(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_do(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_is(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_and(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_or(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_not(
struct ivy_parser *ctx, struct ivy_token *tok)
{
return PARSE_RESULT(IVY_ERR_IO_FAILURE, 0);
}
static struct token_parse_result parse_bang(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end != EXPR_END_DOT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_expr(state);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(status, PARSE_REPEAT_TOKEN);
}
static struct token_parse_result parse_dot(
struct ivy_parser *ctx, struct ivy_token *tok)
{
struct expr_parser_state *state
= parser_get_state(ctx, struct expr_parser_state);
if (state->s_end != EXPR_END_DOT) {
return PARSE_RESULT(IVY_ERR_BAD_SYNTAX, 0);
}
enum ivy_status status = finalise_expr(state);
parser_pop_state(ctx, STATE_ADD_NODE_TO_PARENT);
return PARSE_RESULT(status, 0);
}
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 = {
[IVY_TOK_IDENT] = parse_ident,
[IVY_TOK_ATOM] = parse_atom,
[IVY_TOK_STRING] = parse_string,
[IVY_TOK_STR_START] = parse_str_start,
[IVY_TOK_STR_END] = parse_str_end,
[IVY_TOK_LABEL] = parse_label,
[IVY_TOK_INT] = parse_int,
[IVY_TOK_DOUBLE] = parse_double,
[IVY_TOK_SYMBOL] = parse_symbol,
},
.n_symbol_parsers = {
[IVY_SYM_BANG] = parse_bang,
[IVY_SYM_DOT] = parse_dot,
[IVY_SYM_LEFT_PAREN] = parse_left_paren,
[IVY_SYM_RIGHT_PAREN] = parse_right_paren,
},
.n_keyword_parsers = {
[IVY_KW_IF] = parse_if,
[IVY_KW_ELSE] = parse_else,
[IVY_KW_END] = parse_end,
[IVY_KW_WHILE] = parse_while,
[IVY_KW_FOR] = parse_for,
[IVY_KW_MATCH] = parse_match,
[IVY_KW_TRY] = parse_try,
[IVY_KW_CATCH] = parse_catch,
[IVY_KW_THROW] = parse_throw,
[IVY_KW_UNDERSTANDS] = parse_understands,
[IVY_KW_IN] = parse_in,
[IVY_KW_DO] = parse_do,
[IVY_KW_IS] = parse_is,
[IVY_KW_AND] = parse_and,
[IVY_KW_OR] = parse_or,
[IVY_KW_NOT] = parse_not,
},
};