Files
mie/mie/parse/parser.c

1865 lines
46 KiB
C

#include <fx/core/bstr.h>
#include <mie/attribute/attribute-definition.h>
#include <mie/attribute/attribute-map.h>
#include <mie/ctx.h>
#include <mie/diag/amendment.h>
#include <mie/diag/diag.h>
#include <mie/diag/highlight.h>
#include <mie/dialect/builtin.h>
#include <mie/dialect/dialect.h>
#include <mie/dialect/index.h>
#include <mie/ir/block.h>
#include <mie/ir/op-definition.h>
#include <mie/ir/op.h>
#include <mie/ir/region.h>
#include <mie/ir/register.h>
#include <mie/ir/resolve.h>
#include <mie/parse/lex.h>
#include <mie/parse/parser.h>
#include <mie/parse/token.h>
#include <mie/type/function.h>
#include <mie/type/type-definition.h>
#include <mie/vector.h>
struct mie_parser {
struct mie_ctx *p_ctx;
struct mie_lex *p_lex;
enum mie_status p_status;
fx_string *s_tmp;
};
static fx_string *get_temp_string(struct mie_parser *parser)
{
fx_string_clear(parser->s_tmp);
return parser->s_tmp;
}
#define GET_SOMETHING_BY_FULL_NAME(thing) \
static const struct mie_##thing##_definition *get_##thing##_by_full_name( \
struct mie_parser *ctx, fx_string *name) \
{ \
fx_string *dialect = fx_string_create(); \
fx_string *item = fx_string_create(); \
const char *delim[] = {"."}; \
size_t i = 0; \
fx_iterator *it = fx_string_tokenise( \
name, delim, 1, FX_STRING_TOK_F_NORMAL); \
while (fx_iterator_is_valid(it)) { \
const char *tok = fx_iterator_get_cvalue(it).v_cptr; \
switch (i) { \
case 0: \
fx_string_append_cstr(dialect, tok); \
break; \
case 1: \
fx_string_append_cstr(item, tok); \
break; \
default: \
fx_string_append_c(item, '.'); \
fx_string_append_cstr(item, tok); \
break; \
} \
fx_iterator_move_next(it); \
i++; \
} \
fx_iterator_unref(it); \
const struct mie_##thing##_definition *def \
= mie_ctx_get_##thing##_definition( \
ctx->p_ctx, fx_string_ptr(dialect), \
fx_string_ptr(item)); \
fx_string_unref(dialect); \
fx_string_unref(item); \
return def; \
}
GET_SOMETHING_BY_FULL_NAME(trait);
GET_SOMETHING_BY_FULL_NAME(type);
GET_SOMETHING_BY_FULL_NAME(attribute);
struct mie_parser *mie_parser_create(struct mie_ctx *ctx, struct mie_lex *lex)
{
struct mie_parser *out = malloc(sizeof *out);
if (!out) {
return NULL;
}
memset(out, 0x0, sizeof *out);
out->s_tmp = fx_string_create();
if (!out->s_tmp) {
free(out);
return NULL;
}
out->p_ctx = ctx;
out->p_lex = lex;
out->p_status = MIE_SUCCESS;
return out;
}
void mie_parser_destroy(struct mie_parser *ctx)
{
if (ctx->s_tmp) {
fx_string_unref(ctx->s_tmp);
}
free(ctx);
}
struct mie_ctx *mie_parser_get_mie_ctx(struct mie_parser *ctx)
{
return ctx->p_ctx;
}
struct mie_lex *mie_parser_get_lexer(struct mie_parser *ctx)
{
return ctx->p_lex;
}
enum mie_status mie_parser_get_status(const struct mie_parser *ctx)
{
return ctx->p_status;
}
void mie_parser_set_status(struct mie_parser *ctx, enum mie_status status)
{
ctx->p_status = status;
}
fx_string *mie_parser_get_tempstr(struct mie_parser *ctx)
{
return get_temp_string(ctx);
}
struct mie_token *mie_parser_peek(struct mie_parser *ctx)
{
return mie_lex_peek(ctx->p_lex);
}
enum mie_token_type mie_parser_peek_type(struct mie_parser *ctx)
{
return MIE_TOKEN_TYPE(mie_lex_peek(ctx->p_lex));
}
enum mie_token_symbol mie_parser_peek_symbol(struct mie_parser *ctx)
{
struct mie_token *tok = mie_lex_peek(ctx->p_lex);
if (MIE_TOKEN_TYPE(tok) != MIE_TOK_SYMBOL) {
return MIE_SYM_NONE;
}
return tok->tok_sym;
}
bool mie_parser_check_eof(struct mie_parser *ctx)
{
return mie_lex_peek(ctx->p_lex) == NULL;
}
bool mie_parser_check_type(struct mie_parser *ctx, enum mie_token_type type)
{
return MIE_TOKEN_IS(mie_lex_peek(ctx->p_lex), type);
}
bool mie_parser_check_symbol(struct mie_parser *ctx, enum mie_token_symbol sym)
{
return MIE_TOKEN_IS_SYMBOL(mie_lex_peek(ctx->p_lex), sym);
}
bool mie_parser_advance(struct mie_parser *ctx)
{
mie_lex_advance(ctx->p_lex);
return mie_lex_get_status(ctx->p_lex) == MIE_SUCCESS;
}
bool mie_parser_parse_int(
struct mie_parser *ctx, long long *out, struct mie_file_span *loc)
{
if (!mie_parser_check_type(ctx, MIE_TOK_INT)) {
return false;
}
struct mie_token *tok = mie_lex_peek(ctx->p_lex);
if (tok->tok_value_type != MIE_TOK_V_INT) {
return false;
}
if (loc) {
mie_file_span_init(loc, tok);
}
*out = tok->tok_int;
mie_lex_advance(ctx->p_lex);
return true;
}
bool mie_parser_parse_float(
struct mie_parser *ctx, double *out, struct mie_file_span *loc)
{
if (!mie_parser_check_type(ctx, MIE_TOK_FLOAT)) {
return false;
}
struct mie_token *tok = mie_lex_peek(ctx->p_lex);
if (tok->tok_value_type != MIE_TOK_V_FLOAT) {
return false;
}
if (loc) {
mie_file_span_init(loc, tok);
}
*out = tok->tok_float;
mie_lex_advance(ctx->p_lex);
return true;
}
#define TOKEN_PARSER(name, id) \
bool mie_parser_parse_##name( \
struct mie_parser *ctx, fx_string *out, struct mie_file_span *loc) \
{ \
if (!mie_parser_check_type(ctx, id)) { \
return false; \
} \
struct mie_token *tok = mie_lex_peek(ctx->p_lex); \
switch (tok->tok_value_type) { \
case MIE_TOK_V_STRING: \
fx_string_append_cstr(out, tok->tok_str); \
break; \
case MIE_TOK_V_INT: \
fx_string_append_cstrf(out, "%lld", tok->tok_int); \
break; \
default: \
return false; \
} \
if (loc) { \
mie_file_span_init(loc, tok); \
} \
mie_lex_advance(ctx->p_lex); \
return true; \
}
TOKEN_PARSER(word, MIE_TOK_WORD);
TOKEN_PARSER(name, MIE_TOK_NAME);
TOKEN_PARSER(instname, MIE_TOK_INSTNAME);
TOKEN_PARSER(graphname, MIE_TOK_GRAPHNAME);
TOKEN_PARSER(opname, MIE_TOK_OPNAME);
TOKEN_PARSER(vregname, MIE_TOK_VREGNAME);
TOKEN_PARSER(mregname, MIE_TOK_MREGNAME);
TOKEN_PARSER(blockname, MIE_TOK_BLOCKNAME);
TOKEN_PARSER(attribname, MIE_TOK_ATTRIBNAME);
TOKEN_PARSER(typename, MIE_TOK_TYPENAME);
TOKEN_PARSER(symname, MIE_TOK_SYMNAME);
TOKEN_PARSER(string, MIE_TOK_STRING);
bool mie_parser_parse_keyword(
struct mie_parser *ctx, const char *kw, struct mie_file_span *loc)
{
fx_string *str = get_temp_string(ctx);
if (!mie_parser_parse_word(ctx, str, loc)) {
return false;
}
return strcmp(fx_string_ptr(str), kw) == 0;
}
bool mie_parser_parse_symbol(struct mie_parser *ctx, enum mie_token_symbol sym)
{
struct mie_token *tok = mie_lex_peek(ctx->p_lex);
if (!MIE_TOKEN_IS_SYMBOL(tok, sym)) {
return false;
}
mie_lex_advance(ctx->p_lex);
return true;
}
bool mie_parser_parse_linefeed(struct mie_parser *ctx)
{
struct mie_token *tok = mie_lex_peek(ctx->p_lex);
if (!MIE_TOKEN_IS(tok, MIE_TOK_LINEFEED)) {
return false;
}
while (MIE_TOKEN_IS(tok, MIE_TOK_LINEFEED)) {
mie_lex_advance(ctx->p_lex);
tok = mie_lex_peek(ctx->p_lex);
}
return true;
}
static bool parse_builtin_type_name(
struct mie_parser *ctx, const char *context,
const struct mie_type **out, struct mie_file_span *out_span)
{
fx_string *name = get_temp_string(ctx);
struct mie_file_span loc;
if (!mie_parser_parse_word(ctx, name, &loc)) {
return false;
}
if (out_span) {
*out_span = loc;
}
const struct mie_type_definition *type_info = NULL;
const struct mie_type *type = NULL;
size_t width = 0;
char tmp = 0;
enum {
NONE = 0,
INT,
FLOAT
} base_type = NONE;
const char *name_cstr = fx_string_ptr(name);
if (!strcmp(name_cstr, "memref")) {
type_info = mie_ctx_get_type_definition(
ctx->p_ctx, "builtin", "memref");
} else if (!strcmp(name_cstr, "index")) {
type_info = mie_ctx_get_type_definition(
ctx->p_ctx, "builtin", "index");
} else if (!strcmp(name_cstr, "str")) {
type_info = mie_ctx_get_type_definition(
ctx->p_ctx, "builtin", "string");
} else if (sscanf(name_cstr, "i%zu%c", &width, &tmp) == 1) {
type_info = mie_ctx_get_type_definition(
ctx->p_ctx, "builtin", "int");
base_type = INT;
} else if (sscanf(name_cstr, "f%zu%c", &width, &tmp) == 1) {
type_info = mie_ctx_get_type_definition(
ctx->p_ctx, "builtin", "float");
base_type = FLOAT;
}
if (!type_info) {
mie_parser_report_error_simple(
ctx, "builtin", MIE_BUILTIN_E_UNRESOLVED_TYPE,
MIE_BUILTIN_MSG_UNRESOLVED_BUILTIN_TYPE, &loc);
return false;
}
enum mie_status status = MIE_SUCCESS;
switch (base_type) {
case INT:
type = mie_ctx_get_int_type(ctx->p_ctx, width);
break;
case FLOAT:
type = mie_ctx_get_float_type(ctx->p_ctx, width);
break;
default:
if (type_info->ty_parse) {
status = type_info->ty_parse(ctx, &type);
} else {
type = mie_ctx_get_type(
ctx->p_ctx, type_info->ty_parent->d_name,
type_info->ty_name);
}
break;
}
if (!type || status != MIE_SUCCESS) {
type = NULL;
}
if (out_span) {
out_span->s_end = *mie_lex_get_cursor(ctx->p_lex);
out_span->s_end.c_col--;
}
*out = type;
return type != NULL;
}
static bool parse_type_name(
struct mie_parser *ctx, const char *context,
const struct mie_type **out, struct mie_file_span *out_span)
{
fx_string *name = get_temp_string(ctx);
struct mie_file_span loc;
if (!mie_parser_parse_typename(ctx, name, &loc)) {
return false;
}
if (out_span) {
out_span->s_start = loc.s_start;
}
const struct mie_type_definition *ty_def
= get_type_by_full_name(ctx, name);
if (!ty_def) {
mie_parser_report_error_simple(
ctx, "builtin", MIE_BUILTIN_E_UNRESOLVED_TYPE,
MIE_BUILTIN_MSG_UNRESOLVED_DIALECT_TYPE, &loc);
return false;
}
const struct mie_type *ty = NULL;
enum mie_status status = MIE_SUCCESS;
if (ty_def->ty_parse) {
status = ty_def->ty_parse(ctx, &ty);
} else {
ty = mie_ctx_get_type(
ctx->p_ctx, ty_def->ty_parent->d_name, ty_def->ty_name);
}
if (out_span) {
out_span->s_end = *mie_lex_get_cursor(ctx->p_lex);
out_span->s_end.c_col--;
}
*out = ty;
return ty != NULL;
}
static bool parse_composite_type(
struct mie_parser *ctx, const char *context,
const struct mie_type **out, struct mie_file_span *out_span)
{
const struct mie_type *temp = NULL;
struct mie_file_span span;
MIE_VECTOR_DEFINE(const struct mie_type *, type_list_1);
MIE_VECTOR_DEFINE(const struct mie_type *, type_list_2);
if (!mie_parser_parse_type_list(
ctx, context, MIE_VECTOR_REF(type_list_1), &span)) {
return false;
}
if (out_span) {
*out_span = span;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_HYPHEN_RIGHT_ANGLE)) {
*out = mie_ctx_get_storage_type(
ctx->p_ctx, type_list_1.items, type_list_1.count);
if (out_span) {
out_span->s_end = span.s_end;
}
return *out != NULL;
}
bool ok = false;
if (mie_parser_peek_symbol(ctx) == MIE_SYM_LEFT_PAREN) {
ok = mie_parser_parse_type_list(
ctx, context, MIE_VECTOR_REF(type_list_2), &span);
} else {
ok = mie_parser_parse_type(ctx, context, &temp, &span);
if (temp) {
mie_vector_push_back(type_list_2, &temp, NULL);
}
}
if (!ok) {
mie_vector_destroy(type_list_1, NULL);
mie_vector_destroy(type_list_2, NULL);
return false;
}
if (out_span) {
out_span->s_end = span.s_end;
}
temp = mie_ctx_get_function_type(
ctx->p_ctx, type_list_1.items, type_list_1.count,
type_list_2.items, type_list_2.count);
mie_vector_destroy(type_list_1, NULL);
mie_vector_destroy(type_list_2, NULL);
*out = temp;
return temp != NULL;
}
bool mie_parser_parse_type(
struct mie_parser *ctx, const char *context,
const struct mie_type **out, struct mie_file_span *out_span)
{
if (mie_parser_peek_symbol(ctx) == MIE_SYM_LEFT_PAREN) {
return parse_composite_type(ctx, context, out, out_span);
}
struct mie_parser_item expected[] = {
MIE_PARSE_ITEM_TOKEN(MIE_SYM_LEFT_PAREN),
MIE_PARSE_ITEM_TOKEN(MIE_TOK_TYPENAME),
MIE_PARSE_ITEM_NONE,
};
switch (mie_parser_peek_type(ctx)) {
case MIE_TOK_WORD:
return parse_builtin_type_name(ctx, context, out, out_span);
case MIE_TOK_TYPENAME:
return parse_type_name(ctx, context, out, out_span);
default:
mie_parser_report_unexpected_token_v(ctx, expected, context);
return false;
}
}
bool mie_parser_parse_type_list(
struct mie_parser *ctx, const char *context,
MIE_VECTOR_REF_PARAM(const struct mie_type *, out),
struct mie_file_span *out_span)
{
bool ok = false;
const struct mie_type **type_slot = NULL;
if (out_span) {
out_span->s_start = *mie_lex_get_cursor(ctx->p_lex);
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_PAREN)) {
mie_parser_report_unexpected_token(ctx, MIE_SYM_LEFT_PAREN, context);
return false;
}
if (mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_PAREN)) {
/* empty type list */
if (out_span) {
out_span->s_end = *mie_lex_get_cursor(ctx->p_lex);
out_span->s_end.c_col--;
}
return true;
}
type_slot = mie_vector_ref_emplace_back(out, NULL);
if (!type_slot) {
return false;
}
if (!mie_parser_parse_type(ctx, context, type_slot, NULL)) {
mie_vector_ref_pop_back(out, NULL);
return false;
}
while (1) {
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COMMA)) {
break;
}
type_slot = mie_vector_ref_emplace_back(out, NULL);
if (!type_slot) {
return false;
}
if (!mie_parser_parse_type(ctx, context, type_slot, NULL)) {
mie_vector_ref_pop_back(out, NULL);
return false;
}
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_PAREN)) {
mie_parser_report_unexpected_token(
ctx, MIE_SYM_RIGHT_PAREN, context);
return false;
}
return true;
}
MIE_API bool mie_parser_parse_function_type(
struct mie_parser *ctx, const char *context, struct mie_type **out,
struct mie_file_span *out_span)
{
const struct mie_type *type = NULL;
MIE_VECTOR_DEFINE(const struct mie_type *, in_parts);
MIE_VECTOR_DEFINE(const struct mie_type *, out_parts);
struct mie_file_span span;
if (!mie_parser_parse_type_list(
ctx, context, MIE_VECTOR_REF(in_parts), &span)) {
return false;
}
if (out_span) {
out_span->s_start = span.s_start;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_HYPHEN_RIGHT_ANGLE)) {
mie_vector_destroy(in_parts, NULL);
mie_vector_destroy(out_parts, NULL);
return false;
}
bool ok = false;
if (mie_parser_peek_symbol(ctx) == MIE_SYM_LEFT_PAREN) {
ok = mie_parser_parse_type_list(
ctx, context, MIE_VECTOR_REF(out_parts), &span);
} else {
ok = mie_parser_parse_type(ctx, context, &type, &span);
if (type) {
mie_vector_push_back(out_parts, &type, NULL);
}
}
if (!ok) {
mie_vector_destroy(in_parts, NULL);
mie_vector_destroy(out_parts, NULL);
return false;
}
if (out_span) {
out_span->s_end = span.s_end;
}
type = mie_ctx_get_function_type(
ctx->p_ctx, in_parts.items, in_parts.count, out_parts.items,
out_parts.count);
mie_vector_destroy(in_parts, NULL);
mie_vector_destroy(out_parts, NULL);
*out = (struct mie_type *)type;
return type != NULL;
}
bool mie_parser_parse_operand(struct mie_parser *ctx, struct mie_op_arg *out)
{
memset(out, 0x0, sizeof *out);
fx_string *str = get_temp_string(ctx);
bool result = false;
struct mie_file_span loc;
if (mie_parser_parse_vregname(ctx, str, &loc)) {
out->arg_unresolved.reg_name = fx_string_steal(str);
out->arg_unresolved.reg_flags = MIE_REGISTER_F_VIRTUAL;
result = true;
} else if (mie_parser_parse_mregname(ctx, str, &loc)) {
out->arg_unresolved.reg_name = fx_string_steal(str);
out->arg_unresolved.reg_flags = MIE_REGISTER_F_MACHINE;
result = true;
}
out->arg_span = loc;
return result;
}
bool mie_parser_parse_operand_list(
struct mie_parser *ctx, MIE_VECTOR_REF_PARAM(struct mie_op_arg, out))
{
bool ok = false;
struct mie_op_arg *operand = NULL;
struct mie_token *tok = mie_parser_peek(ctx);
enum mie_token_type type = MIE_TOKEN_TYPE(tok);
if (type != MIE_TOK_VREGNAME && type != MIE_TOK_MREGNAME) {
return false;
}
operand = mie_vector_ref_emplace_back(out, NULL);
if (!operand) {
return false;
}
if (!mie_parser_parse_operand(ctx, operand)) {
return false;
}
while (1) {
tok = mie_parser_peek(ctx);
if (!MIE_TOKEN_IS_SYMBOL(tok, MIE_SYM_COMMA)) {
break;
}
mie_parser_advance(ctx);
tok = mie_parser_peek(ctx);
type = MIE_TOKEN_TYPE(tok);
if (type != MIE_TOK_VREGNAME && type != MIE_TOK_MREGNAME) {
return false;
}
operand = mie_vector_ref_emplace_back(out, NULL);
if (!operand) {
return false;
}
if (!mie_parser_parse_operand(ctx, operand)) {
return false;
}
}
return true;
}
bool mie_parser_parse_parameter(
struct mie_parser *ctx, bool include_type, struct mie_op_arg *out,
const char *context)
{
memset(out, 0x0, sizeof *out);
fx_string *str = get_temp_string(ctx);
struct mie_file_span loc;
if (mie_parser_parse_vregname(ctx, str, &loc)) {
out->arg_unresolved.reg_name = fx_string_steal(str);
out->arg_unresolved.reg_flags = MIE_REGISTER_F_VIRTUAL;
} else if (mie_parser_parse_mregname(ctx, str, &loc)) {
out->arg_unresolved.reg_name = fx_string_steal(str);
out->arg_unresolved.reg_flags = MIE_REGISTER_F_MACHINE;
} else {
struct mie_parser_item required[] = {
MIE_PARSE_ITEM_TOKEN(MIE_TOK_VREGNAME),
MIE_PARSE_ITEM_TOKEN(MIE_TOK_MREGNAME),
MIE_PARSE_ITEM_NONE,
};
mie_parser_report_unexpected_token_v(ctx, required, context);
return false;
}
out->arg_span = loc;
if (!include_type) {
return true;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COLON)) {
mie_parser_report_unexpected_token(ctx, MIE_SYM_COLON, context);
return false;
}
if (!mie_parser_parse_type(
ctx, context, &out->arg_unresolved.reg_type, NULL)) {
return false;
}
return true;
}
bool mie_parser_parse_parameter_list(
struct mie_parser *ctx, bool include_type,
MIE_VECTOR_REF_PARAM(struct mie_op_arg, out), const char *context)
{
bool ok = false;
struct mie_op_arg *operand = NULL;
struct mie_token *tok = mie_parser_peek(ctx);
enum mie_token_type type = MIE_TOKEN_TYPE(tok);
if (type != MIE_TOK_VREGNAME && type != MIE_TOK_MREGNAME) {
return false;
}
operand = mie_vector_ref_emplace_back(out, NULL);
if (!operand) {
return false;
}
if (!mie_parser_parse_parameter(ctx, include_type, operand, context)) {
return false;
}
while (1) {
tok = mie_parser_peek(ctx);
if (!MIE_TOKEN_IS_SYMBOL(tok, MIE_SYM_COMMA)) {
break;
}
mie_parser_advance(ctx);
tok = mie_parser_peek(ctx);
type = MIE_TOKEN_TYPE(tok);
if (type != MIE_TOK_VREGNAME && type != MIE_TOK_MREGNAME) {
struct mie_parser_item required[] = {
MIE_PARSE_ITEM_TOKEN(MIE_TOK_VREGNAME),
MIE_PARSE_ITEM_TOKEN(MIE_TOK_MREGNAME),
MIE_PARSE_ITEM_NONE,
};
mie_parser_report_unexpected_token_v(ctx, required, context);
return false;
}
operand = mie_vector_ref_emplace_back(out, NULL);
if (!operand) {
return false;
}
if (!mie_parser_parse_parameter(
ctx, include_type, operand, context)) {
return false;
}
}
return true;
}
bool mie_parser_parse_register(
struct mie_parser *ctx, struct mie_parser_scope *scope,
const char *context, struct mie_register *out)
{
memset(out, 0x0, sizeof *out);
if (!scope) {
return false;
}
struct mie_parser_item expected[] = {
MIE_PARSE_ITEM_TOKEN(MIE_TOK_VREGNAME),
MIE_PARSE_ITEM_TOKEN(MIE_TOK_MREGNAME),
MIE_PARSE_ITEM_NONE,
};
struct mie_token *tok = mie_parser_peek(ctx);
enum mie_token_type type = MIE_TOKEN_TYPE(tok);
switch (type) {
case MIE_TOK_VREGNAME:
out->reg_flags |= MIE_REGISTER_F_VIRTUAL;
break;
case MIE_TOK_MREGNAME:
out->reg_flags |= MIE_REGISTER_F_MACHINE;
break;
default:
mie_parser_report_unexpected_token_v(ctx, expected, context);
return false;
}
struct mie_name *name = NULL;
fx_string *tmp = get_temp_string(ctx);
switch (tok->tok_value_type) {
case MIE_TOK_V_STRING:
name = mie_parser_scope_put_name(
scope, &out->reg_name, tok->tok_str, MIE_NAME_MAP_F_STRICT);
break;
case MIE_TOK_V_INT:
fx_string_append_cstrf(tmp, "%lld", tok->tok_int);
name = mie_parser_scope_put_name(
scope, &out->reg_name, fx_string_ptr(tmp),
MIE_NAME_MAP_F_STRICT);
break;
default:
break;
}
out->reg_span = tok->tok_location;
mie_parser_advance(ctx);
if (name) {
return true;
}
struct mie_diag *diag = mie_parser_report_error_simple(
ctx, "builtin", MIE_BUILTIN_E_NAME_ALREADY_IN_USE,
MIE_BUILTIN_MSG_NAME_ALREADY_IN_USE, &tok->tok_location);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_NAME_ALREADY_USED_HERE);
return false;
}
bool mie_parser_parse_register_list(
struct mie_parser *ctx, struct mie_parser_scope *scope,
const char *context, MIE_VECTOR_REF_PARAM(struct mie_register, out))
{
bool ok = false;
struct mie_register *reg = NULL;
struct mie_token *tok = mie_parser_peek(ctx);
enum mie_token_type type = MIE_TOKEN_TYPE(tok);
if (type != MIE_TOK_VREGNAME && type != MIE_TOK_MREGNAME) {
return false;
}
reg = mie_vector_ref_emplace_back(out, &mie_register_vector_ops);
if (!mie_parser_parse_register(ctx, scope, context, reg)) {
return false;
}
while (1) {
tok = mie_parser_peek(ctx);
if (!MIE_TOKEN_IS_SYMBOL(tok, MIE_SYM_COMMA)) {
break;
}
mie_parser_advance(ctx);
tok = mie_parser_peek(ctx);
type = MIE_TOKEN_TYPE(tok);
if (type != MIE_TOK_VREGNAME && type != MIE_TOK_MREGNAME) {
return false;
}
reg = mie_vector_ref_emplace_back(out, &mie_register_vector_ops);
if (!mie_parser_parse_register(ctx, scope, context, reg)) {
return false;
}
}
return true;
}
bool mie_parser_parse_region(
struct mie_parser *ctx, struct mie_op *parent,
struct mie_region *region, struct mie_block *first_block)
{
if (mie_op_has_trait(parent, "builtin", "isolated-from-above")) {
region->r_names = mie_name_map_create(NULL);
}
region->r_parent = parent;
struct mie_parser_scope scope = {
.s_region = region,
.s_names = region->r_names,
};
if (!mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_BRACE)) {
return false;
}
if (!mie_parser_parse_linefeed(ctx)) {
return false;
}
struct mie_block *block = first_block;
if (mie_parser_peek_type(ctx) != MIE_TOK_BLOCKNAME) {
if (!block) {
block = mie_region_add_block(region);
}
if (!mie_parser_parse_anonymous_block(ctx, &scope, block)) {
return false;
}
}
while (1) {
if (mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_BRACE)) {
break;
}
block = mie_region_add_block(region);
if (!mie_parser_parse_block(ctx, &scope, block)) {
return false;
}
}
return true;
}
bool mie_parser_parse_region_list(struct mie_parser *ctx, struct mie_op *parent)
{
if (!mie_parser_check_symbol(ctx, MIE_SYM_LEFT_BRACE)) {
return false;
}
struct mie_region *region = mie_op_add_region(parent);
if (!mie_parser_parse_region(ctx, parent, region, NULL)) {
return false;
}
while (1) {
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COMMA)) {
break;
}
if (!mie_parser_check_symbol(ctx, MIE_SYM_LEFT_BRACE)) {
break;
}
struct mie_region *region = mie_op_add_region(parent);
if (!mie_parser_parse_region(ctx, parent, region, NULL)) {
return false;
}
}
return true;
}
bool mie_parser_parse_anonymous_block(
struct mie_parser *ctx, struct mie_parser_scope *scope,
struct mie_block *block)
{
mie_parser_parse_linefeed(ctx);
struct mie_op *op = mie_block_add_op(block);
if (!mie_parser_parse_op(ctx, scope, op)) {
return false;
}
mie_parser_parse_linefeed(ctx);
while (1) {
if (mie_parser_peek_type(ctx) == MIE_TOK_BLOCKNAME) {
break;
}
if (mie_parser_peek_symbol(ctx) == MIE_SYM_RIGHT_BRACE) {
break;
}
struct mie_op *op = mie_block_add_op(block);
if (!mie_parser_parse_op(ctx, scope, op)) {
return false;
}
if (!mie_parser_parse_linefeed(ctx)) {
return false;
}
}
return true;
}
static bool parse_block_parameters(
struct mie_parser *ctx, struct mie_parser_scope *scope,
struct mie_block *block)
{
if (!scope) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_PAREN)) {
return false;
}
MIE_VECTOR_DEFINE(struct mie_op_arg, block_params);
if (!mie_parser_parse_parameter_list(
ctx, true, MIE_VECTOR_REF(block_params),
"block parameters")) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_PAREN)) {
mie_vector_destroy(block_params, NULL);
return false;
}
for (size_t i = 0; i < MIE_VECTOR_COUNT(block_params); i++) {
struct mie_register *param_reg = mie_vector_emplace_back(
block->b_params, &mie_register_vector_ops);
param_reg->reg_flags = block_params.items[i].arg_unresolved.reg_flags
| MIE_REGISTER_F_BLOCK_PARAM;
param_reg->reg_type = block_params.items[i].arg_unresolved.reg_type;
param_reg->reg_block = block;
if (!mie_parser_scope_put_name(
scope, &param_reg->reg_name,
block_params.items[i].arg_unresolved.reg_name,
MIE_NAME_MAP_F_STRICT)) {
return false;
}
}
return true;
}
bool mie_parser_parse_block(
struct mie_parser *ctx, struct mie_parser_scope *scope,
struct mie_block *block)
{
if (!scope) {
return NULL;
}
fx_string *str = get_temp_string(ctx);
struct mie_file_span span;
if (!mie_parser_parse_blockname(ctx, str, &span)) {
return false;
}
if (!mie_parser_scope_put_name(
scope, &block->b_name, fx_string_ptr(str),
MIE_NAME_MAP_F_STRICT)) {
return false;
}
memcpy(&block->b_name.n_span, &span, sizeof span);
if (mie_parser_peek_symbol(ctx) == MIE_SYM_LEFT_PAREN
&& !parse_block_parameters(ctx, scope, block)) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COLON)
|| !mie_parser_parse_linefeed(ctx)) {
return false;
}
while (1) {
if (mie_parser_peek_type(ctx) == MIE_TOK_BLOCKNAME) {
break;
}
if (mie_parser_peek_symbol(ctx) == MIE_SYM_RIGHT_BRACE) {
break;
}
struct mie_op *op = mie_block_add_op(block);
if (!mie_parser_parse_op(ctx, scope, op)) {
return false;
}
if (!mie_parser_parse_linefeed(ctx)) {
return false;
}
}
return true;
}
bool mie_parser_parse_successor(struct mie_parser *ctx, struct mie_op_successor *out)
{
memset(out, 0x0, sizeof *out);
fx_string *str = get_temp_string(ctx);
bool result = false;
if (!mie_parser_parse_blockname(ctx, str, &out->s_name_span)) {
return false;
}
out->s_block_name = fx_string_steal(str);
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COLON)) {
return true;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_PAREN)) {
goto fail;
}
if (!mie_parser_parse_parameter_list(
ctx, true, MIE_VECTOR_REF(out->s_args),
"successor arguments")) {
goto fail;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_PAREN)) {
goto fail;
}
return true;
fail:
if (out->s_block_name) {
free(out->s_block_name);
out->s_block_name = NULL;
}
if (MIE_VECTOR_MAX(out->s_args) > 0) {
mie_vector_destroy(out->s_args, NULL);
}
return false;
}
bool mie_parser_parse_successor_list(
struct mie_parser *ctx, MIE_VECTOR_REF_PARAM(struct mie_op_successor, out))
{
bool ok = false;
struct mie_op_successor *successor = NULL;
successor = mie_vector_ref_emplace_back(out, NULL);
if (!successor) {
return false;
}
if (!mie_parser_parse_successor(ctx, successor)) {
return false;
}
while (1) {
const struct mie_token *tok = mie_parser_peek(ctx);
if (!MIE_TOKEN_IS_SYMBOL(tok, MIE_SYM_COMMA)) {
break;
}
mie_parser_advance(ctx);
mie_parser_parse_linefeed(ctx);
successor = mie_vector_ref_emplace_back(out, NULL);
if (!successor) {
return false;
}
if (!mie_parser_parse_successor(ctx, successor)) {
return false;
}
}
return true;
}
static bool parse_custom_op(
struct mie_parser *ctx, struct mie_parser_scope *scope, struct mie_op *dest)
{
fx_string *str = get_temp_string(ctx);
struct mie_file_span loc;
if (!mie_parser_parse_name(ctx, str, &dest->op_name_span)) {
return false;
}
dest->op_name = fx_string_steal(str);
if (!mie_resolve_op_self(dest, ctx->p_ctx)) {
struct mie_diag *diag = mie_ctx_push_diag(
ctx->p_ctx, dest->op_src, &dest->op_name_span.s_start,
"builtin", MIE_BUILTIN_E_UNKNOWN_OP);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin", MIE_BUILTIN_MSG_UNKNOWN_OP);
struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, loc),
};
struct mie_diag_amendment am[] = {
MIE_DIAG_ADD("~", loc.s_start),
};
mie_diag_push_snippet(
diag, loc.s_start.c_row, loc.s_end.c_row, NULL, 0, hl, 1);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_USE_GENERIC_OP_SYNTAX);
hl[0].hl_type = MIE_DIAG_HIGHLIGHT_HINT;
hl[0].hl_span.s_end = hl[0].hl_span.s_start;
mie_diag_push_snippet(
diag, loc.s_start.c_row, loc.s_end.c_row, am, 1, hl, 1);
return false;
}
if (!dest->op_info->op_parse) {
struct mie_diag *diag = mie_ctx_push_diag(
ctx->p_ctx, dest->op_src, &loc.s_start, "builtin",
MIE_BUILTIN_E_INTERNAL_ERROR);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_OP_HAS_NO_PARSER);
struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, loc),
};
mie_diag_push_snippet(
diag, loc.s_start.c_row, loc.s_end.c_row, NULL, 0, hl, 1);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_DIALECT_INTERNAL_ERROR);
return false;
}
enum mie_status status = dest->op_info->op_parse(ctx, scope, dest);
return status == MIE_SUCCESS;
}
static bool parse_builtin_op(
struct mie_parser *ctx, struct mie_parser_scope *scope, struct mie_op *dest)
{
fx_string *str = get_temp_string(ctx);
struct mie_file_span loc;
if (!mie_parser_parse_word(ctx, str, &loc)) {
return false;
}
dest->op_name = fx_bstr_fmt(NULL, "builtin.%s", fx_string_ptr(str));
if (!mie_resolve_op_self(dest, ctx->p_ctx)) {
struct mie_diag *diag = mie_ctx_push_diag(
ctx->p_ctx, dest->op_src, &loc.s_start, "builtin",
MIE_BUILTIN_E_UNKNOWN_OP);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin", MIE_BUILTIN_MSG_UNKNOWN_OP);
struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, loc),
};
struct mie_diag_amendment am[] = {
MIE_DIAG_ADD("~", loc.s_start),
};
mie_diag_push_snippet(
diag, loc.s_start.c_row, loc.s_end.c_row, NULL, 0, hl, 1);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_USE_GENERIC_OP_SYNTAX);
hl[0].hl_type = MIE_DIAG_HIGHLIGHT_HINT;
hl[0].hl_span.s_end = hl[0].hl_span.s_start;
mie_diag_push_snippet(
diag, loc.s_start.c_row, loc.s_end.c_row, am, 1, hl, 1);
return false;
}
if (!dest->op_info->op_parse) {
struct mie_diag *diag = mie_ctx_push_diag(
ctx->p_ctx, dest->op_src, &loc.s_start, "builtin",
MIE_BUILTIN_E_INTERNAL_ERROR);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_OP_HAS_NO_PARSER);
struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, loc),
};
mie_diag_push_snippet(
diag, loc.s_start.c_row, loc.s_end.c_row, NULL, 0, hl, 1);
mie_diag_push_msg(
diag, ctx->p_ctx, "builtin",
MIE_BUILTIN_MSG_DIALECT_INTERNAL_ERROR);
return false;
}
enum mie_status status = dest->op_info->op_parse(ctx, scope, dest);
return status == MIE_SUCCESS;
}
static bool parse_generic_op(
struct mie_parser *ctx, struct mie_parser_scope *scope, struct mie_op *dest)
{
fx_string *str = get_temp_string(ctx);
struct mie_file_span loc;
if (!mie_parser_parse_opname(ctx, str, &loc)) {
return false;
}
dest->op_name = fx_string_steal(str);
/* resolve the op now. we need to know if the op is isolated-from-above
* in order to add register/block names to the correct region name maps. */
mie_resolve_op_self(dest, ctx->p_ctx);
if (!mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_PAREN)) {
return false;
}
if (mie_parser_peek_symbol(ctx) != MIE_SYM_RIGHT_PAREN
&& !mie_parser_parse_operand_list(ctx, MIE_VECTOR_REF(dest->op_args))) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_PAREN)) {
return false;
}
if (mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_BRACKET)) {
mie_parser_parse_linefeed(ctx);
if (!mie_parser_parse_successor_list(
ctx, MIE_VECTOR_REF(dest->op_successors))) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_BRACKET)) {
return false;
}
}
if (mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_PAREN)) {
mie_parser_parse_linefeed(ctx);
if (!mie_parser_parse_region_list(ctx, dest)) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_PAREN)) {
return false;
}
}
if (mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_BRACE)) {
if (!mie_parser_parse_attribute_map(ctx, &dest->op_attrib)) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_BRACE)) {
return false;
}
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COLON)) {
return false;
}
struct mie_function_type *func_type = NULL;
if (!mie_parser_parse_function_type(
ctx, "operation type signature",
(struct mie_type **)&func_type, NULL)) {
return false;
}
if (MIE_VECTOR_COUNT(func_type->func_in)
!= MIE_VECTOR_COUNT(dest->op_args)) {
return false;
}
if (MIE_VECTOR_COUNT(func_type->func_out)
!= MIE_VECTOR_COUNT(dest->op_result)) {
return false;
}
for (size_t i = 0; i < MIE_VECTOR_COUNT(func_type->func_in); i++) {
dest->op_args.items[i].arg_unresolved.reg_type
= func_type->func_in.items[i];
}
for (size_t i = 0; i < MIE_VECTOR_COUNT(func_type->func_out); i++) {
dest->op_result.items[i].reg_type = func_type->func_out.items[i];
}
return true;
}
static bool parse_graph_op(
struct mie_parser *ctx, struct mie_parser_scope *scope, struct mie_op *dest)
{
return false;
}
bool mie_parser_parse_op(
struct mie_parser *ctx, struct mie_parser_scope *scope, struct mie_op *dest)
{
if (mie_parser_check_eof(ctx)) {
return false;
}
if (mie_parser_check_type(ctx, MIE_TOK_MREGNAME | MIE_TOK_VREGNAME)) {
if (!mie_parser_parse_register_list(
ctx, scope, "operation results",
MIE_VECTOR_REF(dest->op_result))) {
return false;
}
if (!mie_parser_parse_symbol(ctx, MIE_SYM_EQUAL)) {
return false;
}
}
for (size_t i = 0; i < MIE_VECTOR_COUNT(dest->op_result); i++) {
struct mie_register *reg = &dest->op_result.items[i];
reg->reg_flags |= MIE_REGISTER_F_OP_RESULT;
reg->reg_op = dest;
reg->reg_block = dest->op_container;
}
dest->op_src = mie_lex_get_line_source(ctx->p_lex);
if (mie_parser_check_type(ctx, MIE_TOK_NAME)) {
/* custom-format operation */
return parse_custom_op(ctx, scope, dest);
} else if (mie_parser_check_type(ctx, MIE_TOK_OPNAME)) {
/* generic-format operation */
return parse_generic_op(ctx, scope, dest);
} else if (mie_parser_check_type(ctx, MIE_TOK_GRAPHNAME)) {
/* graph-node operation */
return parse_graph_op(ctx, scope, dest);
} else if (mie_parser_check_type(ctx, MIE_TOK_WORD)) {
/* custom-format builtin operation */
return parse_builtin_op(ctx, scope, dest);
} else {
/* not sure what this is */
return false;
}
}
bool mie_parser_parse_attribute(
struct mie_parser *ctx, const struct mie_attribute **dest)
{
enum mie_token_type type = mie_parser_peek_type(ctx);
const struct mie_attribute_definition *attribute = NULL;
fx_string *str = get_temp_string(ctx);
struct mie_file_span span;
bool need_angle_delim = false;
switch (type) {
case MIE_TOK_STRING:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "string");
break;
case MIE_TOK_INT:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "int");
break;
case MIE_TOK_FLOAT:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "float");
break;
case MIE_TOK_SYMBOL:
switch (mie_parser_peek_symbol(ctx)) {
case MIE_SYM_LEFT_BRACKET:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "array");
break;
case MIE_SYM_LEFT_BRACE:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "dict");
break;
case MIE_SYM_LEFT_PAREN:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "type");
break;
default:
break;
}
break;
case MIE_TOK_ATTRIBNAME:
if (!mie_parser_parse_attribname(ctx, str, &span)) {
return false;
}
attribute = get_attribute_by_full_name(ctx, str);
need_angle_delim = true;
break;
case MIE_TOK_TYPENAME:
case MIE_TOK_WORD:
attribute = mie_ctx_get_attribute_definition(
ctx->p_ctx, "builtin", "type");
break;
default:
break;
}
if (!attribute || !attribute->a_parse) {
return false;
}
if (need_angle_delim && !mie_parser_parse_symbol(ctx, MIE_SYM_LEFT_ANGLE)) {
return false;
}
if (attribute->a_parse(ctx, dest) != MIE_SUCCESS) {
return false;
}
if (need_angle_delim && !mie_parser_parse_symbol(ctx, MIE_SYM_RIGHT_ANGLE)) {
return false;
}
return true;
}
static bool parse_attribute_map_entry(
struct mie_parser *ctx, char **out_name,
const struct mie_attribute **out_value)
{
fx_string *str = get_temp_string(ctx);
struct mie_file_span span;
if (!mie_parser_parse_word(ctx, str, &span)) {
return false;
}
char *name = fx_string_steal(str);
if (!mie_parser_parse_symbol(ctx, MIE_SYM_EQUAL)) {
free(name);
return false;
}
const struct mie_attribute *value = NULL;
if (!mie_parser_parse_attribute(ctx, &value)) {
free(name);
return false;
}
*out_name = name;
*out_value = value;
return true;
}
bool mie_parser_parse_attribute_map(
struct mie_parser *ctx, struct mie_attribute_map *out)
{
char *name = NULL;
const struct mie_attribute *value = NULL;
bool ok = false;
if (mie_parser_peek_type(ctx) != MIE_TOK_WORD) {
return false;
}
if (!parse_attribute_map_entry(ctx, &name, &value)) {
return false;
}
mie_attribute_map_put(out, name, value, 0);
free(name);
while (1) {
if (!mie_parser_parse_symbol(ctx, MIE_SYM_COMMA)) {
break;
}
if (!parse_attribute_map_entry(ctx, &name, &value)) {
return false;
}
mie_attribute_map_put(out, name, value, 0);
free(name);
}
return true;
}
static const char *token_diag_string(unsigned int token)
{
#define TOK_STR(tok, str) \
case MIE_TOK_##tok: \
return str
#define SYM_STR(sym, str) \
case MIE_SYM_##sym: \
return str
switch (token) {
TOK_STR(LINEFEED, "end of line");
TOK_STR(INT, "integer constant");
TOK_STR(FLOAT, "floating-point constant");
TOK_STR(SYMBOL, "symbol");
TOK_STR(STRING, "string");
TOK_STR(WORD, "word");
TOK_STR(NAME, "name");
TOK_STR(INSTNAME, "instruction name");
TOK_STR(SYMNAME, "symbol name");
TOK_STR(OPNAME, "operation name");
TOK_STR(GRAPHNAME, "graph operation name");
TOK_STR(VREGNAME, "virtual register name");
TOK_STR(MREGNAME, "machine register name");
TOK_STR(BLOCKNAME, "block name");
TOK_STR(TYPENAME, "type name");
TOK_STR(ATTRIBNAME, "attribute name");
SYM_STR(COLON, "`:`");
SYM_STR(EQUAL, "`=`");
SYM_STR(COMMA, "`,`");
SYM_STR(HYPHEN, "`-`");
SYM_STR(ASTERISK, "`*`");
SYM_STR(PLUS, "`+`");
SYM_STR(PERCENT, "`%`");
SYM_STR(DOLLAR, "`$`");
SYM_STR(CARET, "`^`");
SYM_STR(HASH, "`#`");
SYM_STR(TILDE, "`~`");
SYM_STR(BANG, "`!`");
SYM_STR(QUESTION, "`?`");
SYM_STR(ATSIGN, "`@`");
SYM_STR(LEFT_BRACE, "`{`");
SYM_STR(RIGHT_BRACE, "`}`");
SYM_STR(LEFT_BRACKET, "`[[`");
SYM_STR(RIGHT_BRACKET, "`]`");
SYM_STR(LEFT_PAREN, "`(`");
SYM_STR(RIGHT_PAREN, "`)`");
SYM_STR(LEFT_ANGLE, "`<`");
SYM_STR(RIGHT_ANGLE, "`>`");
SYM_STR(HYPHEN_RIGHT_ANGLE, "`->`");
default:
return "<unknown>";
}
}
struct mie_diag *mie_parser_report_error_simple(
struct mie_parser *parser, const char *dialect, unsigned int diag_class,
unsigned int msg, const struct mie_file_span *loc)
{
struct mie_diag *diag = mie_ctx_push_diag(
parser->p_ctx, mie_lex_get_line_source(parser->p_lex),
&loc->s_start, dialect, diag_class);
mie_diag_push_msg(diag, parser->p_ctx, dialect, msg);
const struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, *loc),
};
mie_diag_push_snippet(
diag, loc->s_start.c_row, loc->s_end.c_row, NULL, 0, hl, 1);
return diag;
}
void mie_parser_report_unexpected_token_v(
struct mie_parser *parser,
const struct mie_parser_item expected_tokens[], const char *context)
{
fx_bstr str;
fx_bstr_begin_dynamic(&str);
struct mie_token *tok = mie_lex_peek(parser->p_lex);
fx_bstr_write_cstr(&str, "expected ", NULL);
for (size_t i = 0; expected_tokens[i].i_type != MIE_PARSER_ITEM_NONE; i++) {
bool end = expected_tokens[i + 1].i_type == MIE_PARSER_ITEM_NONE;
if (end && i > 0) {
fx_bstr_write_cstr(&str, " or ", NULL);
} else if (i > 0) {
fx_bstr_write_cstr(&str, ", ", NULL);
}
switch (expected_tokens[i].i_type) {
case MIE_PARSER_ITEM_TOK:
fx_bstr_write_fmt(
&str, NULL, "[blue]%s[reset]",
token_diag_string(expected_tokens[i].i_tok));
break;
case MIE_PARSER_ITEM_CSTR:
fx_bstr_write_fmt(
&str, NULL, "[blue]%s[reset]",
expected_tokens[i].i_cstr);
break;
default:
break;
}
}
if (context) {
fx_bstr_write_fmt(
&str, NULL, " while parsing [cyan]%s[reset]", context);
}
fx_bstr_write_cstr(&str, "; found [red]", NULL);
if (MIE_TOKEN_TYPE(tok) == MIE_TOK_SYMBOL) {
fx_bstr_write_cstr(&str, token_diag_string(tok->tok_sym), NULL);
} else if (tok != NULL) {
fx_bstr_write_cstr(&str, token_diag_string(tok->tok_type), NULL);
} else {
fx_bstr_write_cstr(&str, "end of file", NULL);
}
fx_bstr_write_cstr(&str, "[reset]", NULL);
fx_bstr_write_cstr(&str, ".", NULL);
char *s = fx_bstr_end(&str);
const struct mie_file_cell *loc = tok ? &tok->tok_location.s_start
: mie_lex_get_cursor(parser->p_lex);
struct mie_file_span span
= tok ? tok->tok_location
: (struct mie_file_span) {
.s_start = *mie_lex_get_cursor(parser->p_lex),
.s_end = *mie_lex_get_cursor(parser->p_lex),
};
struct mie_diag *diag = mie_ctx_push_diag(
parser->p_ctx, mie_lex_get_line_source(parser->p_lex), loc,
"builtin", MIE_BUILTIN_E_UNEXPECTED_TOKEN);
mie_diag_push_string(diag, s);
free(s);
const struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, span),
};
mie_diag_push_snippet(
diag, span.s_start.c_row, span.s_end.c_row, NULL, 0, hl, 1);
}
void mie_parser_report_unexpected_token_s(
struct mie_parser *parser, const char *expected_token, const char *context)
{
fx_bstr str;
fx_bstr_begin_dynamic(&str);
struct mie_token *tok = mie_lex_peek(parser->p_lex);
fx_bstr_write_fmt(&str, NULL, "expected [blue]%s[reset]", expected_token);
if (context) {
fx_bstr_write_fmt(
&str, NULL, " while parsing [cyan]%s[reset]", context);
}
fx_bstr_write_cstr(&str, "; found [red]", NULL);
if (MIE_TOKEN_TYPE(tok) == MIE_TOK_SYMBOL) {
fx_bstr_write_cstr(&str, token_diag_string(tok->tok_sym), NULL);
} else if (tok != NULL) {
fx_bstr_write_cstr(&str, token_diag_string(tok->tok_type), NULL);
} else {
fx_bstr_write_cstr(&str, "end of file", NULL);
}
fx_bstr_write_cstr(&str, "[reset].", NULL);
char *s = fx_bstr_end(&str);
const struct mie_file_cell *loc = tok ? &tok->tok_location.s_start
: mie_lex_get_cursor(parser->p_lex);
struct mie_file_span span
= tok ? tok->tok_location
: (struct mie_file_span) {
.s_start = *mie_lex_get_cursor(parser->p_lex),
.s_end = *mie_lex_get_cursor(parser->p_lex),
};
struct mie_diag *diag = mie_ctx_push_diag(
parser->p_ctx, mie_lex_get_line_source(parser->p_lex), loc,
"builtin", MIE_BUILTIN_E_UNEXPECTED_TOKEN);
mie_diag_push_string(diag, s);
free(s);
const struct mie_diag_highlight hl[] = {
MIE_DIAG_HL(ERROR, span),
};
mie_diag_push_snippet(
diag, span.s_start.c_row, span.s_end.c_row, NULL, 0, hl, 1);
}
static struct mie_name_map *find_name_map(struct mie_region *region)
{
while (region) {
if (region->r_names) {
return region->r_names;
}
struct mie_op *op = region->r_parent;
struct mie_block *block = op ? op->op_container : NULL;
region = block ? block->b_parent : NULL;
}
return NULL;
}
struct mie_name *mie_parser_scope_put_name(
struct mie_parser_scope *scope, struct mie_name *entry,
const char *hint, enum mie_name_map_flags flags)
{
struct mie_name_map *names = scope ? find_name_map(scope->s_region) : NULL;
if (!names) {
return NULL;
}
return mie_name_map_put(names, entry, hint, flags);
}
struct mie_register *mie_parser_scope_find_value(
struct mie_parser_scope *scope, const char *name)
{
struct mie_region *region = scope ? scope->s_region : NULL;
bool end = false;
while (region) {
if (region->r_names) {
end = true;
}
struct mie_register *reg = mie_region_find_register(region, name);
if (reg) {
return reg;
}
struct mie_op *op = region->r_parent;
struct mie_block *block = op ? op->op_container : NULL;
region = block ? block->b_parent : NULL;
}
return NULL;
}