1865 lines
46 KiB
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, ¶m_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;
|
|
}
|