aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2023-11-12 19:19:51 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2023-11-12 19:19:51 +0200
commit5b5f6321c743e9a521e45865312a76ae0bffe450 (patch)
treee14fc4020b251240df010ec7ce72cc7810306d0a
parent8dce541c96a329e3b12f3ea3794fcc8202fbd134 (diff)
downloadek-5b5f6321c743e9a521e45865312a76ae0bffe450.tar.gz
ek-5b5f6321c743e9a521e45865312a76ae0bffe450.zip
start implementing new generics handling
+ Still requires a lot of fixes here and there
-rw-r--r--include/ek/ast.h99
-rw-r--r--include/ek/debug.h1
-rw-r--r--include/ek/scope.h67
-rw-r--r--src/actualize.c264
-rw-r--r--src/ast.c459
-rw-r--r--src/debug.c10
-rw-r--r--src/lexer.l2
-rw-r--r--src/parser.y204
-rw-r--r--src/scope.c651
9 files changed, 665 insertions, 1092 deletions
diff --git a/include/ek/ast.h b/include/ek/ast.h
index feece73..421d247 100644
--- a/include/ek/ast.h
+++ b/include/ek/ast.h
@@ -10,6 +10,8 @@
* Abstract syntax tree handling.
*/
+#define AST_GET(x, y) x->x.y
+
/** Binary operands, that is they take two arguments and produce a result. */
enum ast_binops {
/** Add, \c + */
@@ -22,16 +24,8 @@ enum ast_binops {
AST_DIV,
/** Remainder, \c % */
AST_REM,
- /** Bitwise exclusive or, \c ^ */
- AST_XOR,
- /** Raise to power \c ^^ (likely not necessary) */
- AST_POW,
- /** Bitwise and, \c & */
- AST_AND,
/** Logical and, \c && */
AST_LAND,
- /** Bitwise or, \c | */
- AST_OR,
/** Logical or, \c ||*/
AST_LOR,
/** Left shift (logical), \c << @todo add arithmetic shifts? */
@@ -48,12 +42,6 @@ enum ast_binops {
AST_ASSIGN_DIV,
/** Assigning remainder, \c %= */
AST_ASSIGN_REM,
- /** Assigning bitwise and, \c &= */
- AST_ASSIGN_AND,
- /** Assigning bitwise or, \c |= */
- AST_ASSIGN_OR,
- /** Assigning bitwise exclusive or, \c ^= */
- AST_ASSIGN_XOR,
/** Assigning logical left shift, \c >>= */
AST_ASSIGN_LSHIFT,
/** Assigning logical right shift, \c <<= */
@@ -82,10 +70,10 @@ enum ast_unops {
AST_REF,
/** Dereferencing, \c ' */
AST_DEREF,
- /** Bitwise negation, i.e. inverting bits, \c ~ */
- AST_NOT
};
+#define NULL_LOC() ((struct src_loc){0, 0, 0, 0})
+
/** Represents a source location, spanning over some bit of code. */
struct src_loc {
/** First line of interesting text. */
@@ -110,8 +98,9 @@ enum ast_node_type {
AST_INIT,
/** Assignment. */
AST_ASSIGN,
- /** Call. We don't know to what yet: macro, array or procedure.*/
+ /** Call procedure. */
AST_CALL,
+ AST_ARR_ACCESS,
/** Sizeof. */
AST_SIZEOF,
/** Cast. */
@@ -119,10 +108,10 @@ enum ast_node_type {
/** Defer. */
AST_DEFER,
/** Macro definition. */
- AST_MACRO,
- AST_MACRO_EXPANSION,
- /** Reference to previous expression, i.e. \c @ */
- AST_LAST,
+ AST_MACRO_CONSTRUCT,
+ AST_MACRO_EXPAND,
+ AST_TYPE_CONSTRUCT,
+ AST_TYPE_EXPAND,
/** Procedure definition. */
AST_PROC,
/** Goto. */
@@ -162,8 +151,6 @@ enum ast_node_type {
AST_IMPORT,
/** Enum definition. */
AST_ENUM,
- /** Union definition. */
- AST_UNION,
/** Enum constant value. */
AST_VAL,
/** Switch. */
@@ -310,6 +297,11 @@ struct ast_label {
struct ast_node *defers;
};
+struct ast_arr_access {
+ struct ast_node *base;
+ struct ast_node *idx;
+};
+
/** Goto node. */
struct ast_goto {
/** Name of label to jump to. */
@@ -394,7 +386,7 @@ struct ast_defer {
};
/** Macro definition. */
-struct ast_macro {
+struct ast_macro_construct {
/** Name of macro. */
struct ast_node *id;
/** Parameters macro takes. */
@@ -403,7 +395,18 @@ struct ast_macro {
struct ast_node *body;
};
-struct ast_macro_expansion {
+struct ast_macro_expand {
+ struct ast_node *id;
+ struct ast_node *args;
+};
+
+struct ast_type_construct {
+ struct ast_node *id;
+ struct ast_node *params;
+ struct ast_node *body;
+};
+
+struct ast_type_expand {
struct ast_node *id;
struct ast_node *args;
};
@@ -648,16 +651,6 @@ struct ast_struct {
struct ast_node *body;
};
-/** Union definition. */
-struct ast_union {
- /** Name of union. */
- struct ast_node *id;
- /** List of type parameters, if any. */
- struct ast_node *generics;
- /** Body. */
- struct ast_node *body;
-};
-
/** Enum member constant value. */
struct ast_val {
/** Name of member. */
@@ -741,8 +734,9 @@ struct ast_node {
/** Data relevant to kind. */
union {
+ struct ast_arr_access arr_access;
/** Binary operation. */
- struct ast_binop _binop;
+ struct ast_binop binop;
/** Unary operation. */
struct ast_unop _unop;
/** Call. */
@@ -750,8 +744,10 @@ struct ast_node {
/** Cast. */
struct ast_cast _cast;
/** Macro definition. */
- struct ast_macro _macro;
- struct ast_macro_expansion _macro_expansion;
+ struct ast_macro_construct _macro;
+ struct ast_macro_expand _macro_expand;
+ struct ast_type_construct type_construct;
+ struct ast_type_expand type_expand;
/** Procedure definition. */
struct ast_proc _proc;
/** Goto. */
@@ -794,8 +790,6 @@ struct ast_node {
struct ast_enum _enum;
/** Structure definition. */
struct ast_struct _struct;
- /** Union definition. */
- struct ast_union _union;
/** Enum value. */
struct ast_val _val;
/** Switch case. */
@@ -819,6 +813,8 @@ struct ast_node {
};
};
+struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc);
+
/**
* Generate binary operation node.
*
@@ -828,7 +824,9 @@ struct ast_node {
* @return Corresponding AST node.
*/
struct ast_node *gen_binop(enum ast_binops op,
- struct ast_node *left, struct ast_node *right);
+ struct ast_node *left,
+ struct ast_node *right,
+ struct src_loc loc);
/**
* Generate unary operation.
@@ -854,7 +852,7 @@ struct ast_node *gen_call(struct ast_node *id, struct ast_node *args);
* @param id ID.
* @return Corresponding AST node.
*/
-struct ast_node *gen_id(const char *id);
+struct ast_node *gen_id(const char *id, struct src_loc loc);
/**
* Generate constant integer.
@@ -947,9 +945,22 @@ struct ast_node *gen_ctrl(enum ast_ctrl_kind kind, struct src_loc loc);
* @param body Macro body.
* @return Corresponding AST node.
*/
-struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params,
+struct ast_node *gen_macro_construct(struct ast_node *id, struct ast_node *params,
struct ast_node *body);
+struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args);
+
+struct ast_node *gen_type_construct(struct ast_node *id,
+ struct ast_node *params,
+ struct ast_node *body,
+ struct src_loc loc);
+
+/** @todo change args to type type when I figure out how it should be
+ * constructed */
+struct ast_node *gen_type_expand(struct ast_node *id,
+ struct ast_node *args,
+ struct src_loc loc);
+
/**
* Generate if.
*
@@ -1079,8 +1090,6 @@ struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type);
*/
struct ast_node *gen_trait(struct ast_node *id, struct ast_node *body);
-struct ast_node *gen_macro_expansion(struct ast_node *id, struct ast_node *args);
-
/**
* Generate import;
*
diff --git a/include/ek/debug.h b/include/ek/debug.h
index d222cf4..588fc6b 100644
--- a/include/ek/debug.h
+++ b/include/ek/debug.h
@@ -121,6 +121,7 @@ void semantic_error(struct file_ctx ctx, struct ast_node *node, const char *fmt,
* @param fmt Format string. Follows standard printf() formatting.
*/
void internal_error(const char *fmt, ...);
+void internal_warn(const char *fmt, ...);
/** Issue categorization. */
enum issue_level {
diff --git a/include/ek/scope.h b/include/ek/scope.h
index 422af0f..020aaaa 100644
--- a/include/ek/scope.h
+++ b/include/ek/scope.h
@@ -75,13 +75,13 @@ struct actual {
* matched against this resolution tree to know
* which callable to choose.
*/
-struct callable {
- /** Resolve tree of callable. */
- struct proc_node *root;
- /** AST node ID of callable. */
+struct resolve {
+ /** Resolve tree of resolve. */
+ struct resolve_node *root;
+ /** AST node ID of resolve. */
struct ast_node *id;
- /** Next callable node. */
- struct callable *next;
+ /** Next resolve node. */
+ struct resolve *next;
};
/** A parameter node in the procedure resolution tree. */
@@ -89,7 +89,7 @@ struct param_node {
/** Parameter type. */
struct ast_node *type;
/** Fully resolved procedure if there is no next node. */
- struct proc_node *proc;
+ struct resolve_node *resolved;
/** Next parameter node in current parameter slot. */
struct param_node *next;
};
@@ -134,27 +134,12 @@ struct param_node {
* do_stuff(some_struct(u8)){} // ERR
* @endverbatim
*/
-struct proc_node {
- /** List of primitive types of the current parameter slot. */
- struct param_node *primitives;
- /**
- * Referential type for parameter slot.
- * Each parameter slot only allows a single referential type, because
- * it would be too difficult to check if a reference is identical
- * to another. Some special cases are somewhat trivially checked, but
- * I haven't been able to come up with a generic enough check.
- */
- struct param_node *referential;
-
- /**
- * Fallback generic type for parameter slot.
- * Each parameter slot only allows a single generic type, because
- * it would be too difficult to check if two types have overlap.
- */
- struct param_node *fallback;
+struct resolve_node {
+ /** List of parameters of the current parameter slot. */
+ struct param_node *params;
/** Next procedure with parameter slot. */
- struct ast_node *proc;
+ struct ast_node *resolved;
};
@@ -197,8 +182,6 @@ struct scope {
/** { types */
/** Enums visible in scope. */
struct visible *enums;
- /** Unions visible in scope. */
- struct visible *unions;
/** Structs visible in scope. */
struct visible *structs;
@@ -213,14 +196,15 @@ struct scope {
struct visible *builtins;
/**
- * Templates visible in scope.
+ * Traits visible in scope.
* @todo choose common terminology, sometimes the same thing is referred
* to as interfaces, sometimes templates, sometimes just type.
*/
struct visible *traits;
/** } */
- /** { Callables, incl. variables. */
+ struct visible *type_constructs;
+
/**
* Variables visible in scope.
* @note Only some variables are callable, namely array variables.
@@ -231,19 +215,10 @@ struct scope {
struct visible *macros;
/** Procedures visible in scope. */
struct visible *procs;
- /** } */
- /** { callables */
- /**
- * Anything callable.
- * @note currently each type of callable is first
- * collected into its corresponding visible list,
- * \p vars, \p macros or \p procs, but after the initial
- * program analysis they are merged together to create a callable
- * resolve tree.
- */
- struct callable *callable;
- /** } */
+ struct resolve *proc_resolve;
+ struct resolve *macro_resolve;
+ struct resolve *type_construct_resolve;
};
/** Flags for matching objects during search. */
@@ -428,7 +403,9 @@ int scope_add_alias(struct scope *scope, struct ast_node *alias);
* @param type_template Template to add to scope.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_template(struct scope *scope, struct ast_node *type_template);
+int scope_add_trait(struct scope *scope, struct ast_node *trait);
+
+int scope_add_type_construct(struct scope *scope, struct ast_node *type_construct);
/**
* Add an already allocated visible variable node to scope.
@@ -546,7 +523,7 @@ struct ast_node *scope_find_alias(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_template(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_trait(struct scope *scope, struct ast_node *id);
/**
* Find anything with ID visible to \p scope.
@@ -617,7 +594,7 @@ struct ast_node *file_scope_find_alias(struct scope *scope,
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_template(struct scope *scope,
+struct ast_node *file_scope_find_trait(struct scope *scope,
struct ast_node *id);
/**
diff --git a/src/actualize.c b/src/actualize.c
index 3a381e0..7a9e13d 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -74,7 +74,7 @@ static struct ast_node *void_type()
return NULL;
}
- struct ast_node *void_id = gen_id(void_str);
+ struct ast_node *void_id = gen_id(void_str, NULL_LOC());
if (!void_id) {
internal_error("couldn't allocate void id");
free(void_str);
@@ -100,7 +100,7 @@ static struct ast_node *i64_type()
return NULL;
}
- struct ast_node *i64_id = gen_id(i64_str);
+ struct ast_node *i64_id = gen_id(i64_str, NULL_LOC());
if (!i64_id) {
internal_error("couldn't allocate i64 id");
free(i64_str);
@@ -344,11 +344,6 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node)
break;
}
- case AST_UNION: {
- ret |= scope_add_type(scope, node);
- break;
- }
-
case AST_ENUM: {
ret |= scope_add_type(scope, node);
break;
@@ -360,11 +355,16 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node)
}
case AST_TRAIT: {
- ret |= scope_add_type(scope, node);
+ ret |= scope_add_trait(scope, node);
+ break;
+ }
+
+ case AST_TYPE_CONSTRUCT: {
+ ret |= scope_add_type_construct(scope, node);
break;
}
- case AST_MACRO: {
+ case AST_MACRO_CONSTRUCT: {
ret |= scope_add_macro(scope, node);
break;
}
@@ -406,70 +406,12 @@ static int analyze(struct scope *scope, struct ast_node *tree)
return 0;
}
-/* I would be more happy with a system where proc signatures are actualized
- * on demand, but the current scope implementation doesn't work that well for it.
- * Relatively straight forward to implement some kind of actualization
- * forwarding, the main issue is detecting duplicates. */
-static int analyze_procs(struct scope *scope)
-{
- struct visible *procs = scope->procs;
- /*
- struct act_state state = {0};
- act_set_flags(&state, ACT_ONLY_TYPES);
- if (procs)
- do {
- if (procs->owner != scope)
- goto skip_actualize;
-
- struct ast_node *proc = procs->node;
- if (actualize(&state, scope, proc))
- return -1;
-
- skip_actualize:
- procs = procs->next;
- } while (procs);
- */
-
- /* reinsert procs with actualized signatures, should make sure we don't
- * have duplicates after all aliases etc. have been eliminated */
- procs = scope->procs;
- if (procs)
- do {
- struct visible *next = procs->next;
- if (procs->owner != scope) {
- /* this is a reference, ignore it */
- free(procs);
- goto skip_add;
- }
- if (scope_add_existing_proc(scope, procs)) {
- return -1;
- }
-
-skip_add:
- procs = next;
- } while (procs);
-
- /* repeat for all child scopes */
- struct scope *child = scope->children;
- while (child) {
- if (analyze_procs(child))
- return -1;
-
- child = child->next;
- }
-
- return 0;
-}
-
int analyze_root(struct scope *scope, struct ast_node *tree)
{
scope_add_defaults(scope);
if (analyze(scope, tree))
return -1;
- if (analyze_procs(scope))
- return -1;
-
return 0;
}
@@ -683,14 +625,14 @@ static int replace_id(struct ast_node *body, struct ast_node *id,
return ast_call_on(_replace_id, body, pair);
}
-static int actualize_macro(struct act_state *state,
- struct scope *scope, struct ast_node *macro)
+static int actualize_macro_construct(struct act_state *state,
+ struct scope *scope, struct ast_node *n)
{
UNUSED(state);
/* macro bodies, arguments, etc aren't expanded upon until the macro is
* called, so just try to add it to the local scope */
- assert(macro && macro->node_type == AST_MACRO);
- return scope_add_macro(scope, macro);
+ assert(n && n->node_type == AST_MACRO_CONSTRUCT);
+ return scope_add_macro(scope, n);
}
struct ast_node *extract_typeof(struct ast_node *type)
@@ -833,7 +775,7 @@ static int actualize_macro_call(struct act_state *state,
struct scope *scope, struct ast_node *call,
struct ast_node *macro)
{
- assert(call->node_type == AST_CALL && macro->node_type == AST_MACRO);
+ assert(call->node_type == AST_CALL && macro->node_type == AST_MACRO_EXPAND);
if (ast_flags(macro, AST_FLAG_VARIADIC)) {
semantic_error(scope->fctx, macro,
"variadic macros not yet implemented");
@@ -929,7 +871,7 @@ get_callable:
if (callable->node_type == AST_PROC)
return actualize_proc_call(state, scope, call, callable);
- if (callable->node_type == AST_MACRO)
+ if (callable->node_type == AST_MACRO_EXPAND)
return actualize_macro_call(state, scope, call, callable);
/* TODO: add lambdas and arrays */
@@ -1050,8 +992,8 @@ static int actualize_binop(struct act_state *state,
{
assert(binop && binop->node_type == AST_BINOP);
- struct ast_node *left = binop->_binop.left;
- struct ast_node *right = binop->_binop.right;
+ struct ast_node *left = binop->binop.left;
+ struct ast_node *right = binop->binop.right;
int ret = 0;
ret |= actualize(state, scope, left);
@@ -1253,7 +1195,7 @@ static int actualize_type(struct act_state *state,
struct ast_node *id = type->_type.id;
if (!id)
/* no ID means void */
- type->_type.id = gen_id(strdup("void"));
+ type->_type.id = gen_id(strdup("void"), NULL_LOC());
type->loc = id->loc;
@@ -1263,11 +1205,6 @@ static int actualize_type(struct act_state *state,
EXIT_ACT(-1);
}
- /* this could be more clear, maybe add into the parser some kind
- * of meta class for traitd types? */
- if (exists->node_type == AST_UNION)
- type->_type.kind = AST_TYPE_UNION;
-
/* nothing to do, except maybe check that types are actually
* identical? */
if (exists->node_type == AST_TYPE)
@@ -1276,8 +1213,7 @@ static int actualize_type(struct act_state *state,
assert(exists->node_type == AST_ALIAS
|| exists->node_type == AST_TRAIT
|| exists->node_type == AST_STRUCT
- || exists->node_type == AST_ENUM
- || exists->node_type == AST_UNION);
+ || exists->node_type == AST_ENUM);
/* actualize whatever type we have on demand, either alias or
* trait */
if (!ast_flags(exists, AST_FLAG_ACTUAL))
@@ -1311,11 +1247,6 @@ static int actualize_type(struct act_state *state,
type->_type.enu.id = clone_ast_node(exists->_enum.id);
type->_type.enu.type = exists->_enum.type;
}
- else if (exists->node_type == AST_UNION) {
- type->_type.kind = AST_TYPE_UNION;
- type->_type.unio.id = clone_ast_node(exists->_union.id);
- type->_type.unio.impls = NULL;
- }
if (ast_flags(exists, AST_FLAG_GENERIC))
ast_set_flags(type, AST_FLAG_GENERIC);
@@ -1364,60 +1295,11 @@ static int actualize_type(struct act_state *state,
break;
}
- case AST_TYPE_UNION:
case AST_TYPE_STRUCT: {
assert(ast_flags(type, AST_FLAG_ACTUAL));
break;
}
- case AST_TYPE_GENERIC: {
- struct ast_node *id = type->_type.generic.id;
- struct ast_node *exists = file_scope_resolve_type(scope, id);
- if (!exists) {
- semantic_error(scope->fctx, type, "no such type");
- EXIT_ACT(-1);
- }
-
- if (exists->node_type != AST_UNION &&
- exists->node_type != AST_STRUCT) {
- semantic_error(scope->fctx, type,
- "type not struct or union");
- EXIT_ACT(-1);
- }
-
- if (!ast_flags(exists, AST_FLAG_ACTUAL))
- if (actualize(state, exists->scope, exists))
- EXIT_ACT(-1);
-
- struct ast_node *types = type->_type.generic.args;
- if (actualize(state, scope, types))
- EXIT_ACT(-1);
-
- while (types) {
- if (!primitive_type(types)) {
- semantic_error(scope->fctx, types,
- "only primitive types allowed in trait initialization");
- EXIT_ACT(-1);
- }
-
- if (act_flags(state, ACT_REQUIRE_FULLY_QUALIFIED)) {
- if (!fully_qualified(types)) {
- semantic_error(scope->fctx, types,
- "context requires fully qualified types");
- EXIT_ACT(-1);
- }
- }
- types = types->next;
- }
-
- if (exists->node_type == AST_UNION)
- type->_type.kind = AST_TYPE_UNION;
- else
- type->_type.kind = AST_TYPE_STRUCT;
-
- break;
- }
-
default:
semantic_error(scope->fctx, type, "unimplemented type");
EXIT_ACT(-1);
@@ -1434,7 +1316,7 @@ static int actualize_empty(struct act_state *state,
UNUSED(state);
/* TODO: converting to void is common enough that it might be worth
* creating a function for */
- struct ast_node *void_id = gen_id(strdup("void"));
+ struct ast_node *void_id = gen_id(strdup("void"), NULL_LOC());
if (!void_id) {
internal_error("couldn't allocate type id for empty statement\n");
return -1;
@@ -1578,16 +1460,6 @@ static struct ast_node *lookup_struct_member(struct ast_node *struc,
return lookup_member_idx(struc->_struct.body, find, idx);
}
-static struct ast_node *lookup_union_member(struct ast_node *unio,
- struct ast_node *find)
-{
- if (find)
- return lookup_member_name(unio->_union.body, find, NULL);
-
- size_t idx = 0;
- return lookup_member_idx(unio->_union.body, find, &idx);
-}
-
static struct ast_node *lookup_enum_member(struct ast_node *enu,
struct ast_node *find)
{
@@ -1604,50 +1476,6 @@ static struct ast_node *lookup_enum_member(struct ast_node *enu,
return m;
}
-static int init_union(struct act_state *state, struct scope *scope,
- struct ast_node *exists, struct ast_node *init)
-{
- struct ast_node *arg = init->_init.body;
- if (arg->next) {
- semantic_error(scope->fctx, arg->next,
- "multiple arguments in union initialization not allowed");
- return -1;
- }
-
- if (actualize(state, scope, arg))
- return -1;
-
- struct ast_node *member = NULL;
- if (ast_flags(arg, AST_FLAG_MEMBER)) {
- member = lookup_union_member(exists, arg->_var.id);
- }
- else {
- /* pick first element in body */
- member = exists->_union.body;
- }
-
- if (!member) {
- char *sstr = type_str(exists->type);
- semantic_error(scope->fctx, arg,
- "no such member in %s",
- sstr);
- free(sstr);
- return -1;
- }
-
- if (!implements(0, scope, arg->type, member->type)) {
- char *mstr = type_str(member->type);
- char *astr = type_str(arg->type);
- semantic_error(scope->fctx, arg, "%s does not implement %s",
- astr, mstr);
- free(mstr);
- free(astr);
- return -1;
- }
-
- return 0;
-}
-
static int init_struct(struct act_state *state, struct scope *scope,
struct ast_node *exists, struct ast_node *init)
{
@@ -1757,19 +1585,6 @@ static int actualize_struct_init_cast(struct act_state *state,
return init_struct(state, scope, exists, init);
}
-static int actualize_union_init_cast(struct act_state *state,
- struct scope *scope,
- struct ast_node *init,
- struct ast_node *actual)
-{
- struct ast_node *id = actual->_type.unio.id;
- struct ast_node *exists = file_scope_resolve_type(scope, id);
- assert(exists);
- assert(ast_flags(exists, AST_FLAG_ACTUAL));
-
- return init_union(state, scope, exists, init);
-}
-
static int actualize_init_cast(struct act_state *state,
struct scope *scope, struct ast_node *init,
struct ast_node *type)
@@ -1777,11 +1592,9 @@ static int actualize_init_cast(struct act_state *state,
struct ast_node *actual = actual_type(type);
if (actual->_type.kind == AST_TYPE_STRUCT)
return actualize_struct_init_cast(state, scope, init, actual);
- if (actual->_type.kind == AST_TYPE_UNION)
- return actualize_union_init_cast(state, scope, init, actual);
semantic_error(scope->fctx, type,
- "type is not a struct or union");
+ "type is not a struct");
return -1;
}
@@ -1881,7 +1694,7 @@ static int actualize_const(struct act_state *state, struct scope *scope,
assert(cons->node_type == AST_CONST);
if (cons->_const.kind == AST_CONST_INTEGER) {
/* error checking would be doog */
- cons->type = gen_type(AST_TYPE_ID, gen_id(strdup("i64")),
+ cons->type = gen_type(AST_TYPE_ID, gen_id(strdup("i64"), NULL_LOC()),
NULL, NULL);
scope_add_scratch(scope, cons->type);
return 0;
@@ -2204,36 +2017,6 @@ static int actualize_struct(struct act_state *state,
return 0;
}
-static int actualize_union(struct act_state *state,
- struct scope *scope, struct ast_node *node)
-{
- assert(node->node_type == AST_UNION);
- ast_set_flags(node, AST_FLAG_INIT);
- struct ast_node *generics = node->_union.generics;
- struct scope *union_scope = create_scope();
- if (!union_scope)
- return -1;
-
- scope_add_scope(node->scope, union_scope);
- if (generics)
- ast_set_flags(node, AST_FLAG_GENERIC);
-
- if (actualize(state, union_scope, generics))
- return -1;
-
- struct ast_node *body = node->_union.body;
- if (actualize(state, union_scope, body))
- return -1;
-
- /* cloning slightly odd, but I guess it's fine? */
- struct ast_node *clone_id = clone_ast_node(node->_union.id);
- node->type = gen_type(AST_TYPE_UNION, clone_id, NULL, NULL);
- scope_add_scratch(scope, node->type);
-
- ast_set_flags(node, AST_FLAG_ACTUAL);
- return 0;
-}
-
/* could maybe be renamed, but essentially dot in copper works as either
* -> or . in C, so allow structures or traits and single level pointers to
* structures or traits. */
@@ -2429,7 +2212,7 @@ static int actualize(struct act_state *state, struct scope *scope,
case AST_TRAIT: ret |= actualize_trait(state, scope, node); break;
case AST_ALIAS: ret |= actualize_alias(state, scope, node); break;
- case AST_MACRO: ret |= actualize_macro(state, scope, node); break;
+ case AST_MACRO_CONSTRUCT: ret |= actualize_macro_construct(state, scope, node); break;
case AST_CALL: ret |= actualize_call(state, scope, node); break;
case AST_BINOP: ret |= actualize_binop(state, scope, node); break;
case AST_BLOCK: ret |= actualize_block(state, scope, node); break;
@@ -2446,7 +2229,6 @@ static int actualize(struct act_state *state, struct scope *scope,
case AST_UNOP: ret |= actualize_unop(state, scope, node); break;
case AST_AS: ret |= actualize_as(state, scope, node); break;
case AST_STRUCT: ret |= actualize_struct(state, scope, node); break;
- case AST_UNION: ret |= actualize_union(state, scope, node); break;
case AST_DOT: ret |= actualize_dot(state, scope, node); break;
case AST_INIT: ret |= actualize_init(state, scope, node); break;
case AST_ASSIGN: ret |= actualize_assign(state, scope, node); break;
diff --git a/src/ast.c b/src/ast.c
index 999af4f..5a37254 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -34,69 +34,104 @@
} while ((prev = cur)); \
}
-static struct src_loc loc_span(struct ast_node *left, struct ast_node *right)
+struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc)
{
- struct src_loc loc = {0};
- if (!left && !right)
- return loc;
+ ALLOC_NODE(n, "arr_access");
+ n->node_type = AST_ARR_ACCESS;
+ n->arr_access.base = base;
+ n->arr_access.idx = idx;
+ n->loc = loc;
+ return n;
+}
+
+void destroy_arr_access(struct ast_node *arr_access)
+{
+ assert(arr_access->node_type == AST_ARR_ACCESS);
+ destroy_ast_node(AST_GET(arr_access, base));
+ destroy_ast_node(AST_GET(arr_access, idx));
+ free(arr_access);
+}
- if (!left && right)
- return right->loc;
+struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args)
+{
+ ALLOC_NODE(n, "macro_expand");
+ n->node_type = AST_MACRO_EXPAND;
+ n->_macro_expand.id = id;
+ n->_macro_expand.args = args;
+ n->loc = id->loc;
+ return n;
+}
- if (left && !right)
- return left->loc;
+void destroy_macro_expand(struct ast_node *n)
+{
+ assert(n->node_type == AST_MACRO_EXPAND);
+ destroy_ast_node(n->_macro_expand.id);
+ destroy_ast_node(n->_macro_expand.args);
+ free(n);
+}
- /* this might eventually be a good thing to do,
- * but right now I'm still having issues with initializing all nodes
- * with some kind of even slightly accurate location
- assert(left->loc.first_line);
- assert(left->loc.first_col);
- assert(right->loc.last_line);
- assert(right->loc.last_col);
- */
+struct ast_node *gen_type_construct(struct ast_node *id,
+ struct ast_node *params,
+ struct ast_node *body,
+ struct src_loc loc)
+{
+ ALLOC_NODE(n, "type_construct");
+ n->node_type = AST_TYPE_CONSTRUCT;
+ n->type_construct.id = id;
+ n->type_construct.params = params;
+ n->type_construct.body = body;
+ n->loc = loc;
+ return n;
+}
- loc.first_line = left->loc.first_line;
- loc.first_col = left->loc.first_col;
- loc.last_line = right->loc.last_line;
- loc.last_col = right->loc.last_col;
- return loc;
+void destroy_type_construct(struct ast_node *type_construct)
+{
+ destroy_ast_node(AST_GET(type_construct, id));
+ destroy_ast_node(AST_GET(type_construct, params));
+ destroy_ast_node(AST_GET(type_construct, body));
+ free(type_construct);
}
-struct ast_node *gen_macro_expansion(struct ast_node *id, struct ast_node *args)
+struct ast_node *gen_type_expand(struct ast_node *id,
+ struct ast_node *args,
+ struct src_loc loc)
{
- ALLOC_NODE(n, "macro_expansion");
- n->node_type = AST_MACRO_EXPANSION;
- n->_macro_expansion.id = id;
- n->_macro_expansion.args = args;
- n->loc = id->loc;
+ ALLOC_NODE(n, "type_expand");
+ n->node_type = AST_TYPE_EXPAND;
+ n->type_expand.id = id;
+ n->type_expand.args = args;
+ n->loc = loc;
return n;
}
-void destroy_macro_expansion(struct ast_node *macro_expansion)
+void destroy_type_expand(struct ast_node *n)
{
- assert(macro_expansion->node_type == AST_MACRO_EXPANSION);
- destroy_ast_node(macro_expansion->_macro_expansion.id);
- destroy_ast_node(macro_expansion->_macro_expansion.args);
- free(macro_expansion);
+ assert(n->node_type == AST_TYPE_EXPAND);
+ destroy_ast_node(n->type_expand.args);
+ free((void *)n->type_expand.id);
+ free(n);
}
+
struct ast_node *gen_binop(enum ast_binops op,
- struct ast_node *left, struct ast_node *right)
+ struct ast_node *left,
+ struct ast_node *right,
+ struct src_loc loc)
{
ALLOC_NODE(n, "binop");
n->node_type = AST_BINOP;
- n->_binop.op = op;
- n->_binop.left = left;
- n->_binop.right = right;
- n->loc = loc_span(left, right);
+ n->binop.op = op;
+ n->binop.left = left;
+ n->binop.right = right;
+ n->loc = loc;
return n;
}
void destroy_binop(struct ast_node *binop)
{
assert(binop->node_type == AST_BINOP);
- destroy_ast_node(binop->_binop.left);
- destroy_ast_node(binop->_binop.right);
+ destroy_ast_node(binop->binop.left);
+ destroy_ast_node(binop->binop.right);
free(binop);
}
@@ -135,12 +170,12 @@ void destroy_call(struct ast_node *call)
free(call);
}
-struct ast_node *gen_id(const char *id)
+struct ast_node *gen_id(const char *id, struct src_loc loc)
{
ALLOC_NODE(n, "id");
n->node_type = AST_ID;
n->_id.id = id;
- /* assume the parser populates location data */
+ n->loc = loc;
return n;
}
@@ -157,7 +192,6 @@ struct ast_node *gen_assign(struct ast_node *to, struct ast_node *from)
n->node_type = AST_ASSIGN;
n->_assign.to = to;
n->_assign.from = from;
- n->loc = loc_span(to, from);
return n;
}
@@ -359,11 +393,12 @@ static void destroy_fetch(struct ast_node *fetch)
free(fetch);
}
-struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params,
+struct ast_node *gen_macro_construct(struct ast_node *id,
+ struct ast_node *params,
struct ast_node *body)
{
- ALLOC_NODE(n, "body");
- n->node_type = AST_MACRO;
+ ALLOC_NODE(n, "macro_construct");
+ n->node_type = AST_MACRO_CONSTRUCT;
n->_macro.id = id;
n->_macro.params = params;
n->_macro.body = body;
@@ -371,9 +406,9 @@ struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params,
return n;
}
-void destroy_macro(struct ast_node *macro)
+void destroy_macro_construct(struct ast_node *macro)
{
- assert(macro->node_type == AST_MACRO);
+ assert(macro->node_type == AST_MACRO_CONSTRUCT);
destroy_ast_node(macro->_macro.id);
DESTROY_LIST(macro->_macro.params);
DESTROY_LIST(macro->_macro.body);
@@ -388,7 +423,6 @@ struct ast_node *gen_if(struct ast_node *cond, struct ast_node *body,
n->_if.cond = cond;
n->_if.body = body;
n->_if.els = els;
- n->loc = loc_span(cond, els);
return n;
}
@@ -494,16 +528,9 @@ struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id,
case AST_TYPE_PROC:
n->_type.proc.params = expr;
n->_type.proc.ret = ret;
- n->loc = loc_span(expr, ret);
break;
case AST_TYPE_UNION:
- n->_type.unio.id = id;
- n->_type.unio.impls = expr;
- n->loc = id->loc;
-
- break;
-
case AST_TYPE_STRUCT:
n->_type.struc.id = id;
n->_type.struc.impls = expr;
@@ -519,7 +546,6 @@ struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id,
case AST_TYPE_SIGN:
n->_type.sign.params = expr;
n->_type.sign.ret = ret;
- n->loc = loc_span(expr, ret);
break;
}
@@ -566,16 +592,12 @@ void destroy_type(struct ast_node *type)
destroy_ast_node(type->_type.proc.ret);
break;
+ case AST_TYPE_UNION:
case AST_TYPE_STRUCT:
destroy_ast_node(type->_type.struc.id);
DESTROY_LIST(type->_type.struc.impls);
break;
- case AST_TYPE_UNION:
- destroy_ast_node(type->_type.unio.id);
- DESTROY_LIST(type->_type.unio.impls);
- break;
-
case AST_TYPE_ENUM:
destroy_ast_node(type->_type.enu.id);
destroy_ast_node(type->_type.enu.type);
@@ -596,10 +618,6 @@ struct ast_node *gen_block(struct ast_node *body)
ALLOC_NODE(n, "block");
n->node_type = AST_BLOCK;
n->_block.body = body;
-
- struct ast_node *first = body;
- struct ast_node *last = ast_last_node(body);
- n->loc = loc_span(first, last);
return n;
}
@@ -727,30 +745,6 @@ void destroy_struct(struct ast_node *struc)
free(struc);
}
-struct ast_node *gen_union(struct ast_node *id,
- struct ast_node *generics, struct ast_node *body)
-{
- ALLOC_NODE(n, "union");
- n->node_type = AST_UNION;
- n->_union.id = id;
- n->_union.generics = generics;
- n->_union.body = body;
- if (id)
- n->loc = id->loc;
- else
- n->loc = body->loc;
- return n;
-}
-
-void destroy_union(struct ast_node *unio)
-{
- assert(unio->node_type == AST_UNION);
- destroy_ast_node(unio->_union.id);
- DESTROY_LIST(unio->_union.generics);
- DESTROY_LIST(unio->_union.body);
- free(unio);
-}
-
struct ast_node *gen_enum(struct ast_node *id, struct ast_node *type,
struct ast_node *body)
{
@@ -779,7 +773,6 @@ struct ast_node *gen_cast(struct ast_node *expr, struct ast_node *type)
n->node_type = AST_CAST;
n->_cast.expr = expr;
n->_cast.type = type;
- n->loc = loc_span(expr, type);
return n;
}
@@ -898,20 +891,6 @@ void destroy_empty(struct ast_node *empty)
free(empty);
}
-struct ast_node *gen_last()
-{
- ALLOC_NODE(n, "last");
- n->node_type = AST_LAST;
- /* TODO: location */
- return n;
-}
-
-void destroy_last(struct ast_node *last)
-{
- assert(last->node_type == AST_LAST);
- free(last);
-}
-
void destroy_ast_node(struct ast_node *node)
{
if (!node)
@@ -920,8 +899,9 @@ void destroy_ast_node(struct ast_node *node)
assert(node->node_type);
switch (node->node_type) {
+ case AST_TYPE_EXPAND: destroy_type_expand(node); break;
+ case AST_TYPE_CONSTRUCT: destroy_type_construct(node); break;
case AST_FETCH: destroy_fetch(node); break;
- case AST_UNION: destroy_union(node); break;
case AST_ASSIGN: destroy_assign(node); break;
case AST_INIT: destroy_init(node); break;
case AST_SIZEOF: destroy_sizeof(node); break;
@@ -930,8 +910,8 @@ void destroy_ast_node(struct ast_node *node)
case AST_UNOP: destroy_unop(node); break;
case AST_CALL: destroy_call(node); break;
case AST_CAST: destroy_cast(node); break;
- case AST_MACRO: destroy_macro(node); break;
- case AST_MACRO_EXPANSION: destroy_macro_expansion(node); break;
+ case AST_MACRO_CONSTRUCT: destroy_macro_construct(node); break;
+ case AST_MACRO_EXPAND: destroy_macro_expand(node); break;
case AST_PROC: destroy_proc(node); break;
case AST_GOTO: destroy_goto(node); break;
case AST_LABEL: destroy_label(node); break;
@@ -957,7 +937,7 @@ void destroy_ast_node(struct ast_node *node)
case AST_ID: destroy_id(node); break;
case AST_AS: destroy_as(node); break;
case AST_EMPTY: destroy_empty(node); break;
- case AST_LAST: destroy_last(node); break;
+ case AST_ARR_ACCESS: destroy_arr_access(node); break;
}
}
@@ -994,10 +974,6 @@ static const char *binop_symbol(int op)
case AST_MUL: return "*";
case AST_DIV: return "/";
case AST_REM: return "%";
- case AST_XOR: return "^";
- case AST_POW: return "^^";
- case AST_AND: return "&";
- case AST_OR: return "|";
case AST_LOR: return "||";
case AST_LAND: return "&&";
case AST_LSHIFT: return "<<";
@@ -1007,9 +983,6 @@ static const char *binop_symbol(int op)
case AST_ASSIGN_MUL: return "*=";
case AST_ASSIGN_DIV: return "/=";
case AST_ASSIGN_REM: return "%=";
- case AST_ASSIGN_AND: return "&=";
- case AST_ASSIGN_OR: return "|=";
- case AST_ASSIGN_XOR: return "^=";
case AST_ASSIGN_LSHIFT: return "<<=";
case AST_ASSIGN_RSHIFT: return ">>=";
case AST_LT: return "<";
@@ -1029,8 +1002,7 @@ static const char *unop_symbol(int op)
case AST_NEG: return "-";
case AST_LNOT: return "!";
case AST_REF: return "&";
- case AST_DEREF: return "'";
- case AST_NOT: return "~";
+ case AST_DEREF: return "*";
}
return "UNKNOWN";
@@ -1093,18 +1065,6 @@ static void __dump_ast(int depth, struct ast_node *node)
dump(depth, "}\n");
break;
- case AST_UNION:
- dump(depth, "{UNION:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, node->_union.id);
- dump_ast(depth + 1, node->_union.generics);
- dump_ast(depth + 1, node->_union.body);
-
- dump(depth, "}\n");
- break;
-
case AST_ASSIGN:
dump(depth, "{ASSIGN:");
dump_flags(node);
@@ -1171,10 +1131,10 @@ static void __dump_ast(int depth, struct ast_node *node)
case AST_BINOP:
dump(depth, "{BINOP:");
dump_flags(node);
- printf(" %s\n", binop_symbol(node->_binop.op));
+ printf(" %s\n", binop_symbol(node->binop.op));
- dump_ast(depth + 1, node->_binop.left);
- dump_ast(depth + 1, node->_binop.right);
+ dump_ast(depth + 1, node->binop.left);
+ dump_ast(depth + 1, node->binop.right);
dump(depth, "}\n");
break;
@@ -1221,8 +1181,8 @@ static void __dump_ast(int depth, struct ast_node *node)
dump(depth, "}\n");
break;
- case AST_MACRO:
- dump(depth, "{MACRO:");
+ case AST_MACRO_CONSTRUCT:
+ dump(depth, "{MACRO_CONSTRUCT:");
dump_flags(node);
putchar('\n');
@@ -1233,13 +1193,13 @@ static void __dump_ast(int depth, struct ast_node *node)
dump(depth, "}\n");
break;
- case AST_MACRO_EXPANSION:
- dump(depth, "{MACRO_EXPANSION:");
+ case AST_MACRO_EXPAND:
+ dump(depth, "{MACRO_EXPAND:");
dump_flags(node);
putchar('\n');
- dump_ast(depth + 1, node->_macro_expansion.id);
- dump_ast(depth + 1, node->_macro_expansion.args);
+ dump_ast(depth + 1, node->_macro_expand.id);
+ dump_ast(depth + 1, node->_macro_expand.args);
dump(depth, "}\n");
break;
@@ -1361,6 +1321,8 @@ static void __dump_ast(int depth, struct ast_node *node)
dump_ast(depth + 1, node->_type.proc.ret);
break;
+ /* not really but y'know */
+ case AST_TYPE_UNION:
case AST_TYPE_STRUCT:
printf(" STRUCT\n");
/* oh yeah, struc is at least right now just an ID that
@@ -1375,12 +1337,6 @@ static void __dump_ast(int depth, struct ast_node *node)
dump_ast(depth + 1, node->_type.enu.type);
break;
- case AST_TYPE_UNION:
- printf(" UNION\n");
- dump_ast(depth + 1, node->_type.unio.id);
- dump_ast(depth + 1, node->_type.unio.impls);
- break;
-
case AST_TYPE_SIGN: printf(" SIGN\n");
dump_ast(depth + 1, node->_type.sign.params);
dump_ast(depth + 1, node->_type.sign.ret);
@@ -1392,12 +1348,6 @@ static void __dump_ast(int depth, struct ast_node *node)
dump(depth, "}\n");
break;
- case AST_LAST:
- dump(depth, "{LAST:");
- dump_flags(node);
- printf("}\n");
- break;
-
case AST_EMPTY:
dump(depth, "{EMPTY:");
dump_flags(node);
@@ -1553,6 +1503,9 @@ static void __dump_ast(int depth, struct ast_node *node)
dump(depth, "}\n");
break;
+
+ default:
+ dump(depth, "{UNIMP}\n");
}
}
@@ -1577,17 +1530,30 @@ struct ast_node *clone_ast_node(struct ast_node *node)
assert(node->node_type);
struct ast_node *new = NULL;
switch (node->node_type) {
+ case AST_ARR_ACCESS:
+ new = gen_arr_access(clone_ast_node(node->arr_access.base),
+ clone_ast_node(node->arr_access.idx),
+ node->loc);
+ break;
+
+ case AST_TYPE_CONSTRUCT:
+ new = gen_type_construct(clone_ast_node(node->type_construct.id),
+ clone_ast_node(node->type_construct.params),
+ clone_ast_node(node->type_construct.body),
+ node->loc);
+ break;
+
+ case AST_TYPE_EXPAND:
+ new = gen_type_expand(clone_ast_node(node->type_expand.id),
+ clone_ast_node(node->type_expand.args),
+ node->loc);
+ break;
+
case AST_FETCH:
new = gen_fetch(clone_ast_node(node->_fetch.id),
clone_ast_node(node->_fetch.type));
break;
- case AST_UNION:
- new = gen_union(clone_ast_node(node->_union.id),
- clone_ast_node(node->_union.generics),
- clone_ast_node(node->_union.body));
- break;
-
case AST_ASSIGN:
new = gen_assign(clone_ast_node(node->_assign.to),
clone_ast_node(node->_assign.from));
@@ -1612,9 +1578,10 @@ struct ast_node *clone_ast_node(struct ast_node *node)
case AST_LABEL: new = gen_label(clone_ast_node(node->_label.id));
break;
- case AST_BINOP: new = gen_binop(node->_binop.op,
- clone_ast_node(node->_binop.left),
- clone_ast_node(node->_binop.right));
+ case AST_BINOP: new = gen_binop(node->binop.op,
+ clone_ast_node(node->binop.left),
+ clone_ast_node(node->binop.right),
+ node->loc);
break;
case AST_UNOP: new = gen_unop(node->_unop.op,
@@ -1628,13 +1595,14 @@ struct ast_node *clone_ast_node(struct ast_node *node)
case AST_DEFER: new = gen_defer(clone_ast_node(node->_defer.expr));
break;
- case AST_MACRO: new = gen_macro(clone_ast_node(node->_macro.id),
+ case AST_MACRO_CONSTRUCT: new = gen_macro_construct(
+ clone_ast_node(node->_macro.id),
clone_ast_node(node->_macro.params),
clone_ast_node(node->_macro.body));
break;
- case AST_MACRO_EXPANSION: new = gen_macro_expansion(clone_ast_node(node->_macro_expansion.id),
- clone_ast_node(node->_macro_expansion.args));
+ case AST_MACRO_EXPAND: new = gen_macro_expand(clone_ast_node(node->_macro_expand.id),
+ clone_ast_node(node->_macro_expand.args));
break;
case AST_CAST: new = gen_cast(clone_ast_node(node->_cast.expr),
@@ -1712,6 +1680,7 @@ struct ast_node *clone_ast_node(struct ast_node *node)
/* ditto, should actual be cloned? */
node->_type.trait.actual);
break;
+
case AST_TYPE_ID:
new = gen_type(AST_TYPE_ID,
clone_ast_node(node->_type.id),
@@ -1734,6 +1703,7 @@ struct ast_node *clone_ast_node(struct ast_node *node)
new = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL);
break;
+ case AST_TYPE_UNION:
case AST_TYPE_STRUCT:
new = gen_type(AST_TYPE_STRUCT,
clone_ast_node(node->_type.struc.id),
@@ -1748,13 +1718,6 @@ struct ast_node *clone_ast_node(struct ast_node *node)
NULL);
break;
- case AST_TYPE_UNION:
- new = gen_type(AST_TYPE_UNION,
- clone_ast_node(node->_type.unio.id),
- clone_ast_node(node->_type.unio.impls),
- NULL);
- break;
-
case AST_TYPE_PROC:
new = gen_type(AST_TYPE_PROC, NULL,
clone_ast_node(node->_type.proc.params),
@@ -1830,17 +1793,13 @@ struct ast_node *clone_ast_node(struct ast_node *node)
break;
case AST_ID:
- new = gen_id(strdup(node->_id.id));
+ new = gen_id(strdup(node->_id.id), node->loc);
break;
case AST_EMPTY:
new = gen_empty();
break;
- case AST_LAST:
- new = gen_last();
- break;
-
case AST_ALIAS:
new = gen_alias(clone_ast_node(node->_alias.id),
clone_ast_node(node->_alias.type));
@@ -1893,20 +1852,6 @@ static int identical_scope(void *left, void *right)
return left == right;
}
-static int identical_union(int exact, struct ast_node *a, struct ast_node *b)
-{
- if (!identical_ast_nodes(exact, a->_union.id, b->_union.id))
- return 0;
-
- if (!identical_ast_nodes(exact, a->_union.generics, b->_union.generics))
- return 0;
-
- if (!identical_ast_nodes(exact, a->_union.body, b->_union.body))
- return 0;
-
- return 1;
-}
-
static int identical_assign(int exact, struct ast_node *a, struct ast_node *b)
{
if (!identical_ast_nodes(exact, a->_assign.to, a->_assign.to))
@@ -1956,13 +1901,13 @@ static int identical_label(int exact, struct ast_node *a, struct ast_node *b)
static int identical_binop(int exact, struct ast_node *a, struct ast_node *b)
{
- if (a->_binop.op != b->_binop.op)
+ if (a->binop.op != b->binop.op)
return 0;
- if (!identical_ast_nodes(exact, a->_binop.left, b->_binop.left))
+ if (!identical_ast_nodes(exact, a->binop.left, b->binop.left))
return 0;
- if (!identical_ast_nodes(exact, a->_binop.right, b->_binop.right))
+ if (!identical_ast_nodes(exact, a->binop.right, b->binop.right))
return 0;
return 1;
@@ -2006,7 +1951,7 @@ static int identical_defer(int exact, struct ast_node *a, struct ast_node *b)
return identical_ast_nodes(exact, a->_defer.expr, b->_defer.expr);
}
-static int identical_macro(int exact, struct ast_node *a, struct ast_node *b)
+static int identical_macro_construct(int exact, struct ast_node *a, struct ast_node *b)
{
if (!identical_ast_nodes(exact, a->_macro.id, b->_macro.id))
return 0;
@@ -2020,6 +1965,17 @@ static int identical_macro(int exact, struct ast_node *a, struct ast_node *b)
return 1;
}
+static int identical_macro_expand(int exact, struct ast_node *a, struct ast_node *b)
+{
+ if (!identical_ast_nodes(exact, a->_macro_expand.id, b->_macro_expand.id))
+ return 0;
+
+ if (!identical_ast_nodes(exact, a->_macro_expand.args, b->_macro_expand.args))
+ return 0;
+
+ return 1;
+}
+
static int identical_proc(int exact, struct ast_node *a, struct ast_node *b)
{
if (!identical_ast_nodes(exact, a->_proc.id, b->_proc.id))
@@ -2170,19 +2126,6 @@ static int identical_type_struct(int exact, struct ast_node *a,
return 1;
}
-static int identical_type_union(int exact, struct ast_node *a,
- struct ast_node *b)
-{
- if (!identical_ast_nodes(exact, a->_type.unio.id, b->_type.unio.id))
- return 0;
-
- if (!identical_ast_nodes(1, a->_type.unio.impls,
- b->_type.unio.impls))
- return 0;
-
- return 1;
-}
-
static int identical_type_enum(int exact, struct ast_node *a,
struct ast_node *b)
{
@@ -2241,8 +2184,8 @@ static int identical_type(int exact, struct ast_node *a, struct ast_node *b)
case AST_TYPE_TYPEOF: ret = identical_type_typeof(exact, a, b); break;
case AST_TYPE_PROC: ret = identical_type_proc(exact, a, b); break;
case AST_TYPE_SIGN: ret = identical_type_sign(exact, a, b); break;
+ case AST_TYPE_UNION:
case AST_TYPE_STRUCT: ret = identical_type_struct(exact, a, b); break;
- case AST_TYPE_UNION: ret = identical_type_union(exact, a, b); break;
case AST_TYPE_POINTER: break;
}
@@ -2416,6 +2359,42 @@ static int identical_fetch(int exact, struct ast_node *a, struct ast_node *b)
return 1;
}
+static int identical_type_expand(int exact, struct ast_node *a, struct ast_node *b)
+{
+ if (!identical_ast_nodes(exact, a->type_expand.id, b->type_expand.id))
+ return 0;
+
+ if (!identical_ast_nodes(exact, a->type_expand.args, b->type_expand.args))
+ return 0;
+
+ return 1;
+}
+
+static int identical_type_construct(int exact, struct ast_node *a, struct ast_node *b)
+{
+ if (!identical_ast_nodes(exact, a->type_construct.id, b->type_construct.id))
+ return 0;
+
+ if (!identical_ast_nodes(exact, a->type_construct.params, b->type_construct.params))
+ return 0;
+
+ if (!identical_ast_nodes(exact, a->type_construct.body, b->type_construct.body))
+ return 0;
+
+ return 1;
+}
+
+static int identical_arr_access(int exact, struct ast_node *a, struct ast_node *b)
+{
+ if (!identical_ast_nodes(exact, a->arr_access.base, b->arr_access.base))
+ return 0;
+
+ if (!identical_ast_nodes(exact, a->arr_access.idx, b->arr_access.idx))
+ return 0;
+
+ return 1;
+}
+
/* sort of unfortnate that we can't just do a direct memcmp... */
int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b)
{
@@ -2448,8 +2427,10 @@ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b)
int ret = 0;
switch (a->node_type) {
+ case AST_ARR_ACCESS: ret = identical_arr_access(exact, a, b); break;
+ case AST_TYPE_CONSTRUCT: ret = identical_type_construct(exact, a, b); break;
+ case AST_TYPE_EXPAND: ret = identical_type_expand(exact, a, b); break;
case AST_FETCH: ret = identical_fetch(exact, a, b); break;
- case AST_UNION: ret = identical_union(exact, a, b); break;
case AST_ASSIGN: ret = identical_assign(exact, a, b); break;
case AST_INIT: ret = identical_init(exact, a, b); break;
case AST_SIZEOF: ret = identical_sizeof(exact, a, b); break;
@@ -2462,8 +2443,8 @@ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b)
case AST_CALL: ret = identical_call(exact, a, b); break;
case AST_CAST: ret = identical_cast(exact, a, b); break;
case AST_DEFER: ret = identical_defer(exact, a, b); break;
- case AST_MACRO: ret = identical_macro(exact, a, b); break;
- case AST_MACRO_EXPANSION: ret = identical_macro(exact, a, b); break;
+ case AST_MACRO_CONSTRUCT: ret = identical_macro_construct(exact, a, b); break;
+ case AST_MACRO_EXPAND: ret = identical_macro_expand(exact, a, b); break;
case AST_PROC: ret = identical_proc(exact, a, b); break;
case AST_VAR: ret = identical_var(exact, a, b); break;
case AST_FOR: ret = identical_for(exact, a, b); break;
@@ -2485,7 +2466,6 @@ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b)
case AST_TRAIT: ret = identical_trait(exact, a, b); break;
case AST_IF: ret = identical_if(exact, a, b); break;
case AST_EMPTY: break;
- case AST_LAST: break;
}
if (ret == 0)
@@ -2506,16 +2486,6 @@ int ast_flags(struct ast_node *node, enum ast_flag flags)
return node->flags & flags;
}
-static int call_on_union(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_union.id, data);
- ret |= call(node->_union.generics, data);
- ret |= call(node->_union.body, data);
- return ret;
-}
-
static int call_on_assign(int (*call)(struct ast_node *,
void *), struct ast_node *node, void *data)
{
@@ -2714,15 +2684,6 @@ static int call_on_type_typeof(int (*call)(struct ast_node *,
return call(node->_type.typeo.expr, data);
}
-static int call_on_type_union(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_type.unio.id, data);
- ret |= call(node->_type.unio.impls, data);
- return ret;
-}
-
static int call_on_type_struct(int (*call)(struct ast_node *,
void *), struct ast_node *node, void *data)
{
@@ -2795,7 +2756,7 @@ static int call_on_type(int (*call)(struct ast_node *,
case AST_TYPE_ARR: ret = call_on_type_arr(call, node, data); break;
case AST_TYPE_TYPEOF: ret = call_on_type_typeof(call, node, data);
break;
- case AST_TYPE_UNION: ret = call_on_type_union(call, node, data); break;
+ case AST_TYPE_UNION:
case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data);
break;
case AST_TYPE_PROC: ret = call_on_type_proc(call, node, data); break;
@@ -2823,8 +2784,8 @@ static int call_on_binop(int (*call)(struct ast_node *,
void *), struct ast_node *node, void *data)
{
int ret = 0;
- ret |= call(node->_binop.left, data);
- ret |= call(node->_binop.right, data);
+ ret |= call(node->binop.left, data);
+ ret |= call(node->binop.right, data);
return ret;
}
@@ -2843,7 +2804,7 @@ static int call_on_call(int (*call)(struct ast_node *,
return ret;
}
-static int call_on_macro(int (*call)(struct ast_node *,
+static int call_on_macro_construct(int (*call)(struct ast_node *,
void *), struct ast_node *node, void *data)
{
int ret = 0;
@@ -2878,11 +2839,28 @@ static int call_on_fetch(int (*call)(struct ast_node *,
return ret;
}
-static int call_on_macro_expansion(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data)
+static int call_on_macro_expand(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data)
+{
+ int ret = 0;
+ ret |= call(node->_macro_expand.id, data);
+ ret |= call(node->_macro_expand.args, data);
+ return ret;
+}
+
+static int call_on_type_construct(int (*call)(struct ast_node *, void *), struct ast_node *type_construct, void *data)
+{
+ int ret = 0;
+ ret |= call(AST_GET(type_construct, id), data);
+ ret |= call(AST_GET(type_construct, params), data);
+ ret |= call(AST_GET(type_construct, body), data);
+ return ret;
+}
+
+static int call_on_type_expand(int (*call)(struct ast_node *, void *), struct ast_node *type_expand, void *data)
{
int ret = 0;
- ret |= call(node->_macro_expansion.id, data);
- ret |= call(node->_macro_expansion.args, data);
+ ret |= call(AST_GET(type_expand, id), data);
+ ret |= call(AST_GET(type_expand, args), data);
return ret;
}
@@ -2901,8 +2879,10 @@ int ast_call_on(int (*call)(struct ast_node *,
return ret;
switch (node->node_type) {
+ case AST_ARR_ACCESS:
+ case AST_TYPE_CONSTRUCT: ret = call_on_type_construct(call, node, data); break;
+ case AST_TYPE_EXPAND: ret = call_on_type_expand(call, node, data); break;
case AST_FETCH: ret = call_on_fetch(call, node, data); break;
- case AST_UNION: ret = call_on_union(call, node, data); break;
case AST_ASSIGN: ret = call_on_assign(call, node, data); break;
case AST_INIT: ret = call_on_init(call, node, data); break;
case AST_SIZEOF: ret = call_on_sizeof(call, node, data); break;
@@ -2928,11 +2908,10 @@ int ast_call_on(int (*call)(struct ast_node *,
case AST_BINOP: ret = call_on_binop(call, node, data); break;
case AST_UNOP: ret = call_on_unop(call, node, data); break;
case AST_CALL: ret = call_on_call(call, node, data); break;
- case AST_MACRO: ret = call_on_macro(call, node, data); break;
- case AST_MACRO_EXPANSION: ret = call_on_macro_expansion(call, node, data); break;
+ case AST_MACRO_CONSTRUCT: ret = call_on_macro_construct(call, node, data); break;
+ case AST_MACRO_EXPAND: ret = call_on_macro_expand(call, node, data); break;
case AST_PROC: ret = call_on_proc(call, node, data); break;
case AST_BLOCK: ret = call_on_block(call, node, data); break;
- case AST_LAST: break;
case AST_EMBED: break;
case AST_CTRL: break;
case AST_IMPORT: break;
diff --git a/src/debug.c b/src/debug.c
index ee410be..2b993bf 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -169,6 +169,16 @@ void internal_error(const char *fmt, ...)
va_end(args);
}
+void internal_warn(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fprintf(stderr, "internal warning: ");
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+ va_end(args);
+}
+
/**
* Workhorse for type_str().
*
diff --git a/src/lexer.l b/src/lexer.l
index 50e7c1e..bcfa5be 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -211,7 +211,7 @@ STRING \"(\\.|[^"\\])*\"
. {
struct src_issue issue;
issue.level = SRC_ERROR;
- issue.loc = to_src_loc(yylloc);
+ issue.loc = src_loc(*yylloc);
issue.fctx.fbuf = parser->buf;
issue.fctx.fname = parser->fname;
src_issue(issue, "Unexpected token: %s", yytext);
diff --git a/src/parser.y b/src/parser.y
index 8f5886c..236a106 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -142,7 +142,9 @@
/* constant operations */
%nterm <node> const_expr const_unop const_binop
-%nterm <node> macro_expand
+%nterm <node> macro_expand type_expand
+
+%nterm <node> type_construct type_params type_param
/* array stuff */
%nterm <node> arr arr_inits arr_init
@@ -189,7 +191,7 @@ static int next_interesting_feature(YYSTYPE *yylval, YYLTYPE *yylloc,
* @param yylloc Bison location info.
* @return Internal location info.
*/
-static struct src_loc to_src_loc(YYLTYPE *yylloc);
+static struct src_loc src_loc(YYLTYPE yylloc);
/**
* Print parsing error.
@@ -227,15 +229,11 @@ static const char *clone_string(const char *s);
%start input;
%%
id
- : ID {
- $$ = gen_id(strdup($1));
- $$->loc = to_src_loc(&yylloc);
- }
+ : ID {$$ = gen_id(strdup($1), src_loc(@$));}
apply
: APPLY {
- $$ = gen_id(strdup($1));
- $$->loc = to_src_loc(&yylloc);
+ $$ = gen_id(strdup($1), src_loc(@$));
}
var
@@ -252,37 +250,36 @@ assign
: expr "=" expr { $$ = gen_assign($1, $3); }
binop
- : expr "+" expr { $$ = gen_binop(AST_ADD, $1, $3); }
- | expr "-" expr { $$ = gen_binop(AST_SUB, $1, $3); }
- | expr "*" expr { $$ = gen_binop(AST_MUL, $1, $3); }
- | expr "/" expr { $$ = gen_binop(AST_DIV, $1, $3); }
- | expr "%" expr { $$ = gen_binop(AST_REM, $1, $3); }
- | expr "<<" expr { $$ = gen_binop(AST_LSHIFT, $1, $3); }
- | expr ">>" expr { $$ = gen_binop(AST_RSHIFT, $1, $3); }
- | expr "+=" expr { $$ = gen_binop(AST_ASSIGN_ADD, $1, $3); }
- | expr "-=" expr { $$ = gen_binop(AST_ASSIGN_SUB, $1, $3); }
- | expr "*=" expr { $$ = gen_binop(AST_ASSIGN_MUL, $1, $3); }
- | expr "/=" expr { $$ = gen_binop(AST_ASSIGN_DIV, $1, $3); }
- | expr "%=" expr { $$ = gen_binop(AST_ASSIGN_REM, $1, $3); }
+ : expr "+" expr { $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$)); }
+ | expr "-" expr { $$ = gen_binop(AST_SUB, $1, $3, src_loc(@$)); }
+ | expr "*" expr { $$ = gen_binop(AST_MUL, $1, $3, src_loc(@$)); }
+ | expr "/" expr { $$ = gen_binop(AST_DIV, $1, $3, src_loc(@$)); }
+ | expr "%" expr { $$ = gen_binop(AST_REM, $1, $3, src_loc(@$)); }
+ | expr "<<" expr { $$ = gen_binop(AST_LSHIFT, $1, $3, src_loc(@$)); }
+ | expr ">>" expr { $$ = gen_binop(AST_RSHIFT, $1, $3, src_loc(@$)); }
+ | expr "+=" expr { $$ = gen_binop(AST_ASSIGN_ADD, $1, $3, src_loc(@$)); }
+ | expr "-=" expr { $$ = gen_binop(AST_ASSIGN_SUB, $1, $3, src_loc(@$)); }
+ | expr "*=" expr { $$ = gen_binop(AST_ASSIGN_MUL, $1, $3, src_loc(@$)); }
+ | expr "/=" expr { $$ = gen_binop(AST_ASSIGN_DIV, $1, $3, src_loc(@$)); }
+ | expr "%=" expr { $$ = gen_binop(AST_ASSIGN_REM, $1, $3, src_loc(@$)); }
| expr "<<=" expr {
- $$ = gen_binop(AST_ASSIGN_LSHIFT, $1, $3);
+ $$ = gen_binop(AST_ASSIGN_LSHIFT, $1, $3, src_loc(@$));
}
| expr ">>=" expr {
- $$ = gen_binop(AST_ASSIGN_RSHIFT, $1, $3);
+ $$ = gen_binop(AST_ASSIGN_RSHIFT, $1, $3, src_loc(@$));
}
- | expr "<" expr { $$ = gen_binop(AST_LT, $1, $3); }
- | expr ">" expr { $$ = gen_binop(AST_GT, $1, $3); }
- | expr "<=" expr { $$ = gen_binop(AST_LE, $1, $3); }
- | expr ">=" expr { $$ = gen_binop(AST_GE, $1, $3); }
- | expr "!=" expr { $$ = gen_binop(AST_NE, $1, $3); }
- | expr "==" expr { $$ = gen_binop(AST_EQ, $1, $3); }
+ | expr "<" expr { $$ = gen_binop(AST_LT, $1, $3, src_loc(@$)); }
+ | expr ">" expr { $$ = gen_binop(AST_GT, $1, $3, src_loc(@$)); }
+ | expr "<=" expr { $$ = gen_binop(AST_LE, $1, $3, src_loc(@$)); }
+ | expr ">=" expr { $$ = gen_binop(AST_GE, $1, $3, src_loc(@$)); }
+ | expr "!=" expr { $$ = gen_binop(AST_NE, $1, $3, src_loc(@$)); }
+ | expr "==" expr { $$ = gen_binop(AST_EQ, $1, $3, src_loc(@$)); }
unop
: "-" expr { $$ = gen_unop(AST_NEG, $2); }
| "!" expr { $$ = gen_unop(AST_LNOT, $2); }
| "&" expr { $$ = gen_unop(AST_REF, $2); }
| "*" expr { $$ = gen_unop(AST_DEREF, $2); }
- | "~" expr { $$ = gen_unop(AST_NOT, $2); }
arr_init
: "=>" const_expr "..." const_expr "=" arg { $$ = gen_var($2, $4, $6); }
@@ -320,24 +317,49 @@ defer
: "defer" body { $$ = gen_defer($2); }
const_binop
- : const_expr "+" const_expr { $$ = gen_binop(AST_ADD, $1, $3); }
- | const_expr "-" const_expr { $$ = gen_binop(AST_SUB, $1, $3); }
- | const_expr "*" const_expr { $$ = gen_binop(AST_MUL, $1, $3); }
- | const_expr "/" const_expr { $$ = gen_binop(AST_DIV, $1, $3); }
- | const_expr "%" const_expr { $$ = gen_binop(AST_REM, $1, $3); }
- | const_expr "<<" const_expr { $$ = gen_binop(AST_LSHIFT, $1, $3); }
- | const_expr ">>" const_expr { $$ = gen_binop(AST_RSHIFT, $1, $3); }
- | const_expr "<" const_expr { $$ = gen_binop(AST_LT, $1, $3); }
- | const_expr ">" const_expr { $$ = gen_binop(AST_GT, $1, $3); }
- | const_expr "<=" const_expr { $$ = gen_binop(AST_LE, $1, $3); }
- | const_expr ">=" const_expr { $$ = gen_binop(AST_GE, $1, $3); }
- | const_expr "!=" const_expr { $$ = gen_binop(AST_NE, $1, $3); }
- | const_expr "==" const_expr { $$ = gen_binop(AST_EQ, $1, $3); }
+ : const_expr "+" const_expr {
+ $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$));
+ }
+ | const_expr "-" const_expr {
+ $$ = gen_binop(AST_SUB, $1, $3, src_loc(@$));
+ }
+ | const_expr "*" const_expr {
+ $$ = gen_binop(AST_MUL, $1, $3, src_loc(@$));
+ }
+ | const_expr "/" const_expr {
+ $$ = gen_binop(AST_DIV, $1, $3, src_loc(@$));
+ }
+ | const_expr "%" const_expr {
+ $$ = gen_binop(AST_REM, $1, $3, src_loc(@$));
+ }
+ | const_expr "<<" const_expr {
+ $$ = gen_binop(AST_LSHIFT, $1, $3, src_loc(@$));
+ }
+ | const_expr ">>" const_expr {
+ $$ = gen_binop(AST_RSHIFT, $1, $3, src_loc(@$));
+ }
+ | const_expr "<" const_expr {
+ $$ = gen_binop(AST_LT, $1, $3, src_loc(@$));
+ }
+ | const_expr ">" const_expr {
+ $$ = gen_binop(AST_GT, $1, $3, src_loc(@$));
+ }
+ | const_expr "<=" const_expr {
+ $$ = gen_binop(AST_LE, $1, $3, src_loc(@$));
+ }
+ | const_expr ">=" const_expr {
+ $$ = gen_binop(AST_GE, $1, $3, src_loc(@$));
+ }
+ | const_expr "!=" const_expr {
+ $$ = gen_binop(AST_NE, $1, $3, src_loc(@$));
+ }
+ | const_expr "==" const_expr {
+ $$ = gen_binop(AST_EQ, $1, $3, src_loc(@$));
+ }
const_unop
: "-" const_expr { $$ = gen_unop(AST_NEG, $2); }
| "!" const_expr { $$ = gen_unop(AST_LNOT, $2); }
- | "~" const_expr { $$ = gen_unop(AST_NOT, $2); }
const_expr
: "(" const_expr ")" { $$ = $2; }
@@ -351,16 +373,16 @@ const_expr
expr
: expr "." id { $$ = gen_dot($1, $3); }
| "..." id { $$ = $2; }
- | INT { $$ = gen_int($1); $$->loc = to_src_loc(&yylloc); }
- | FLOAT { $$ = gen_float($1); $$->loc = to_src_loc(&yylloc); }
+ | INT { $$ = gen_int($1); $$->loc = src_loc(@$); }
+ | FLOAT { $$ = gen_float($1); $$->loc = src_loc(@$); }
| STRING {
$$ = gen_string(clone_string($1));
- $$->loc = to_src_loc(&yylloc);
+ $$->loc = src_loc(@$);
}
| "(" expr ")" { $$ = $2; }
| expr "(" args ")" { $$ = gen_call($1, $3); }
| expr "(" ")" { $$ = gen_call($1, NULL); }
- | expr "[" expr "]" { $$ = gen_call($1, $3); /** @todo add arr access */}
+ | expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); /** @todo add arr access */}
| "(" var_init ")" { $$ = $2; }
| "sizeof" expr { $$ = gen_sizeof($2); }
| expr "as" type { $$ = gen_cast($1, $3); }
@@ -389,8 +411,8 @@ goto
statelet
: "return" args { $$ = gen_return($2); }
| "return" { $$ = gen_return(NULL); }
- | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, to_src_loc(&yylloc)); }
- | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, to_src_loc(&yylloc)); }
+ | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(yylloc)); }
+ | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(yylloc)); }
| trait
| import
| alias
@@ -443,21 +465,20 @@ references
| "..." id { $$ = $2; ast_set_flags($$, AST_FLAG_VARIADIC); }
| id
-/* TODO: rethink how macros play into everyting */
macro
: "define" id "(" references ")" body {
- $$ = gen_macro($2, $4, $6);
+ $$ = gen_macro_construct($2, $4, $6);
ast_set_flags($6, AST_FLAG_UNHYGIENIC);
}
| "define" id "(" references "..." id ")" body {
/* TODO: the location data of the variadic ID is way off */
ast_append($4, $6);
- $$ = gen_macro($2, $4, $8);
+ $$ = gen_macro_construct($2, $4, $8);
ast_set_flags($$, AST_FLAG_VARIADIC);
ast_set_flags($8, AST_FLAG_UNHYGIENIC);
}
| "define" id "(" ")" body {
- $$ = gen_macro($2, NULL, $5);
+ $$ = gen_macro_construct($2, NULL, $5);
ast_set_flags($5, AST_FLAG_UNHYGIENIC);
}
@@ -552,8 +573,6 @@ type
$$ = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL);
$$->_type.next = $2;
}
- | anon_struct { $$ = $1; }
- | anon_union { $$ = $1; }
| "*" type {
$$ = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL);
$$->_type.next = $2;
@@ -574,6 +593,21 @@ type
| "mut" type {
$$ = $2; ast_set_flags($$, AST_FLAG_MUTABLE);
}
+ | anon_struct
+ /* syntactic sugar for struct {union {...} } */
+ | anon_union
+ /* syntactic sugar for anon_struct */
+ | type_expand
+
+types
+ : type "," types
+ | type
+
+/* vec![int] is effectively struct {vec![int]} */
+type_expand
+ : apply "[" types "]"
+ /* legal, but weird */
+ | apply "[" "]"
var_decl
: type id { $$ = gen_var($2, $1, NULL); }
@@ -599,25 +633,25 @@ proc
struct_elem
: var_decl
- | macro_expand
+ | type_expand
;
members
: struct_elem ";" members { $$ = $1; $1->next = $3; }
- | struct_elem ";" { $$ = $1; }
+ | struct_elem ";"
tagged_union
: "union" id "{" members "}" {
- $$ = gen_union($2, NULL, $4);
+ /* essentially struct {union{members}} */
+ $$ = gen_struct($2, NULL, $4);
}
anon_union
- : "union" "{" members "}" { $$ = gen_union(NULL, NULL, $3); }
- | "union" macro_expand { $$ = gen_union(NULL, NULL, $2); }
+ : "union" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); }
macro_expand
- : apply "(" ")" { $$ = gen_macro_expansion($1, NULL); }
- | apply "(" args ")" { $$ = gen_macro_expansion($1, $3); }
+ : apply "(" ")" { $$ = gen_macro_expand($1, NULL); }
+ | apply "(" args ")" { $$ = gen_macro_expand($1, $3); }
tagged_struct
: "struct" id "{" members "}" {
@@ -626,13 +660,12 @@ tagged_struct
anon_struct
: "struct" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); }
- | "struct" macro_expand { $$ = gen_struct(NULL, NULL, $2); }
trait_elem
- : id
- | id func_sign { $$ = gen_proc($1, $2, NULL); }
- | var_decl
- | macro_expand
+ : id /* trait */
+ | id func_sign { $$ = gen_proc($1, $2, NULL); } /* proc */
+ | var_decl /* member */
+ | type_expand /* type construction */
trait_elems
: trait_elem ";" trait_elems { $$ = $1; $1->next = $3; }
@@ -653,6 +686,21 @@ trait
$$ = gen_trait($2, NULL);
}
+type_param
+ : id id
+
+type_params
+ : type_param "," type_params { $$ = $1; $1->next = $3; }
+ | type_param
+
+type_construct
+ : "typedef" id "[" type_params "]" "{" members "}" {
+ $$ = gen_type_construct($2, $4, $7, src_loc(@$));
+ }
+ | "typedef" id "[" "]" "{" members "}" {
+ $$ = gen_type_construct($2, NULL, $6, src_loc(@$));
+ }
+
enum_val
: id { $$ = gen_val($1, NULL); }
| id "=" expr { $$ = gen_val($1, $3); }
@@ -686,10 +734,11 @@ top_if
/* slightly silly to allow stray semicolons at a top level, but seems to help
* with recovering from certain syntax errors */
top
- : enum { $$ = $1; }
- | proc { $$ = $1; }
- | tagged_struct { $$ = $1; }
- | tagged_union { $$ = $1; }
+ : enum
+ | proc
+ | tagged_struct
+ | tagged_union
+ | type_construct
| macro { $$ = $1; }
| top_if { $$ = $1; ast_set_flags($$, AST_FLAG_CONST); }
| import { $$ = $1; }
@@ -698,6 +747,7 @@ top
| "pub" enum { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" tagged_struct { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" tagged_union { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
+ | "pub" type_construct { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" proc { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" macro { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" import { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
@@ -759,13 +809,13 @@ static int next_interesting_feature(YYSTYPE *yylval, YYLTYPE *yylloc,
}
-static struct src_loc to_src_loc(YYLTYPE *yylloc)
+static struct src_loc src_loc(YYLTYPE yylloc)
{
struct src_loc loc;
- loc.first_line = yylloc->first_line;
- loc.last_line = yylloc->last_line;
- loc.first_col = yylloc->first_column;
- loc.last_col = yylloc->last_column;
+ loc.first_line = yylloc.first_line;
+ loc.last_line = yylloc.last_line;
+ loc.first_col = yylloc.first_column;
+ loc.last_col = yylloc.last_column;
return loc;
}
@@ -776,7 +826,7 @@ static void yyerror(YYLTYPE *yylloc, void *lexer,
struct src_issue issue;
issue.level = SRC_ERROR;
- issue.loc = to_src_loc(yylloc);
+ issue.loc = src_loc(*yylloc);
issue.fctx.fbuf = parser->buf;
issue.fctx.fname = parser->fname;
src_issue(issue, msg);
diff --git a/src/scope.c b/src/scope.c
index 8d9ada3..d6481c3 100644
--- a/src/scope.c
+++ b/src/scope.c
@@ -17,6 +17,13 @@
#include <ek/scope.h>
#include <ek/actualize.h>
+static struct ast_node *match_proc(struct scope *scope,
+ struct ast_node *id,
+ struct ast_node *args);
+
+static struct ast_node *match_macro(struct scope *scope,
+ struct ast_node *id, struct ast_node *args);
+
static int generics_trait_type(struct ast_node *generics)
{
if (!generics)
@@ -36,10 +43,6 @@ static int generic_type(struct ast_node *type)
if (type->_type.kind == AST_TYPE_STRUCT)
return generics_trait_type(type->_type.struc.impls);
- if (type->_type.kind == AST_TYPE_UNION) {
- return generics_trait_type(type->_type.unio.impls);
- }
-
if (type->_type.kind == AST_TYPE_TRAIT)
return type->_type.trait.actual == NULL;
@@ -90,59 +93,19 @@ int fully_qualified(struct ast_node *type)
return 0;
}
- if (type->_type.kind == AST_TYPE_UNION) {
- if (!ast_flags(type, AST_FLAG_GENERIC))
- return 1;
-
- if (type->_type.unio.impls)
- return fully_qualified(type->_type.unio.impls);
-
- return 0;
- }
-
return fully_qualified(type->_type.next);
}
-static struct param_node *find_primitive(struct proc_node *node,
+static struct param_node *find_matching_param(struct resolve_node *node,
struct ast_node *type)
{
- struct param_node *param = node->primitives;
+ struct param_node *param = node->params;
while (param) {
- if (types_match(type, param->type))
+ /* untyped matches everything, yay */
+ if (!param->type)
return param;
- param = param->next;
- }
-
- return NULL;
-}
-
-static int compare_primitives(struct ast_node *a, struct ast_node *b);
-
-/* match also checks qualification status of the types, since we can
- * differentiate between fully qualified types and not fully qualified types
- * by placing qualified types towards the front of the primitive list.
- * This is analoguous to the fallback thing in traits, but we want to be able to
- * support multiple not fully qualified primitives, for example
- *
- * add(some_generic_struct)
- * add(some_other_generic_struct)
- *
- * since they are easily distinguishable from eachother, in contract to traits.
- *
- * Therefore, use this when checking if a primitive should be added to the list,
- * otherwise use find_primitive() to get which primitive matches.
- * (are these names inverted from their intention? I'm not sure)
- */
-static struct param_node *match_primitive(struct proc_node *node,
- struct ast_node *type)
-{
- struct param_node *param = node->primitives;
- while (param) {
- /* note very subtle change in that we pass param->type first
- * here, but second in find_primitive. This could easily be
- * confusing... */
- if (types_match(param->type, type))
+ if (types_match(type, param->type))
return param;
param = param->next;
@@ -151,70 +114,7 @@ static struct param_node *match_primitive(struct proc_node *node,
return NULL;
}
-static int match_generic(struct scope *scope, struct ast_node *a,
- struct ast_node *b)
-{
- return implements(0, scope, a, b);
-}
-
-static int compare_impls(struct ast_node *a, struct ast_node *b)
-{
- if (!a)
- return 1;
-
- if (!b)
- return 0;
-
- while (a && b) {
- if (compare_primitives(a, b) == 0)
- return 0;
-
- a = a->next;
- b = b->next;
- }
-
- return 1;
-}
-
-/* return 1 if a should come after b, 0 if a should come before b */
-static int compare_primitives(struct ast_node *a, struct ast_node *b)
-{
- assert(a);
- if (!b)
- return 0;
-
- /* fully qualified types go first */
- if (fully_qualified(a))
- return 0;
-
- if (fully_qualified(b))
- return 1;
-
- /* TODO: figure out what kind of unqualified type we're dealing with,
- * i.e. some_generic(u32, some_other_generic) should come before
- * some_generic */
-
- /* if we're dealing with different unqualified types, push stuff
- * backwards, so we don't end up with something like
- * 1. some_generic_type
- * 2. some_generic_union
- * 3. some_generic_type(u32)
- */
-
- if (a->_type.kind != b->_type.kind)
- return 1;
-
- if (a->_type.kind == AST_TYPE_STRUCT)
- return compare_impls(a->_type.struc.impls,
- b->_type.struc.impls);
-
- if (a->_type.kind == AST_TYPE_UNION)
- return compare_impls(a->_type.unio.impls, b->_type.unio.impls);
-
- return 1;
-}
-
-static struct proc_node *insert_primitive(struct proc_node *node,
+static struct resolve_node *insert_resolve(struct resolve_node *node,
struct ast_node *type)
{
struct param_node *new = calloc(1, sizeof(struct param_node));
@@ -223,181 +123,88 @@ static struct proc_node *insert_primitive(struct proc_node *node,
}
new->type = type;
- struct proc_node *next = calloc(1, sizeof(struct proc_node));
+ struct resolve_node *next = calloc(1, sizeof(struct resolve_node));
if (!next) {
free(new);
return NULL;
}
- new->proc = next;
+ new->resolved = next;
- if (!node->primitives) {
- node->primitives = new;
+ if (!node->params) {
+ node->params = new;
return next;
}
- struct param_node *iter = node->primitives, *prev = NULL;
- while (iter && compare_primitives(type, iter->type)) {
- prev = iter;
- iter = iter->next;
- }
-
- if (prev)
- prev->next = new;
-
- new->next = iter;
-
- if (iter == node->primitives)
- node->primitives = new;
+ new->next = node->params;
+ node->params = new;
return next;
}
-static int add_next_resolve(struct scope *scope, struct ast_node *proc,
- struct proc_node *node, struct ast_node *params)
+static int add_next_resolve(struct scope *scope, struct ast_node *resolve,
+ struct resolve_node *node, struct ast_node *params)
{
assert(node);
if (params && actualize_temp_type(scope, params))
return -1;
- /* TODO: variadics? */
+ /* TODO: variadics in macros? */
/* we've run out of params, check if this is a suitable node */
if (!params) {
/* node is already occupied, error on ambiguous definition */
- if (node->proc) {
- semantic_error(scope->fctx, proc, "ambiguous callable");
- semantic_error(scope->fctx, node->proc, "matches here");
+ if (node->resolved) {
+ semantic_error(scope->fctx, resolve, "ambiguous resolution");
+ semantic_error(scope->fctx, node->resolved, "matches here");
return -1;
}
- node->proc = proc;
+ node->resolved = resolve;
return 0;
}
assert(params->node_type == AST_VAR);
- if (primitive_type(params->type)) {
- struct param_node *match = match_primitive(node, params->type);
- if (match)
- return add_next_resolve(scope, proc, match->proc,
- params->next);
-
- struct proc_node *next = insert_primitive(node, params->type);
- if (!next)
- return -1;
-
- return add_next_resolve(scope, proc, next, params->next);
- }
+ struct param_node *match = find_matching_param(node, params->type);
+ if (match)
+ return add_next_resolve(scope, resolve,
+ match->resolved,
+ params->next);
- if (referential_type(params->type)) {
- /* TODO: I don't think there's a good way to check if the
- * referential types are identical, but could be worth a shot */
- if (!node->referential) {
- node->referential =
- calloc(1, sizeof(struct param_node));
- node->referential->type = params->type;
-
- struct proc_node *next =
- calloc(1, sizeof(struct proc_node));
- node->referential->proc = next;
-
- return add_next_resolve(scope, proc, next,
- params->next);
- }
-
- if (!types_match(node->referential->type, params->type)) {
- semantic_error(scope->fctx, params->type,
- "ambiguous referential");
- semantic_error(scope->fctx, node->referential->type,
- "matches here");
- return -1;
- }
-
- /* common reference */
- destroy_ast_tree(params->type);
- params->_var.type = NULL;
- params->type = node->referential->type;
- return add_next_resolve(scope, proc, node->referential->proc,
- params->next);
- }
-
- /* otherwise try to use type as fallback */
- if (!node->fallback) {
- node->fallback = calloc(1, sizeof(struct param_node));
- node->fallback->type = params->type;
-
- struct proc_node *next = calloc(1, sizeof(struct proc_node));
- node->fallback->proc = next;
- return add_next_resolve(scope, proc, next, params->next);
- }
-
- if (!match_generic(scope, node->fallback->type, params->type)) {
- semantic_error(scope->fctx, params->type, "ambiguous generic");
- semantic_info(scope->fctx, node->fallback->type,
- "matches here");
+ /** @todo referential stuff, should only one be allowed per slot or
+ * something? */
+ struct resolve_node *next = insert_resolve(node, params->type);
+ if (!next)
return -1;
- }
- /* common reference */
- destroy_ast_tree(params->type);
- params->_var.type = NULL;
- params->type = node->fallback->type;
- return add_next_resolve(scope, proc, node->fallback->proc,
- params->next);
+ return add_next_resolve(scope, resolve, next, params->next);
}
-static int add_resolve(struct scope *scope, struct proc_node *root,
+static int add_resolve(struct scope *scope, struct resolve *resolve,
struct ast_node *proc)
{
- assert(root);
-
struct ast_node *sign = proc->_proc.sign;
struct ast_node *params = sign->_type.sign.params;
struct scope *resolv_scope = create_scope();
scope_add_scope(scope, resolv_scope);
- return add_next_resolve(resolv_scope, proc, root, params);
+ return add_next_resolve(resolv_scope, proc, resolve->root, params);
}
-static struct ast_node *proc_resolve(struct scope *scope,
- struct proc_node *node,
+static struct ast_node *resolve(struct scope *scope,
+ struct resolve_node *node,
struct ast_node *args)
{
assert(node);
if (!args) {
- if (node->proc)
- return node->proc;
+ if (node->resolved)
+ return node->resolved;
return NULL;
}
/* first check if we match a primitive type */
- struct param_node *found = find_primitive(node, args->type);
+ struct param_node *found = find_matching_param(node, args->type);
if (found)
- return proc_resolve(scope, found->proc, args->next);
-
- /* no primitives, check referentials */
- struct param_node *ref = node->referential;
- if (ref) {
- /* this works on the assumption that references actually are
- * references to previous nodes, which we've hopefully
- * initialized with real types by now.
- * However, that doesn't happen, because the fallback isn't the
- * one that the type is assigned to. Therefore, fuck. */
- if (types_match(args->type, ref->type))
- return proc_resolve(scope, ref->proc, args->next);
- }
-
- /* referential didn't match, check fallback */
- struct param_node *fallback = node->fallback;
- if (!fallback)
- return NULL;
-
- if (implements(0, scope, args->type, fallback->type)) {
- /* my idea is that we could lock each node individually and
- * allow multithreading scopes, but I realize that recursively
- * checking traits might cause a lock... */
- init_trait_type(fallback->type, fallback->type, args->type);
- return proc_resolve(scope, fallback->proc, args->next);
- }
+ return resolve(scope, found->resolved, args->next);
return NULL;
}
@@ -466,33 +273,34 @@ void destroy_actuals(struct actual *actuals)
} while ((prev = cur));
}
-void destroy_proc_node(struct proc_node *);
+void destroy_resolve_node(struct resolve_node *);
void destroy_param_nodes(struct param_node *param)
{
if (!param)
return;
- destroy_proc_node(param->proc);
+ destroy_resolve_node(param->resolved);
destroy_param_nodes(param->next);
free(param);
}
-void destroy_proc_node(struct proc_node *proc)
+void destroy_resolve_node(struct resolve_node *resolve)
{
- destroy_param_nodes(proc->primitives);
- destroy_param_nodes(proc->referential);
- destroy_param_nodes(proc->fallback);
- free(proc);
+ if (!resolve)
+ return;
+
+ destroy_param_nodes(resolve->params);
+ free(resolve);
}
-void destroy_callable(struct callable *callable)
+void destroy_resolve(struct resolve *resolve)
{
- struct callable *prev = callable, *cur;
+ struct resolve *prev = resolve, *cur;
if (prev)
do {
cur = prev->next;
- destroy_proc_node(prev->root);
+ destroy_resolve_node(prev->root);
destroy_ast_node(prev->id);
free(prev);
} while ((prev = cur));
@@ -510,14 +318,15 @@ void destroy_scope(struct scope *scope)
}
destroy_scratch(scope->scratch);
- destroy_callable(scope->callable);
+ destroy_resolve(scope->proc_resolve);
+ destroy_resolve(scope->macro_resolve);
+ destroy_resolve(scope->type_construct_resolve);
destroy_visible(scope, scope->vars);
destroy_visible(scope, scope->procs);
destroy_visible(scope, scope->builtins);
destroy_visible(scope, scope->enums);
- destroy_visible(scope, scope->unions);
destroy_visible(scope, scope->structs);
destroy_visible(scope, scope->aliases);
destroy_visible(scope, scope->traits);
@@ -572,13 +381,13 @@ static struct scratch *create_scratch(struct ast_node *scratch)
}
CREATE_VISIBLE(create_var, vars, AST_VAR);
-CREATE_VISIBLE(create_macro, macros, AST_MACRO);
CREATE_VISIBLE(create_proc, procs, AST_PROC);
+CREATE_VISIBLE(create_macro, macros, AST_MACRO_CONSTRUCT);
+CREATE_VISIBLE(create_type_construct, type_constructs, AST_TYPE_CONSTRUCT);
CREATE_VISIBLE(create_enum, enums, AST_ENUM);
CREATE_VISIBLE(create_alias, aliases, AST_ALIAS);
CREATE_VISIBLE(create_struct, structs, AST_STRUCT);
-CREATE_VISIBLE(create_union, unions, AST_UNION);
CREATE_VISIBLE(create_builtin, builtins, AST_TYPE);
CREATE_VISIBLE(create_trait, traits, AST_TRAIT);
@@ -598,15 +407,15 @@ CREATE_VISIBLE(create_trait, traits, AST_TRAIT);
}
REFERENCE_VISIBLE(reference_var, vars, AST_VAR);
-REFERENCE_VISIBLE(reference_macro, macros, AST_MACRO);
REFERENCE_VISIBLE(reference_proc, procs, AST_PROC);
+REFERENCE_VISIBLE(reference_macro, macros, AST_MACRO_CONSTRUCT);
REFERENCE_VISIBLE(reference_enum, enums, AST_ENUM);
+REFERENCE_VISIBLE(reference_trait, traits, AST_TRAIT);
REFERENCE_VISIBLE(reference_alias, aliases, AST_ALIAS);
-REFERENCE_VISIBLE(reference_union, unions, AST_UNION);
REFERENCE_VISIBLE(reference_struct, structs, AST_STRUCT);
REFERENCE_VISIBLE(reference_builtin, builtins, AST_TYPE);
-REFERENCE_VISIBLE(reference_trait, traits, AST_TRAIT);
+REFERENCE_VISIBLE(reference_type_construct, type_constructs, AST_TYPE_CONSTRUCT);
/* does NOT walk the scope tree upward if it doesn't find the var in the scope
* */
@@ -632,13 +441,13 @@ FIND_VISIBLE(scope_find_enum, enums, AST_ENUM, _enum);
FIND_VISIBLE(scope_find_alias, aliases, AST_ALIAS, _alias);
FIND_VISIBLE(scope_find_builtin, builtins, AST_TYPE, _type);
FIND_VISIBLE(scope_find_struct, structs, AST_STRUCT, _struct);
-FIND_VISIBLE(scope_find_union, unions, AST_UNION, _union);
FIND_VISIBLE(scope_find_trait, traits, AST_TRAIT, _trait);
/* note that these return the first match for the ID, and as such might not be
* what should be called. */
FIND_VISIBLE(scope_find_var, vars, AST_VAR, _var);
-FIND_VISIBLE(scope_find_macro, macros, AST_MACRO, _macro);
FIND_VISIBLE(scope_find_proc, procs, AST_PROC, _proc);
+FIND_VISIBLE(scope_find_macro, macros, AST_MACRO_CONSTRUCT, _macro);
+FIND_VISIBLE(scope_find_type_construct, type_constructs, AST_TYPE_CONSTRUCT, type_construct);
struct ast_node *scope_find(struct scope *scope, struct ast_node *id)
{
@@ -673,7 +482,7 @@ struct ast_node *scope_find(struct scope *scope, struct ast_node *id)
int name(struct scope *scope, struct ast_node *node) \
{ \
assert(node->node_type == ast_type); \
- struct ast_node *shadow = file_scope_find(scope, \
+ struct ast_node *shadow = file_scope_find_##obj_type(scope, \
node->ast_name.id); \
if (shadow) { \
semantic_error(scope->fctx, node, \
@@ -698,7 +507,6 @@ struct visible *create_type(struct scope *scope, struct ast_node *type)
case AST_TRAIT: return create_trait(scope, type);
case AST_ENUM: return create_enum(scope, type);
case AST_STRUCT: return create_struct(scope, type);
- case AST_UNION: return create_union(scope, type);
default:
semantic_error(scope->fctx, type, "unknown type");
return NULL;
@@ -713,7 +521,6 @@ int reference_type(int public, struct scope *scope, struct visible *visible)
case AST_TRAIT: return reference_trait(public, scope, visible);
case AST_ENUM: return reference_enum(public, scope, visible);
case AST_STRUCT: return reference_struct(public, scope, visible);
- case AST_UNION: return reference_union(public, scope, visible);
default:
semantic_error(scope->fctx, visible->node, "unknown type");
return 1;
@@ -758,10 +565,6 @@ struct ast_node *scope_find_type(struct scope *scope, struct ast_node *id)
if (found)
return found;
- found = scope_find_union(scope, id);
- if (found)
- return found;
-
found = scope_find_alias(scope, id);
if (found)
return found;
@@ -848,44 +651,6 @@ static int find_implementation(struct ast_node *trait, struct ast_node *type)
return 0;
}
-static struct ast_node *match_macro(int global, struct scope *scope,
- struct ast_node *id, struct ast_node *args)
-{
- const size_t arg_count = ast_list_len(args);
- struct visible *prev = scope->macros, *cur;
- if (prev)
- do {
- cur = prev->next;
- struct ast_node *macro = prev->node;
- /* must have identical IDs */
- if (!identical_ast_nodes(0, macro->_macro.id, id))
- continue;
-
- const size_t param_count = ast_list_len(
- macro->_macro.params);
-
- /* if macros have the same number of arguments, they
- * match */
- if (param_count == arg_count)
- return macro;
-
- /* if we have a variadic macro, a longer list of args is
- * a match */
- if (ast_flags(macro, AST_FLAG_VARIADIC)
- && param_count < arg_count)
- return macro;
-
- } while ((prev = cur));
-
- if (global && !scope_flags(scope, SCOPE_FILE))
- return match_macro(global, scope->parent, id, args);
-
- return NULL;
-}
-
-static struct ast_node *match_proc(enum match_flags flags, struct scope *scope,
- struct ast_node *id, struct ast_node *args);
-
static int implements_proc(enum match_flags flags, struct scope *scope,
struct ast_node *arg_type,
struct ast_node *param_type, struct ast_node *proc)
@@ -901,7 +666,7 @@ static int implements_proc(enum match_flags flags, struct scope *scope,
init_trait_types(params, param_type, arg_type);
init_trait_type(ret, param_type, arg_type);
- struct ast_node *impl = match_proc(1, scope, id, params);
+ struct ast_node *impl = match_proc(scope, id, params);
if (!impl)
goto out;
@@ -1182,34 +947,53 @@ static int match_params(enum match_flags flags, struct scope *scope,
return ret;
}
-static struct ast_node *match_proc(enum match_flags flags, struct scope *scope,
- struct ast_node *id, struct ast_node *args)
+static struct ast_node *match_resolve(struct scope *scope,
+ struct resolve *s,
+ struct ast_node *id,
+ struct ast_node *args)
{
- (void)(flags);
- struct callable *cb = scope->callable;
- while (cb) {
- if (identical_ast_nodes(0, cb->id, id))
- return proc_resolve(scope, cb->root, args);
+ while (s) {
+ /** @todo linear search, a hashmap would be faster */
+ if (identical_ast_nodes(0, s->id, id))
+ return resolve(scope, s->root, args);
- cb = cb->next;
+ s = s->next;
}
+
return NULL;
}
+static struct ast_node *match_macro(struct scope *scope,
+ struct ast_node *id,
+ struct ast_node *args)
+{
+ return match_resolve(scope, scope->macro_resolve, id, args);
+}
+
+static struct ast_node *match_proc(struct scope *scope,
+ struct ast_node *id,
+ struct ast_node *args)
+{
+ return match_resolve(scope, scope->proc_resolve, id, args);
+}
+
+static struct ast_node *match_type_construct(struct scope *scope,
+ struct ast_node *id,
+ struct ast_node *args)
+{
+ return match_resolve(scope, scope->type_construct_resolve, id, args);
+}
+
int scope_add_macro(struct scope *scope, struct ast_node *macro)
{
- assert(macro->node_type == AST_MACRO);
+ assert(macro->node_type == AST_MACRO_CONSTRUCT);
/* TODO: separate between arrays and macros? */
struct ast_node *id = macro->_macro.id;
struct ast_node *params = macro->_macro.params;
- int macro_exists = match_macro(0, scope, id, params) != NULL;
- // TODO: search for any proc with same number of parameters as macro */
- // int proc_exists = match_proc(0, scope, id, params) != NULL;
- int proc_exists = 0;
-
- if (macro_exists || proc_exists) {
+ int macro_exists = (match_macro(scope, id, params) != NULL);
+ if (macro_exists) {
semantic_error(scope->fctx, macro, "macro redefined");
return -1;
}
@@ -1225,6 +1009,75 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro)
return 0;
}
+int add_proc_resolve(struct scope *scope, struct ast_node *proc)
+{
+ if (!scope->proc_resolve) {
+ scope->proc_resolve = calloc(1, sizeof(struct resolve));
+ }
+
+ struct resolve *resolve = scope->proc_resolve;
+ while (resolve) {
+ if (identical_ast_nodes(0, resolve->id, proc->_proc.id))
+ return add_resolve(scope, resolve, proc);
+
+ resolve = resolve->next;
+ }
+
+ resolve = calloc(1, sizeof(struct resolve));
+ resolve->root = calloc(1, sizeof(struct resolve_node));
+ resolve->id = clone_ast_node(proc->_proc.id);
+ resolve->next = scope->proc_resolve;
+ scope->proc_resolve = resolve;
+
+ return add_resolve(scope, resolve, proc);
+}
+
+int add_macro_resolve(struct scope *scope, struct ast_node *macro)
+{
+ if (!scope->macro_resolve) {
+ scope->macro_resolve = calloc(1, sizeof(struct resolve));
+ }
+
+ struct resolve *resolve = scope->macro_resolve;
+ while (resolve) {
+ if (identical_ast_nodes(0, resolve->id, macro->_macro.id))
+ return add_resolve(scope, resolve, macro);
+
+ resolve = resolve->next;
+ }
+
+ resolve = calloc(1, sizeof(struct resolve));
+ resolve->root = calloc(1, sizeof(struct resolve_node));
+ resolve->id = clone_ast_node(macro->_macro.id);
+ resolve->next = scope->macro_resolve;
+ scope->macro_resolve = resolve;
+
+ return add_resolve(scope, resolve, macro);
+}
+
+int add_type_construct_resolve(struct scope *scope, struct ast_node *type_construct)
+{
+ if (!scope->type_construct_resolve) {
+ scope->type_construct_resolve = calloc(1, sizeof(struct resolve));
+ }
+
+ struct resolve *resolve = scope->type_construct_resolve;
+ while (resolve) {
+ if (identical_ast_nodes(0, resolve->id, AST_GET(type_construct, id)))
+ return add_resolve(scope, resolve, type_construct);
+
+ resolve = resolve->next;
+ }
+
+ resolve = calloc(1, sizeof(struct resolve));
+ resolve->root = calloc(1, sizeof(struct resolve_node));
+ resolve->id = clone_ast_node(AST_GET(type_construct, id));
+ resolve->next = scope->type_construct_resolve;
+ scope->type_construct_resolve = resolve;
+
+ return add_resolve(scope, resolve, type_construct);
+}
+
/* would be useful with scope_remove_proc which also removed all references? */
int scope_add_proc(struct scope *scope, struct ast_node *proc)
{
@@ -1234,7 +1087,7 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc)
struct ast_node *sign = proc->_proc.sign;
struct ast_node *params = sign->_type.sign.params;
- struct ast_node *macro_exists = match_macro(0, scope, id, params);
+ struct ast_node *macro_exists = match_proc(scope, id, params);
if (macro_exists) {
semantic_error(scope->fctx, proc, "proc redefined");
@@ -1246,6 +1099,8 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc)
if (!new)
return -1;
+ add_proc_resolve(scope, proc);
+
int public = scope_flags(scope, SCOPE_PUBLIC);
if (scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC))
return reference_proc(public, scope->parent, new);
@@ -1253,65 +1108,28 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc)
return 0;
}
-int scope_add_existing_var(struct scope *scope, struct visible *visible)
-{
- struct ast_node *node = visible->node;
- assert(node->node_type == AST_VAR);
- struct ast_node *shadow = file_scope_find(scope, node->_var.id);
- if (shadow) {
- semantic_error(scope->fctx, node, "shadowing is not allowed\n");
- semantic_info(scope->fctx, shadow,
- "previous declaration was here\n");
- return -1;
- }
-
- visible->next = scope->vars;
- scope->vars = visible;
-
- int public = scope_flags(scope, SCOPE_PUBLIC);
- if (scope_flags(scope, SCOPE_FILE) && ast_flags(node, AST_FLAG_PUBLIC))
- return reference_proc(public, scope->parent, visible);
-
- return 0;
-}
-
-int scope_add_existing_proc(struct scope *scope, struct visible *visible)
+int scope_add_type_construct(struct scope *scope, struct ast_node *type_construct)
{
- struct ast_node *proc = visible->node;
- assert(proc->node_type == AST_PROC);
+ assert(type_construct->node_type == AST_TYPE_CONSTRUCT);
- struct ast_node *id = proc->_proc.id;
- struct ast_node *sign = proc->_proc.sign;
- struct ast_node *params = sign->_type.sign.params;
+ struct ast_node *id = AST_GET(type_construct, id);
+ struct ast_node *params = AST_GET(type_construct, params);
- struct ast_node *macro_exists = match_macro(0, scope, id, params);
- if (macro_exists) {
- semantic_error(scope->fctx, proc, "proc redefined");
- semantic_info(scope->fctx, macro_exists, "previously as macro");
+ int type_construct_exists = (match_type_construct(scope, id, params) != NULL);
+ if (type_construct_exists) {
+ semantic_error(scope->fctx, type_construct, "type construct redefined");
return -1;
}
- if (!scope->callable) {
- scope->callable = calloc(1, sizeof(struct callable));
- scope->callable->root = calloc(1, sizeof(struct proc_node));
- scope->callable->id = clone_ast_node(id);
- return add_resolve(scope, scope->callable->root, proc);
- }
-
- struct callable *cb = scope->callable;
- while (cb) {
- if (identical_ast_nodes(0, cb->id, id))
- return add_resolve(scope, cb->root, proc);
+ struct visible *new = create_type_construct(scope, type_construct);
+ if (!new)
+ return -1;
- cb = cb->next;
- }
+ int public = scope_flags(scope, SCOPE_PUBLIC);
+ if (scope_flags(scope, SCOPE_FILE) && ast_flags(type_construct, AST_FLAG_PUBLIC))
+ return reference_type_construct(public, scope->parent, new);
- cb = calloc(1, sizeof(struct callable));
- cb->root = calloc(1, sizeof(struct proc_node));
- cb->id = clone_ast_node(id);
- cb->next = scope->callable;
- scope->callable = cb;
- return add_resolve(scope, cb->root, proc);
+ return 0;
}
#define FIND_FILE_VISIBLE(name, obj_type) \
@@ -1378,12 +1196,12 @@ struct ast_node *file_scope_find(struct scope *scope, struct ast_node *id)
return NULL;
}
-struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *call)
+struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *macro)
{
- assert(call->node_type == AST_CALL);
- struct ast_node *id = call->_call.id;
- struct ast_node *args = call->_call.args;
- return match_macro(0, scope, id, args);
+ assert(macro->node_type == AST_MACRO_EXPAND);
+ struct ast_node *id = macro->_macro_expand.id;
+ struct ast_node *args = macro->_macro_expand.args;
+ return match_macro(scope, id, args);
}
static int trait_contains_proc(enum match_flags flags, struct scope *scope,
@@ -1423,39 +1241,7 @@ struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call)
struct ast_node *id = call->_call.id;
struct ast_node *args = call->_call.args;
- /* TODO: this prints out an error for each scope we run through, figure
- * out where we should check for this stuff so only a single error is
- * printed */
- /* loop over arguments, if any of them are traitd check that the
- * found proc can be found in the trait */
- struct ast_node *arg = args;
- while (arg) {
- struct ast_node *trait = extract_trait(arg->type);
- if (!trait)
- goto next;
-
- if (!trait_contains_proc(MATCH_CALL, scope, trait, id,
- args)) {
- char *cstr = call_str(call);
- char *tstr = type_str(arg);
- semantic_error(scope->fctx, arg,
- "%s not associated with %s",
- cstr,
- tstr);
- free(cstr);
- free(tstr);
- return NULL;
- }
-
-next:
- arg = arg->next;
- }
-
- struct ast_node *proc = match_proc(MATCH_CALL, scope, id, args);
- if (!proc)
- return NULL;
-
- return proc;
+ return match_proc(scope, id, args);
}
struct ast_node *scope_resolve_actual(struct scope *scope,
@@ -1488,40 +1274,11 @@ struct ast_node *scope_resolve_actual(struct scope *scope,
return NULL;
}
-struct ast_node *scope_resolve_arr(struct scope *scope, struct ast_node *call)
-{
- assert(call->node_type == AST_CALL);
- /* could implement arrays in multiple dimensions, though that might make
- * other things complicated so disallow it for now */
- if (ast_list_len(call->_call.args) != 1)
- return NULL;
-
- struct ast_node *arg = call->_call.args;
- struct ast_node *var = scope_find_var(scope, call->_call.id);
- if (!var)
- return NULL;
-
- /* TODO: actualize has types_match, should it be generalized into ast.c
- * or something? */
- if (!identical_ast_nodes(0, var->type, arg->type))
- return NULL;
-
- return var;
-}
-
struct ast_node *scope_resolve_call(struct scope *scope, struct ast_node *call)
{
assert(call->node_type == AST_CALL);
- /* TODO: should make sure we're getting an array at some point */
- struct ast_node *found = scope_resolve_arr(scope, call);
- if (found)
- return found;
-
- found = scope_resolve_macro(scope, call);
- if (found)
- return found;
-
- found = scope_resolve_actual(scope, call);
+ /* unsure if actual should be here or somewhere else but eh */
+ struct ast_node *found = scope_resolve_actual(scope, call);
if (found)
return found;
@@ -1567,10 +1324,6 @@ struct ast_node *scope_resolve_type(struct scope *scope, struct ast_node *type)
id = type->_struct.id;
break;
- case AST_UNION:
- id = type->_union.id;
- break;
-
case AST_ENUM:
id = type->_enum.id;
break;
@@ -1596,6 +1349,18 @@ struct ast_node *file_scope_resolve_type(struct scope *scope,
return NULL;
}
+struct ast_node *file_scope_resolve_macro(struct scope *scope, struct ast_node *macro)
+{
+ struct ast_node *found = scope_resolve_macro(scope, macro);
+ if (found)
+ return found;
+
+ if (!scope_flags(scope, SCOPE_FILE))
+ return file_scope_resolve_type(scope->parent, macro);
+
+ return NULL;
+}
+
/* this might be useful somewhere else as well */
static const char *default_types[] = {"u8", "u16", "u32", "u64",
"i8" "i16", "i32", "i64",
@@ -1610,7 +1375,7 @@ int scope_add_defaults(struct scope *root)
i < sizeof(default_types) / sizeof(default_types[0]);
++i) {
const char *type = default_types[i];
- struct ast_node *n = gen_id(strdup(type));
+ struct ast_node *n = gen_id(strdup(type), NULL_LOC());
if (!n)
return -1;