Use heuristic to determine the type to convert to for compile time types. Added parsing for generic

This commit is contained in:
Christoffer Lerno
2021-07-22 18:45:39 +02:00
parent d5f5d59a37
commit c4aa366592
13 changed files with 185 additions and 157 deletions

View File

@@ -87,8 +87,6 @@ const char *decl_to_name(Decl *decl)
return "function";
case DECL_GENERIC:
return "generic";
case DECL_GENFUNC:
TODO
case DECL_INTERFACE:
return "interface";
case DECL_MACRO:
@@ -180,7 +178,6 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:
case DECL_GENFUNC:
case DECL_GENERIC:
case DECL_CT_IF:
case DECL_CT_ELSE:
@@ -914,8 +911,8 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
indent--;
DUMPAST(decl->macro_decl.body);
DUMPEND();
case DECL_GENFUNC:
DUMPF("(macro %s", decl->name);
case DECL_GENERIC:
DUMPF("(generic %s", decl->name);
DUMPTI(decl->macro_decl.rtype);
indent++;
DUMP("(params");
@@ -963,16 +960,6 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
DUMPF("(enum-constant %s", decl->name);
DUMPEXPR(decl->enum_constant.expr);
DUMPEND();
case DECL_GENERIC:
DUMPF("(generic %s\n", decl->name);
indent++;
DUMP("(params");
DUMPDECLS(decl->generic_decl.parameters);
DUMP("(cases");
DUMPASTS(decl->generic_decl.cases);
DUMPE();
indent--;
DUMPEND();
case DECL_TYPEDEF:
DUMPF("(typedef %s", decl->name);
if (decl->typedef_decl.is_func)

View File

@@ -183,7 +183,6 @@ static void register_generic_decls(Module *module, Decl **decls)
case DECL_DISTINCT:
case DECL_ENUM:
case DECL_GENERIC:
case DECL_GENFUNC:
case DECL_INTERFACE:
case DECL_ERR:
case DECL_FUNC:

View File

@@ -428,10 +428,10 @@ typedef struct
{
bool failable : 1;
Decl **parameters;
Decl **body_parameters;
TypeInfo *type_parent; // May be null
TypeInfo *rtype; // May be null!
struct Ast_ *body;
Decl **body_parameters;
TokenId block_parameter;
} MacroDecl;
@@ -1236,6 +1236,7 @@ typedef struct Module_
Ast **files; // Asts
Decl** method_extensions;
Decl** generic_cache;
STable symbols;
STable public_symbols;
struct Context_ **contexts;
@@ -1321,6 +1322,7 @@ typedef struct Context_
Decl **functions;
Decl **macros;
Decl **generics;
Decl **generic_methods;
Decl **interfaces;
Decl **templates;
Decl **methods;

View File

@@ -113,9 +113,16 @@ void context_register_global_decl(Context *context, Decl *decl)
vec_add(context->interfaces, decl);
decl_set_external_name(decl);
break;
case DECL_GENFUNC:
case DECL_GENERIC:
vec_add(context->generics, decl);
if (decl->macro_decl.type_parent)
{
vec_add(context->generic_methods, decl);
return;
}
else
{
vec_add(context->generics, decl);
}
decl_set_external_name(decl);
break;
case DECL_MACRO:

View File

@@ -561,15 +561,13 @@ Decl *copy_decl(Decl *decl)
break;
case DECL_ARRAY_VALUE:
TODO
case DECL_GENFUNC:
case DECL_GENERIC:
case DECL_MACRO:
MACRO_COPY_TYPE(decl->macro_decl.type_parent);
MACRO_COPY_DECL_LIST(decl->macro_decl.parameters);
MACRO_COPY_AST(decl->macro_decl.body);
MACRO_COPY_TYPE(decl->macro_decl.rtype);
break;
case DECL_GENERIC:
TODO
case DECL_CT_SWITCH:
case DECL_CT_CASE:
case DECL_ATTRIBUTE:

View File

@@ -149,7 +149,6 @@ typedef enum
DECL_INTERFACE,
DECL_LABEL,
DECL_MACRO,
DECL_GENFUNC,
DECL_STRUCT,
DECL_TYPEDEF,
DECL_UNION,
@@ -157,9 +156,9 @@ typedef enum
} DeclKind;
#define NON_TYPE_DECLS DECL_ARRAY_VALUE: case DECL_IMPORT: case DECL_MACRO: \
case DECL_GENERIC: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENFUNC
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC
typedef enum
{

View File

@@ -1693,9 +1693,10 @@ static inline bool parse_func_macro_header(Context *context, bool rtype_is_optio
*/
static inline Decl *parse_macro_declaration(Context *context, Visibility visibility)
{
advance_and_verify(context, TOKEN_MACRO);
DeclKind kind = try_consume(context, TOKEN_MACRO) ? DECL_MACRO : DECL_GENERIC;
if (kind == DECL_GENERIC) advance_and_verify(context, TOKEN_GENERIC);
Decl *decl = decl_new(DECL_MACRO, context->tok.id, visibility);
Decl *decl = decl_new(kind, context->tok.id, visibility);
TypeInfo **rtype_ref = &decl->macro_decl.rtype;
TypeInfo **method_type_ref = &decl->macro_decl.type_parent;
bool failable;
@@ -2236,8 +2237,6 @@ Decl *parse_top_level_statement(Context *context)
decl = TRY_DECL_OR(parse_struct_declaration(context, visibility), poisoned_decl);
break;
case TOKEN_GENERIC:
TODO
break;
case TOKEN_MACRO:
decl = TRY_DECL_OR(parse_macro_declaration(context, visibility), poisoned_decl);
break;

View File

@@ -330,15 +330,41 @@ bool enum_to_pointer(Expr* expr, Type *from, Type *type)
return int_to_pointer(expr, type);
}
Type *type_by_expr_range(ExprConst *expr)
{
if (expr->kind == TYPE_FXX)
{
return type_double;
}
assert(expr->kind == TYPE_IXX);
BigInt *b = &expr->i;
// 1. Does it fit in a C int? If so, that's the type.
Type *type = type_cint();
if (!expr_const_will_overflow(expr, type->type_kind)) return type;
int width_max = platform_target.int128 ? 128 : 64;
int current_width = platform_target.width_c_int * 2;
while (current_width <= width_max)
{
type = type_int_signed_by_bitsize(current_width);
if (!expr_const_will_overflow(expr, type->type_kind)) return type;
type = type_int_unsigned_by_bitsize(current_width);
if (!expr_const_will_overflow(expr, type->type_kind)) return type;
current_width *= width_max;
}
return NULL;
}
bool cast_implicitly_to_runtime(Expr *expr)
{
Type *canonical = expr->type->canonical;
Type *type;
switch (canonical->type_kind)
{
case TYPE_IXX:
return cast(expr, type_long);
case TYPE_FXX:
return cast(expr, type_double);
type = type_by_expr_range(&expr->const_expr);
return type && cast(expr, type);
default:
return true;
}

View File

@@ -610,7 +610,7 @@ static inline const char *name_by_decl(Decl *method_like)
return "macro method";
case DECL_FUNC:
return "method";
case DECL_GENFUNC:
case DECL_GENERIC:
return "generic method";
default:
UNREACHABLE
@@ -1009,6 +1009,7 @@ static bool sema_analyse_macro_method(Context *context, Decl *decl)
static inline bool sema_analyse_macro(Context *context, Decl *decl)
{
bool is_generic = decl->decl_kind == DECL_GENERIC;
TypeInfo *rtype = decl->macro_decl.rtype;
if (decl->macro_decl.rtype && !sema_resolve_type_info(context, rtype)) return decl_poison(decl);
VECEACH(decl->macro_decl.parameters, i)
@@ -1018,10 +1019,16 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
assert(param->decl_kind == DECL_VAR);
switch (param->var.kind)
{
case VARDECL_PARAM:
case VARDECL_PARAM_EXPR:
case VARDECL_PARAM_CT:
case VARDECL_PARAM_REF:
if (is_generic)
{
SEMA_ERROR(param, "Only regular parameters and type parameters are allowed for generic functions.");
return decl_poison(decl);
}
FALLTHROUGH;
case VARDECL_PARAM:
if (param->var.type_info)
{
if (!sema_resolve_type_info(context, param->var.type_info)) return decl_poison(decl);
@@ -1046,6 +1053,11 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
}
param->resolve_status = RESOLVE_DONE;
}
if (is_generic && vec_size(decl->macro_decl.body_parameters))
{
SEMA_ERROR(decl->macro_decl.body_parameters[0], "Trailing block syntax is not allowed for generic functions.");
return decl_poison(decl);
}
VECEACH(decl->macro_decl.body_parameters, i)
{
Decl *param = decl->macro_decl.body_parameters[i];
@@ -1195,64 +1207,6 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
}
}
static inline bool sema_analyse_generic(Context *context, Decl *decl)
{
// 1. If it has a return type, make sure it resolves.
if (decl->generic_decl.rtype && !sema_resolve_type_info(context, decl->generic_decl.rtype)) return false;
unsigned param_count = vec_size(decl->generic_decl.parameters);
if (param_count < 1)
{
SEMA_ERROR(decl, "A generic function needs at least 1 parameter.");
return false;
}
Ast **cases = decl->generic_decl.cases;
bool default_has_been_found = false;
VECEACH(cases, i)
{
Ast *generic_case = cases[i];
if (generic_case->ast_kind == AST_CASE_STMT)
{
if (!generic_case->case_stmt.is_type)
{
SEMA_ERROR(generic_case->case_stmt.expr, "Expected a type as the argument.");
return false;
}
if (!generic_case->case_stmt.is_type_list)
{
TypeInfo **type_infos = VECNEW(TypeInfo *, 2);
vec_add(type_infos, generic_case->case_stmt.type_info);
generic_case->case_stmt.type_infos = type_infos;
generic_case->case_stmt.is_type_list = true;
}
TypeInfo **type_infos = generic_case->case_stmt.type_infos;
unsigned args = vec_size(type_infos);
for (unsigned j = 0; j < args; j++)
{
if (!sema_resolve_type_info(context, type_infos[j])) return false;
}
if (args != param_count)
{
if (param_count == 1)
{
SEMA_ERROR(type_infos[1], "Expected a single type as the argument.");
return false;
}
SEMA_ERROR(type_infos[args - 1], "Expected %d types in the case statement.", param_count);
return false;
}
continue;
}
assert(generic_case->ast_kind == AST_DEFAULT_STMT);
if (default_has_been_found)
{
SEMA_ERROR(generic_case, "More than one default statement found.");
return false;
}
}
return true;
}
@@ -1458,9 +1412,8 @@ bool sema_analyse_decl(Context *context, Decl *decl)
case DECL_FUNC:
if (!sema_analyse_func(context, decl)) return decl_poison(decl);
break;
case DECL_GENFUNC:
TODO
case DECL_MACRO:
case DECL_GENERIC:
if (!sema_analyse_macro(context, decl)) return decl_poison(decl);
break;
case DECL_VAR:
@@ -1482,9 +1435,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
if (!sema_analyse_error(context, decl)) return decl_poison(decl);
decl_set_external_name(decl);
break;
case DECL_GENERIC:
if (!sema_analyse_generic(context, decl)) return decl_poison(decl);
break;
case DECL_DEFINE:
if (!sema_analyse_define(context, decl)) return decl_poison(decl);
break;

View File

@@ -192,6 +192,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
case DECL_MACRO:
SEMA_ERROR(expr, "Expected macro followed by (...) or prefixed by '&'.");
return expr_poison(expr);
case DECL_GENERIC:
SEMA_ERROR(expr, "Expected generic followed by (...) or prefixed by '&'.");
return expr_poison(expr);
case DECL_ENUM_CONSTANT:
expr_replace(expr, decl->enum_constant.expr);
return true;
@@ -223,8 +226,6 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
case DECL_ARRAY_VALUE:
UNREACHABLE
case DECL_IMPORT:
case DECL_GENERIC:
case DECL_GENFUNC:
case DECL_CT_IF:
case DECL_CT_ELSE:
case DECL_CT_ELIF:
@@ -232,9 +233,8 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr
case DECL_CT_CASE:
case DECL_ATTRIBUTE:
case DECL_CT_ASSERT:
UNREACHABLE
case DECL_DEFINE:
TODO
UNREACHABLE
}
switch (decl->var.kind)
{
@@ -1031,22 +1031,6 @@ static inline bool sema_expr_analyse_var_call(Context *context, Type *to, Expr *
}
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Decl *decl, Expr *expr)
{
Expr **arguments = expr->call_expr.arguments;
Decl **parameter_list = decl->generic_decl.parameters;
if (vec_size(parameter_list) != vec_size(arguments))
{
SEMA_ERROR(expr, "Expected %d parameter(s) to the generic function.", vec_size(parameter_list));
return false;
}
VECEACH(arguments, i)
{
if (!sema_analyse_expr(context, NULL, arguments[i])) return false;
}
TODO
};
@@ -1239,6 +1223,11 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr
case VARDECL_PARAM:
// foo
if (!sema_analyse_expr_of_required_type(context, param->type, arg, false)) return false;
if (!param->type && !cast_implicitly_to_runtime(arg))
{
SEMA_ERROR(arg, "Constant cannot implicitly be cast to a real type.");
return false;
}
param->alignment = type_abi_alignment(param->type ? param->type : arg->type);
break;
case VARDECL_PARAM_EXPR:
@@ -1422,7 +1411,102 @@ static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr
context->macro_scope = old_macro_scope;
return ok;
}
static inline Decl *sema_generate_generic_function(Context *context, Expr *call_expr, Expr *struct_var, Decl *decl, const char *mangled_name)
{
TODO
return NULL;
}
static inline bool sema_expr_analyse_generic_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl)
{
assert(decl->decl_kind == DECL_GENERIC);
Expr **args = call_expr->call_expr.arguments;
Decl **func_params = decl->macro_decl.parameters;
unsigned explicit_args = vec_size(args);
unsigned total_args = explicit_args;
scratch_buffer_clear();
scratch_buffer_append(decl->external_name);
// TODO revisit name mangling
if (struct_var)
{
total_args++;
scratch_buffer_append_char('@');
scratch_buffer_append(struct_var->type->canonical->name);
}
if (total_args != vec_size(func_params))
{
// TODO HANDLE VARARGS
SEMA_ERROR(call_expr, "Mismatch on number of arguments.");
return false;
}
int offset = total_args - explicit_args;
for (unsigned i = 0; i < explicit_args; i++)
{
Expr *arg = args[i];
Decl *param = func_params[i + offset];
if (param->decl_kind == VARDECL_PARAM_CT_TYPE)
{
if (!sema_analyse_expr_value(context, NULL, arg)) return false;
if (arg->expr_kind != EXPR_TYPEINFO)
{
SEMA_ERROR(arg, "A type, like 'int' or 'double' was expected for the parameter '%s'.", param->name);
return false;
}
scratch_buffer_append_char(',');
scratch_buffer_append(arg->type_expr->type->canonical->name);
continue;
}
if (param->var.type_info)
{
if (!sema_analyse_expr_of_required_type(context, param->var.type_info->type, arg, true)) return false;
}
else
{
if (!sema_analyse_expr(context, NULL, arg)) return false;
if (!cast_implicitly_to_runtime(arg)) return false;
}
scratch_buffer_append_char(',');
scratch_buffer_append(arg->type->canonical->name);
}
const char *mangled_name = scratch_buffer_interned();
Decl **generic_cache = decl->module->generic_cache;
Decl *found = NULL;
VECEACH(generic_cache, i)
{
if (generic_cache[i]->external_name == mangled_name)
{
found = generic_cache[i];
break;
}
}
if (!found)
{
found = sema_generate_generic_function(context, call_expr, struct_var, decl, mangled_name);
}
// Remove type parameters from call.
for (unsigned i = 0; i < explicit_args; i++)
{
Decl *param = func_params[i + offset];
if (param->decl_kind == VARDECL_PARAM_CT_TYPE)
{
for (unsigned j = i + 1; j < explicit_args; j++)
{
args[j - 1] = args[j];
}
explicit_args--;
i--;
}
}
vec_resize(args, explicit_args);
// Perform the normal func call on the found declaration.
return sema_expr_analyse_func_call(context, to, call_expr, found, struct_var);
}
static bool sema_analyse_body_expansion(Context *context, Expr *call)
{
@@ -1537,7 +1621,7 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
SEMA_ERROR(expr, "Macro declarations cannot be called without using '@' before the macro name.");
return false;
case DECL_GENERIC:
return sema_expr_analyse_generic_call(context, to, decl, expr);
return sema_expr_analyse_generic_call(context, to, expr, struct_var, decl);
case DECL_POISONED:
return false;
default:

View File

@@ -244,7 +244,7 @@ Decl *sema_find_extension_method_in_module(Module *module, Type *type, const cha
if (extension->func_decl.type_parent->type == type) return extension;
break;
case DECL_MACRO:
case DECL_GENFUNC:
case DECL_GENERIC:
if (extension->macro_decl.type_parent->type == type) return extension;
break;
default:

View File

@@ -119,7 +119,6 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
case DECL_ARRAY_VALUE:
case DECL_IMPORT:
case DECL_MACRO:
case DECL_GENFUNC:
case DECL_GENERIC:
case DECL_LABEL:
SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "This is not a type.");
@@ -137,30 +136,6 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
}
Type *type_by_expr_range(ExprConst *expr)
{
if (expr->kind == TYPE_FXX)
{
return type_double;
}
assert(expr->kind == TYPE_IXX);
BigInt *b = &expr->i;
// 1. Does it fit in a C int? If so, that's the type.
Type *type = type_cint();
if (!expr_const_will_overflow(expr, type->type_kind)) return type;
int width_max = platform_target.int128 ? 128 : 64;
int current_width = platform_target.width_c_int * 2;
while (current_width <= width_max)
{
type = type_int_signed_by_bitsize(current_width);
if (!expr_const_will_overflow(expr, type->type_kind)) return type;
type = type_int_unsigned_by_bitsize(current_width);
if (!expr_const_will_overflow(expr, type->type_kind)) return type;
current_width *= width_max;
}
return NULL;
}
bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow)
{
@@ -192,22 +167,12 @@ bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow
{
return type_info_poison(type_info);
}
type_info->type = expr->type;
switch (type_info->type->type_kind)
if (!cast_implicitly_to_runtime(expr))
{
case TYPE_FXX:
case TYPE_IXX:
assert(expr->expr_kind == EXPR_CONST);
type_info->type = type_by_expr_range(&expr->const_expr);
if (!type_info->type)
{
SEMA_ERROR(expr, "The expression does not fit any runtime type.");
return false;
}
break;
default:
break;
SEMA_ERROR(expr, "The expression does not fit any runtime type.");
return false;
}
type_info->type = expr->type;
type_info->resolve_status = RESOLVE_DONE;
return true;
}

View File

@@ -0,0 +1,12 @@
module foo;
import std::io;
macro foo(y)
{
return y * y;
}
func void main()
{
io::printf("%d\n", @foo(10));
}