Files
mie/mie/dialect/func/op/func.c

258 lines
7.7 KiB
C

#include <mie/attribute/attribute-map.h>
#include <mie/ctx.h>
#include <mie/diag/diag.h>
#include <mie/dialect/builtin.h>
#include <mie/dialect/dialect.h>
#include <mie/dialect/func.h>
#include <mie/interface/interface-definition.h>
#include <mie/interface/interface.h>
#include <mie/ir/block.h>
#include <mie/ir/emit.h>
#include <mie/ir/op-definition.h>
#include <mie/ir/op.h>
#include <mie/ir/region.h>
#include <mie/macros.h>
#include <mie/parse/parser.h>
#include <mie/print/printer.h>
#include <mie/type/function.h>
static enum mie_status print(struct mie_printer *printer, const struct mie_op *op)
{
const struct mie_attribute *sym_name
= mie_attribute_map_get(&op->op_attrib, "sym_name");
const struct mie_attribute *function_type_attr
= mie_attribute_map_get(&op->op_attrib, "function_type");
const char *sym_name_cstr = mie_string_get_cstr(sym_name);
const struct mie_type *function_type_g
= mie_type_attr_get_type(function_type_attr);
const struct mie_function_type *function_ty
= (const struct mie_function_type *)function_type_g;
b_stream_write_fmt(printer->p_stream, NULL, " @%s(", sym_name_cstr);
const struct mie_region *code = mie_op_get_first_region(op);
const struct mie_block *entry = mie_region_get_first_block(code);
for (size_t i = 0; i < MIE_VECTOR_COUNT(entry->b_params); i++) {
if (i > 0) {
b_stream_write_string(printer->p_stream, ", ", NULL);
}
const struct mie_register *param = &entry->b_params.items[i];
mie_printer_print_register(printer, param, MIE_PRINT_F_INCLUDE_TYPE);
}
b_stream_write_string(printer->p_stream, ") -> ", NULL);
if (MIE_VECTOR_COUNT(function_ty->func_out) != 1) {
b_stream_write_char(printer->p_stream, '(');
}
for (size_t i = 0; i < MIE_VECTOR_COUNT(function_ty->func_out); i++) {
if (i > 0) {
b_stream_write_string(printer->p_stream, ", ", NULL);
}
const struct mie_type *ty = function_ty->func_out.items[i];
mie_printer_print_type(printer, ty);
}
if (MIE_VECTOR_COUNT(function_ty->func_out) != 1) {
b_stream_write_char(printer->p_stream, ')');
}
b_stream_write_char(printer->p_stream, ' ');
mie_printer_print_region(
printer, code, MIE_PRINT_F_EXCLUDE_FIRST_BLOCK_HEADER);
return MIE_SUCCESS;
}
static enum mie_status parse_return_type(
struct mie_parser *parser,
MIE_VECTOR_REF_PARAM(const struct mie_type *, out))
{
bool ok = true;
if (mie_parser_peek_symbol(parser) == MIE_SYM_LEFT_PAREN) {
ok = mie_parser_parse_type_list(
parser, "function return type", MIE_VECTOR_REF2(out), NULL);
} else {
const struct mie_type *tmp;
ok = mie_parser_parse_type(
parser, "function return type", &tmp, NULL);
if (ok) {
mie_vector_ref_push_back(out, &tmp, NULL);
}
}
return ok ? MIE_SUCCESS : MIE_ERR_BAD_SYNTAX;
}
static enum mie_status parse(
struct mie_parser *parser, struct mie_parser_scope *scope,
struct mie_op *out)
{
if (!scope) {
struct mie_diag *diag = mie_parser_report_error_simple(
parser, "builtin", MIE_BUILTIN_E_OP_REQUIRES_PARENT_SCOPE,
MIE_BUILTIN_MSG_OP_REQUIRES_PARENT_SCOPE,
&out->op_name_span);
mie_diag_push_msg(
diag, mie_parser_get_mie_ctx(parser), "builtin",
MIE_BUILTIN_MSG_OP_PARENT_SCOPE_EXAMPLE);
return MIE_ERR_BAD_SYNTAX;
}
b_string *temp = mie_parser_get_tempstr(parser);
if (!mie_parser_parse_symname(parser, temp, NULL)) {
mie_parser_report_unexpected_token(
parser, MIE_TOK_SYMNAME, "function signature");
return MIE_ERR_BAD_SYNTAX;
}
struct mie_attribute *sym_name = mie_ctx_get_string(
mie_parser_get_mie_ctx(parser), b_string_ptr(temp));
if (!mie_parser_parse_symbol(parser, MIE_SYM_LEFT_PAREN)) {
mie_parser_report_unexpected_token(
parser, MIE_SYM_LEFT_PAREN, "function parameter list");
return MIE_ERR_BAD_SYNTAX;
}
MIE_VECTOR_DEFINE(struct mie_op_arg, block_params);
MIE_VECTOR_DEFINE(const struct mie_type *, in_types);
MIE_VECTOR_DEFINE(const struct mie_type *, out_types);
if (!mie_parser_parse_parameter_list(
parser, true, MIE_VECTOR_REF(block_params),
"function parameter list")) {
return MIE_ERR_BAD_SYNTAX;
}
if (!mie_parser_parse_symbol(parser, MIE_SYM_RIGHT_PAREN)) {
mie_parser_report_unexpected_token(
parser, MIE_SYM_LEFT_PAREN, "function parameter list");
return MIE_ERR_BAD_SYNTAX;
}
struct mie_region *body = mie_op_add_region(out);
struct mie_block *entry = mie_region_add_block(body);
for (size_t i = 0; i < MIE_VECTOR_COUNT(block_params); i++) {
struct mie_register *param_reg = mie_vector_emplace_back(
entry->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 = entry;
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;
}
mie_vector_push_back(in_types, &param_reg->reg_type, NULL);
}
if (!mie_parser_parse_symbol(parser, MIE_SYM_HYPHEN_RIGHT_ANGLE)) {
mie_parser_report_unexpected_token(
parser, MIE_SYM_HYPHEN_RIGHT_ANGLE,
"function signature");
return MIE_ERR_BAD_SYNTAX;
}
if (parse_return_type(parser, MIE_VECTOR_REF(out_types)) != MIE_SUCCESS) {
return MIE_ERR_BAD_SYNTAX;
}
const struct mie_type *func_type = mie_ctx_get_function_type(
mie_parser_get_mie_ctx(parser), in_types.items, in_types.count,
out_types.items, out_types.count);
mie_vector_destroy(in_types, NULL);
mie_vector_destroy(out_types, NULL);
struct mie_attribute *function_type
= mie_type_attr_create(mie_parser_get_mie_ctx(parser), func_type);
mie_attribute_map_put(
&out->op_attrib, "sym_name", sym_name, MIE_ATTRMAP_F_REPLACE);
mie_attribute_map_put(
&out->op_attrib, "function_type", function_type,
MIE_ATTRMAP_F_REPLACE);
if (!mie_parser_parse_region(parser, out, body, entry)) {
return MIE_ERR_BAD_SYNTAX;
}
return MIE_SUCCESS;
}
struct mie_op *mie_func_func_put(
struct mie_emitter *e, const char *name, struct mie_func_parameter *params,
size_t nr_params, const struct mie_type **ret_types, size_t nr_ret_types)
{
const struct mie_type **param_types
= calloc(nr_params, sizeof *param_types);
if (!param_types) {
return NULL;
}
for (size_t i = 0; i < nr_params; i++) {
param_types[i] = params[i].param_type;
}
const struct mie_type *func_type = mie_ctx_get_function_type(
mie_emitter_get_ctx(e), param_types, nr_params, ret_types,
nr_ret_types);
free(param_types);
if (!func_type) {
return NULL;
}
struct mie_op *op = mie_emitter_put_op(e, "func", "func", NULL, 0);
struct mie_region *region = mie_op_add_region(op);
struct mie_block *entry = mie_region_add_block(region);
mie_name_map_put(region->r_names, &entry->b_name, "entry", 0);
for (size_t i = 0; i < nr_params; i++) {
struct mie_register *param_reg = mie_block_add_param(entry);
mie_name_map_put(
region->r_names, &param_reg->reg_name,
params[i].param_name, 0);
param_reg->reg_type = params[i].param_type;
params[i].param_reg = param_reg;
}
struct mie_attribute *sym_name
= mie_ctx_get_string(mie_emitter_get_ctx(e), name);
struct mie_attribute *function_type
= mie_type_attr_create(mie_emitter_get_ctx(e), func_type);
mie_attribute_map_put(
&op->op_attrib, "sym_name", sym_name, MIE_ATTRMAP_F_REPLACE);
mie_attribute_map_put(
&op->op_attrib, "function_type", function_type,
MIE_ATTRMAP_F_REPLACE);
return op;
}
MIE_OP_DEFINITION_BEGIN(mie_func_func, "func")
MIE_OP_DEFINITION_PRINT(print);
MIE_OP_DEFINITION_PARSE(parse);
MIE_OP_DEFINITION_TRAIT("builtin", "isolated-from-above");
MIE_OP_DEFINITION_TRAIT("func", "function-like");
MIE_OP_INTERFACE_BEGIN("builtin", "symbol", struct mie_symbol)
MIE_OP_INTERFACE_FUNC(sym_get_name) = NULL;
MIE_OP_INTERFACE_END()
MIE_OP_DEFINITION_END()