aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/std.ek243
-rw-r--r--include/ek/ast.h76
-rw-r--r--include/ek/ops.h10
-rw-r--r--include/ek/scope.h284
-rw-r--r--src/actualize.c147
-rw-r--r--src/asm.c18
-rw-r--r--src/ast.c368
-rw-r--r--src/compiler.c25
-rw-r--r--src/debug.c17
-rw-r--r--src/lexer.l3
-rw-r--r--src/ops.c120
-rw-r--r--src/parser.y176
-rw-r--r--src/scope.c709
13 files changed, 798 insertions, 1398 deletions
diff --git a/examples/std.ek b/examples/std.ek
new file mode 100644
index 0000000..4404730
--- /dev/null
+++ b/examples/std.ek
@@ -0,0 +1,243 @@
+/* comparison traits */
+pub typedef cmp {
+ eq(*cmp a, *cmp b => bool);
+ cmp(*cmp a, *cmp b => bool);
+
+ ne(*cmp a, *cmp b => bool) {return !a.eq(b)}
+
+ lt(*cmp a, *cmp b => bool) {return a.cmp(b) < 0}
+ bt(*cmp a, *cmp b => bool) {return a.cmp(b) > 0}
+ le(*cmp a, *cmp b => bool) {return !a.bt(b)}
+ ge(*cmp a, *cmp b => bool) {return !a.lt(b)}
+
+}
+
+/* hash traits */
+pub typedef hash {
+ hash(*hash h => i27);
+}
+
+/* builtin type 'implementations' */
+/* as a special case, builtin types are allowed to be typedef'd to implement
+ * interfaces */
+pub typedef i9 {
+ fmt;
+ fmt(*i9 i, string args => result![string]) {
+ return ok!("123".str());
+ }
+
+ cmp;
+ eq(*i9 i, *i9 o => bool) {
+ return *i == *o;
+ }
+
+ cmp(*i9 i, *i9 o => bool) {
+ return *i - *o;
+ }
+
+ hash;
+ hash(*i9 i => i27) {
+ return i;
+ }
+}
+
+/* special case of special case, 'str' means *i9 but pointers aren't allowed in
+ * the parser stage. Is this an ugly solution? Feels kind of ugly. */
+pub typedef str {
+ fmt;
+ fmt(*i9 s, string args => result![string]) {
+ /* here we should probably copy s in case it is statically
+ * defined */
+ return {.len = 2, .buf = "cp"} as string;
+ }
+
+ cmp;
+ eq(*i9 s, *i9 o => bool) {
+ if s == o {return true;}
+ /* iterate over stuff I guess */
+ }
+
+ lt(*i9 s, *i9 o => bool) {
+ if s == o {return false;}
+ /* iterate over stuff */
+ }
+
+ hash;
+ hash(*i9 s => i27) {
+ /* iterate over all characters and hash them I guess */
+ }
+}
+
+/* 'continue typedef' to implement more traits and stuff, can be postponed a bit
+ * as I don't think it's an essential feature yet. Might be in the future,
+ * though, just requires some extra finangling to figure out how each thing
+ * should work.
+ * Particularly template continuations might be a bit interesting, should we
+ * force the user to replicate the type arguments or should it be done
+ * automatically?
+
+pub continue str {
+ /* implement some other traits */
+};
+*/
+
+/* any import */
+pub typedef any {}
+
+/* string import */
+pub typedef string {
+ usize len;
+ *i9 buf;
+}
+
+/* result import */
+pub typedef result[any T] {
+ *i9 err;
+ T val;
+
+ err(*result r => bool) {
+ return r.err != null;
+ }
+}
+
+pub define ok(v) {
+ {.err = null, .val = v} as result;
+}
+
+pub define err(e) {
+ {.err = e} as result;
+}
+
+/* fmt import */
+pub typedef fmt {
+ fmt(*fmt p, string args => result![string]);
+ str(*fmt p => string) {
+ /* is this a loop? allowed? */
+ /* alternative would be {.len = 0, .buf = ""} as string I guess*/
+ const r = p.fmt("".str());
+ if r.err() {
+ abort("error converting to string");
+ }
+
+ return r.v;
+ }
+}
+
+/* file import */
+pub typedef file {
+ /* file could also just be a memory region, kind of like memstream? */
+}
+
+/* here would be useful if macros could take type arguments as well, for example
+ * f must be a file and fmt must be a string, but I guess this is a quick I can
+ * live with... */
+pub define fprint(f, fmt, ...args) {
+ /* possible name clash, hmmm */
+ i27 __ek_reserved_pos = 0;
+ const for __ek_reserved_a : args {
+ __ek_reserved_pos += f.output_fmt_string(fmt, pos);
+ if __ek_reserved_pos < 0 {
+ abort("too many print arguments");
+ }
+
+ /* pos should be at a {}, with an unknown string of arguments
+ * within */
+ /* find matching '}' */
+ i27 __ek_reserved_prev_pos = __ek_reserved_pos;
+ do {
+ if fmt.at(__ek_reserved_pos) == '}' {break;}
+ __ek_reserved_pos += 1;
+ } while 1;
+
+ /* skip leading '{' */
+ __ek_reserved_prev_pos += 1;
+
+ /* copy arguments to a separate string (probably pretty slow, a
+ * string_view or something could be beneficial here)*/
+ const p = fmt.dup(__ek_reserved_prev_pos, __ek_reserved_pos);
+ const string r = a.fmt(p);
+
+ /* better abort messages could be useful, provide some
+ * "stringify" operator? #a or something? I guess we have
+ * src_loc that could lift the appropriate code, maybe? not
+ * high priority for now anyway */
+ if r.err() {abort("failed to format argument");}
+ f.output_raw_string(r.v);
+
+ /* skip over trailing '}' */
+ __ek_reserved_pos += 1;
+ }
+
+ /* if output_fmt_string() still wants to continue, we have extra
+ * brackets that can't be handled as we ran out of args */
+ if f.output_fmt_string(fmt, pos) > 0 {
+ abort("too few print arguments");
+ }
+}
+
+/* vec import */
+pub typedef vec[any T] {
+ // we want our vector to be formattable, used by print etc.
+ fmt;
+ fmt(*vec v, string args => result![string]) {
+ return ok!("test".str());
+ }
+
+ usize len;
+ *T buf;
+ ^(usize) alloc;
+
+ init(*vec v, ^(usize) alloc) {
+ v.len = 0;
+ v.buf = null;
+ v.alloc = alloc;
+ }
+
+ init(*vec v) {
+ init(v, alloc);
+ }
+
+ length(*vec v => usize) { return v.len; }
+ index(*vec v, usize i => T)
+ {
+ assert(i < v.len, "index %zu out of bounds\n", i);
+ return &v.buf[i];
+ }
+
+ index(*vec v, isize i => T)
+ {
+ if i < 0 {
+ assert(-i < v.len, "reverse index %zi out of bounds\n", i);
+ return &v.buf[v.len + i];
+ }
+
+ /* v.whatever() is effectively syntactic sugar for
+ * whatever::typeof(v)(&v), but since I don't allow typeof()
+ * it's built-in. */
+ return v.index(i as usize);
+ }
+
+ prepend(*vec v, T e) { v.insert(e, 0); }
+ append(*vec v, T e) { v.insert(e, v.len); }
+
+ preplace(*vec v, T e) { v.place(e, 0); }
+ applace(*vec v, T e) { v.place(e, v.len); }
+
+ place(*vec v, T e) {}
+ insert(*vec v, T e) {}
+
+ deinit(*vec v)
+ {
+ for (usize i = 0); i < v.len; i += 1 {
+ deinit(v[i]);
+ v[i] = null;
+ }
+
+ dealloc(v.buf);
+ }
+}
+
+main() {
+ vec![i8] what;
+ what.length();
+}
diff --git a/include/ek/ast.h b/include/ek/ast.h
index e078f59..201b746 100644
--- a/include/ek/ast.h
+++ b/include/ek/ast.h
@@ -32,18 +32,17 @@
#define AST_ARR_ACCESS(x) x->_arr_access
#define AST_MACRO_CONSTRUCT(x) x->_macro_construct
#define AST_MACRO_EXPAND(x) x->_macro_expand
-#define AST_TYPE_CONSTRUCT(x) x->_type_construct
#define AST_TYPE_EXPAND(x) x->_type_expand
#define AST_TYPE(x) x->_type
#define AST_ID_TYPE(x) x->_type._id
+#define AST_CONSTRUCT_TYPE(x) x->_type._construct
#define AST_TRAIT_TYPE(x) x->_type._trait
/** @todo is sign and proc type the same ? */
-#define AST_TYPEOF_TYPE(x) x->_type._typeof
-#define AST_PROC_TYPE(x) x->_type._proc
+#define AST_PROC_TYPE(x) x->_type._proc
#define AST_ARR_TYPE(x) x->_type._arr
-#define AST_SIGN_TYPE(x) x->_type._sign
-#define AST_ENUM_TYPE(x) x->_type._enum
+#define AST_SIGN_TYPE(x) x->_type._sign
+#define AST_ENUM_TYPE(x) x->_type._enum
#define AST_UNION_TYPE(x) x->_type._union
#define AST_STRUCT_TYPE(x) x->_type._struct
/* might rename primitive to something else */
@@ -148,7 +147,6 @@ enum ast_node_type {
/** Macro definition. */
AST_MACRO_CONSTRUCT,
AST_MACRO_EXPAND,
- AST_TYPE_CONSTRUCT,
AST_TYPE_EXPAND,
/** Procedure definition. */
AST_PROC,
@@ -228,8 +226,7 @@ enum ast_type_kind {
AST_TYPE_PRIMITIVE,
/** Array. */
AST_TYPE_ARR,
- /** Typeof expression. */
- AST_TYPE_TYPEOF,
+ AST_TYPE_CONSTRUCT,
/** Trait. */
AST_TYPE_TRAIT,
/** Pointer to a type. */
@@ -366,6 +363,8 @@ struct trait_implemented {
struct ast_trait {
/** Name of trait. */
struct ast_node *id;
+ /** Parameters to construct concrete type from trait. */
+ struct ast_node *params;
/** Body of trait. */
struct ast_node *body;
/** List of types that implement this trait. */
@@ -401,7 +400,7 @@ struct ast_unop {
/** A call. */
struct ast_call {
/** Name to call, whatever it may be. */
- struct ast_node *id;
+ struct ast_node *expr;
/** List of arguments to call. */
struct ast_node *args;
};
@@ -427,12 +426,6 @@ struct ast_macro_expand {
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;
@@ -550,7 +543,7 @@ struct ast_type {
/** Type kind. */
enum ast_type_kind kind;
/**
- * Next type element in whole type. I.e. 'u32 is two elements, one
+ * Next type element in whole type. I.e. *i9 is two elements, one
* AST_TYPE_POINTER and one AST_TYPE_ID.
*/
struct ast_node *next;
@@ -565,6 +558,11 @@ struct ast_type {
} _id;
struct {
+ struct ast_node *id;
+ struct ast_node *args;
+ } _construct;
+
+ struct {
enum ast_primitive type;
} _primitive;
@@ -578,12 +576,6 @@ struct ast_type {
struct ast_node *base;
} _ptr;
- /** Typeof. */
- struct {
- /** Expression to take type of. */
- struct ast_node *expr;
- } _typeof;
-
/** Procedure. */
struct {
/** Name. */
@@ -764,7 +756,6 @@ struct ast_node {
/** Macro definition. */
struct ast_macro_construct _macro_construct;
struct ast_macro_expand _macro_expand;
- struct ast_type_construct _type_construct;
struct ast_type_expand _type_expand;
/** Procedure definition. */
struct ast_proc _proc;
@@ -831,7 +822,8 @@ struct ast_node {
};
};
-struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc);
+struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx,
+ struct src_loc loc);
/**
* Generate binary operation node.
@@ -843,8 +835,8 @@ struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, str
*/
struct ast_node *gen_binop(enum ast_binops op,
struct ast_node *left,
- struct ast_node *right,
- struct src_loc loc);
+ struct ast_node *right,
+ struct src_loc loc);
/**
* Generate unary operation.
@@ -862,7 +854,8 @@ struct ast_node *gen_unop(enum ast_unops op, struct ast_node *expr);
* @param args Arguments to call.
* @return Corresponding AST node.
*/
-struct ast_node *gen_call(struct ast_node *id, struct ast_node *args);
+struct ast_node *gen_call(struct ast_node *id, struct ast_node *args,
+ struct src_loc loc);
/**
* Generate ID.
@@ -963,21 +956,18 @@ 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_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 src_loc loc);
+struct ast_node *gen_macro_construct(struct ast_node *id,
+ struct ast_node *params,
+ struct ast_node *body);
-struct ast_node *gen_type_construct(struct ast_node *id,
- struct ast_node *params,
- struct ast_node *body,
- struct src_loc loc);
+struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args,
+ 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);
+ struct ast_node *args,
+ struct src_loc loc);
/**
* Generate if.
@@ -1018,8 +1008,9 @@ struct ast_node *gen_primitive(enum ast_primitive type, struct src_loc loc);
* @param rets Return type, when applicable.
* @return Corresponding AST node.
*/
-struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id,
- struct ast_node *decl, struct ast_node *rets);
+struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *t2,
+ struct ast_node *t1,
+ struct src_loc loc);
/**
* Generate block.
@@ -1038,7 +1029,7 @@ struct ast_node *gen_block(struct ast_node *body);
* @return Corresponding AST node.
*/
struct ast_node *gen_var(struct ast_node *id, struct ast_node *type,
- struct ast_node *init);
+ struct ast_node *init, struct src_loc loc);
/**
* Generate lambda.
@@ -1069,7 +1060,7 @@ struct ast_node *gen_proc(struct ast_node *id, struct ast_node *type,
* @param id Name to do dot with.
* @return Corresponding AST node.
*/
-struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id);
+struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id, struct src_loc loc);
/**
* Generate enum definition.
@@ -1107,7 +1098,8 @@ struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type);
* @param body Body.
* @return Corresponding AST node.
*/
-struct ast_node *gen_trait(struct ast_node *id, struct ast_node *body);
+struct ast_node *gen_trait(struct ast_node *id, struct ast_node *params,
+ struct ast_node *body, struct src_loc loc);
/**
* Generate import;
diff --git a/include/ek/ops.h b/include/ek/ops.h
index 0d9d433..a7672d7 100644
--- a/include/ek/ops.h
+++ b/include/ek/ops.h
@@ -2,6 +2,7 @@
#define EK_OPS_H
#include <ek/ast.h>
+#include <stdio.h>
enum loc_kind {
LOC_NONE, LOC_REG, LOC_MEM
@@ -10,8 +11,6 @@ enum loc_kind {
struct loc {
enum loc_kind kind;
struct loc *next;
- size_t start;
- size_t end;
size_t reg;
long long off;
size_t width;
@@ -50,10 +49,7 @@ struct ops {
struct op *head;
};
-struct ops *create_ops();
-void destroy_ops(struct ops *ops);
-int lower_ops(struct scope *root, struct ops *ops);
-int alloc_regs(struct ops *ops);
-int print_asm(struct ops *ops, const char *output);
+int lower_ops(struct scope *root, const char *fname);
+int print_asm(struct ops *ops, FILE *f);
#endif /* EK_OPS_H */
diff --git a/include/ek/scope.h b/include/ek/scope.h
index 10b0aad..9c4224e 100644
--- a/include/ek/scope.h
+++ b/include/ek/scope.h
@@ -49,83 +49,6 @@ struct actual {
struct actual *next;
};
-/**
- * Callable nodes visible to scope.
- *
- * Each callable consists of an ID and
- * a resolution tree built from parameters the
- * callable can take.
- * Parameters passed to the callable are
- * matched against this resolution tree to know
- * which callable to choose.
- */
-struct resolve {
- /** Resolve tree of resolve. */
- struct resolve_node *root;
- /** AST node ID of resolve. */
- struct ast_node *id;
- /** Next resolve node. */
- struct resolve *next;
-};
-
-/** A parameter node in the procedure resolution tree. */
-struct param_node {
- /** Parameter type. */
- struct ast_node *type;
- /** Fully resolved procedure if there is no next node. */
- struct resolve_node *resolved;
- /** Next parameter node in current parameter slot. */
- struct param_node *next;
-};
-
-/**
- * A procedure node in the resolution tree.
- *
- * A resolution tree is how Ek chooses which overloaded callable
- * to choose from. For example,
- *
- * @verbatim
- * do_stuff(u8, f32){}
- * do_stuff(u8, f64){}
- * do_stuff(u16, f32){}
- * @endverbatim
- *
- * generates a resolution tree of the form
- * @verbatim
- * callable:
- * do_stuff -> u8 -> f32
- * -> f64
- * u16 -> f32
- * @endverbatim
- *
- * When a callable is called with some arguments, the argument's types
- * are actualized and using the resolve tree, the correct do_stuff is chosen.
- *
- * Additionally, interfaces are allowed, but only as a 'fallback'. That is, if
- * no trivial parameter type matches the argument type, the fallback is checked,
- * and if the argument type doesn't implement the fallback, the resolution
- * is considered to have failed.
- *
- * Self-refential parameter types are similarly checked after primitive types.
- *
- * @note Generic structures without type arguments are considered primitive,
- * as are fully qualified generic structures, anything between is disallowed.
- * Eg.
- * @verbatim
- * struct some_struct (a A, b B) {...}
- * do_stuff(some_struct){...} // OK
- * do_stuff(some_struct(u8, u16)){} // OK
- * do_stuff(some_struct(u8)){} // ERR
- * @endverbatim
- */
-struct resolve_node {
- /** List of parameters of the current parameter slot. */
- struct param_node *params;
-
- /** Next procedure with parameter slot. */
- struct ast_node *resolved;
-};
-
struct types {
struct ast_node *id;
struct ast_node *type;
@@ -165,35 +88,12 @@ struct scope {
*/
struct actual *actuals;
- /** { types */
-
+ struct visible *vars;
+ struct visible *procs;
+ struct visible *macros;
struct visible *types;
- /** } */
-
struct visible *type_constructs;
-
- /**
- * Variables visible in scope.
- * @note Only some variables are callable, namely array variables.
- * @todo Could maybe add separate array list instead of a variable list?
- */
- struct visible *vars;
-
- struct resolve *proc_resolve;
- struct resolve *macro_resolve;
- struct resolve *type_construct_resolve;
-};
-
-/** Flags for matching objects during search. */
-enum match_flags {
- /** Search globally, not just in current scope. */
- MATCH_GLOBAL = (1 << 0),
- /**
- * Match call arguments to parameters.
- * If this flag is not present, only the name is matched.
- */
- MATCH_CALL = (1 << 1),
};
/**
@@ -236,17 +136,6 @@ void destroy_visible(struct scope *scope, struct visible *visible);
void destroy_scope(struct scope *scope);
/**
- * Create temporary scope.
- * Adds \p parent as the parent of the scope, but doesn't add the new scope
- * to the list of children \p parent has.
- * Caller is responsible for destroying the temporary scope.
- *
- * @param parent The temporary scope's parent.
- * @return New temporary scope.
- */
-struct scope *create_temp_scope(struct scope *parent);
-
-/**
* Add default stuff to scope, mainly builtin types.
*
* @param root Scope to add default stuff to.
@@ -327,7 +216,8 @@ int scope_add_var(struct scope *scope, struct ast_node *var);
* @param type Type to add to scope.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_type(struct scope *scope, struct ast_node *id, struct ast_node *type);
+int scope_add_type(struct scope *scope, struct ast_node *id,
+ struct ast_node *type);
/**
* Add procedure to scope.
@@ -359,53 +249,7 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro);
*/
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.
- * After initial analysis, preallocated variable nodes are actualized
- * and added back into the scope to build up the resolution tree.
- *
- * @param scope Scope to add variable node to.
- * @param var Variable to to add to scope.
- * @return \c 0 when succesful, non-zero otherwise.
- */
-int scope_add_existing_var(struct scope *scope, struct visible *var);
-
-/**
- * Add an already allocated visible procedure node to scope.
- * After initial analysis, preallocated procedure nodes are (partially)
- * actualized and added back into the scope to build up the resolution tree.
- *
- * @param scope SCope to add procedure node to.
- * @param proc Procedure to add to scope.
- * @return \c 0 when succesful, non-zero otherwise.
- */
-int scope_add_existing_proc(struct scope *scope, struct visible *proc);
-
-/**
- * Find an actualized AST node with ID in \p scope.
- * Since actuals are file global, technically no need for a file_*
- * @note Doesn't do any resolution. See scope_resolve_actual().
- *
- * @param scope Scope to look in.
- * @param id ID of actual to find.
- * @return Pointer to the actualized AST node corresponding to \p id if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_find_actual(struct scope *scope, struct ast_node *id);
-
-/**
- * Find anything with ID in \p scope.
- * @note Only looks in the current scope, so doesn't see anything outside
- * of it. See file_scope_find().
- *
- * @param scope Scope to look in.
- * @param id ID of whatever to find.
- * @return Pointer to the AST node corresponding to \p id if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_find(struct scope *scope, struct ast_node *id);
+int scope_resolve(struct scope *scope);
/**
* Find a variable with ID in \p scope.
@@ -480,16 +324,6 @@ struct ast_node *scope_find_alias(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.
- *
- * @param scope Scope to look in.
- * @param id ID of whatever to find.
- * @return Pointer to the AST node corresponding to \p id if found,
- * otherwise \c NULL.
- */
-struct ast_node *file_scope_find(struct scope *scope, struct ast_node *id);
-
-/**
* Find a variable with ID visible to \p scope.
*
* @param scope Scope to look in.
@@ -549,110 +383,6 @@ struct ast_node *file_scope_find_alias(struct scope *scope,
* otherwise \c NULL.
*/
struct ast_node *file_scope_find_trait(struct scope *scope,
- struct ast_node *id);
-
-/**
- * Try to resolve a call to an array in \p scope.
- *
- * @param scope Scope to look in.
- * @param call AST call node to try and match to an array.
- * @return Pointer to the AST node corresponding to \p call if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_resolve_arr(struct scope *scope, struct ast_node *call);
-
-/**
- * Try to resolve a call to a macro in \p scope.
- *
- * @param scope Scope to look in.
- * @param call AST call node to try and match to a macro.
- * @return Pointer to the AST node corresponding to \p call if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_resolve_macro(struct scope *scope,
- struct ast_node *call);
-
-/**
- * Try to resolve a call to an actualized node in \p scope.
- *
- * @param scope Scope to look in.
- * @param call AST call node to try and match to an actualized node.
- * @return Pointer to the AST node corresponding to \p call if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_resolve_actual(struct scope *scope,
- struct ast_node *call);
-
-/**
- * Try to resolve a call to a procedure in \p scope.
- *
- * @param scope Scope to look in.
- * @param call AST call node to try and match to a procedure.
- * @return Pointer to the AST node corresponding to \p call if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call);
-
-/**
- * Try to resolve a call to an AST node in \p scope.
- *
- * @param scope Scope to look in.
- * @param call AST call node to try and match to an AST node.
- * @return Pointer to the AST node corresponding to \p call if found,
- * otherwise \c NULL.
- */
-struct ast_node *scope_resolve_call(struct scope *scope, struct ast_node *call);
-
-/**
- * Try to resolve a call to an AST node visible to \p scope.
- *
- * @param scope Scope to look in.
- * @param call AST call node to try and match to an AST node.
- * @return Pointer to the AST node corresponding to \p call if found,
- * otherwise \c NULL.
- */
-struct ast_node *file_scope_resolve_call(struct scope *scope,
- struct ast_node *call);
-
-struct ast_node *file_scope_resolve_macro(struct scope *scope,
- struct ast_node *macro);
-
-/**
- * Check if \p arg_type implements \p param_type.
- *
- * A type implement another type if
- * a) They resolve to the same primitive type after alias and expression substitutions
- * b) One type is a trait and the other type has all members and
- * procedures specified in the trait.
- *
- * \p arg_type should never be a trait, so I suppose it's undefined if a trait
- * implements another trait.
- *
- * @param flags Flags for resolution.
- * @param scope Scope to check types in.
- * @param arg_type Argument type.
- * @param param_type Parameter type.
- * @return \c 1 if \p arg_type implements \p param_type, \c 0 otherwise.
- */
-int implements(enum match_flags flags, struct scope *scope,
- struct ast_node *arg_type,
- struct ast_node *param_type);
-
-/**
- * Check if type is primitive.
- *
- * @param type Type to check.
- * @return \c 1 if \p type is primitive, \c 0 otherwise.
- */
-int primitive_type(struct ast_node *type);
-
-/**
- * Check if type is fully qualified.
- * A fully qualified type is a struct or union with all type parameters filled.
- *
- * @param type Type to check.
- * @return \c 1 if \p type is fully qualified, \c 0 otherwise.
- */
-int fully_qualified(struct ast_node *type);
+ struct ast_node *id);
#endif /* SCOPE_H */
diff --git a/src/actualize.c b/src/actualize.c
index 694eca9..591df1a 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -288,7 +288,7 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node)
case AST_IMPORT: {
const char *file = AST_IMPORT(node).file;
ret |= process_file(&scope,
- ast_flags(node, AST_FLAG_PUBLIC), file);
+ ast_flags(node, AST_FLAG_PUBLIC), file);
break;
}
@@ -329,11 +329,6 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node)
break;
}
- case AST_TYPE_CONSTRUCT: {
- ret |= scope_add_type_construct(scope, node);
- break;
- }
-
case AST_MACRO_CONSTRUCT: {
ret |= scope_add_macro(scope, node);
break;
@@ -377,7 +372,6 @@ static int analyze(struct scope *scope, struct ast_node *tree)
int analyze_root(struct scope *scope, struct ast_node *tree)
{
- scope_add_defaults(scope);
if (analyze(scope, tree))
return -1;
@@ -410,10 +404,6 @@ int types_match(struct ast_node *a, struct ast_node *b)
assert(a->node_type == AST_TYPE);
assert(b->node_type == AST_TYPE);
- /* typeofs match 'everything' */
- if (AST_TYPE(a).kind == AST_TYPE_TYPEOF || AST_TYPE(b).kind == AST_TYPE_TYPEOF)
- return 1;
-
/* if the type kind doesn't match, we're done. */
if (AST_TYPE(a).kind != AST_TYPE(b).kind)
return 0;
@@ -423,7 +413,7 @@ int types_match(struct ast_node *a, struct ast_node *b)
if (AST_TYPE(a).kind == AST_TYPE_POINTER)
return types_match(AST_PTR_TYPE(a).base,
- AST_PTR_TYPE(b).base);
+ AST_PTR_TYPE(b).base);
if (AST_TYPE(a).kind == AST_TYPE_PRIMITIVE)
return primitives_match(a, b);
@@ -467,7 +457,7 @@ static int replace_id(struct ast_node *body, struct ast_node *id,
}
static int actualize_macro_construct(struct act_state *state,
- struct scope *scope, struct ast_node *n)
+ struct scope *scope, struct ast_node *n)
{
UNUSED(state);
/* macro bodies, arguments, etc aren't expanded upon until the macro is
@@ -476,18 +466,6 @@ static int actualize_macro_construct(struct act_state *state,
return scope_add_macro(scope, n);
}
-struct ast_node *extract_typeof(struct ast_node *type)
-{
- if (!type)
- return 0;
-
- assert(type->node_type == AST_TYPE);
- if (type->_type.kind == AST_TYPE_TYPEOF)
- return type;
-
- return extract_typeof(type->_type.next);
-}
-
struct ast_node *extract_trait(struct ast_node *type)
{
if (!type)
@@ -501,7 +479,7 @@ struct ast_node *extract_trait(struct ast_node *type)
}
static void actualize_trait_types(struct ast_node *params,
- struct ast_node *args)
+ struct ast_node *args)
{
/** @todo replace trait types with arg types, should probably be merged
* */
@@ -534,11 +512,12 @@ static int actualize_proc_call(struct act_state *state,
}
static int actualize_macro_expand(struct act_state *state,
- struct scope *scope, struct ast_node *macro_expand)
+ struct scope *scope,
+ struct ast_node *macro_expand)
{
assert(macro_expand->node_type == AST_MACRO_EXPAND);
struct ast_node *id = AST_MACRO_EXPAND(macro_expand).id;
- struct ast_node *macro = file_scope_resolve_macro(scope, id);
+ struct ast_node *macro = file_scope_find_macro(scope, id);
if (!macro) {
semantic_error(scope->fctx, macro_expand, "no such macro");
return -1;
@@ -596,11 +575,16 @@ static int actualize_call(struct act_state *state,
/* check that arguments exist, make sure they have types etc. */
/* TODO: procedure callbacks? */
- int ret = actualize(state, scope, call->_call.args);
+ int ret = actualize(state, scope, AST_CALL(call).args);
if (ret)
return ret;
- struct ast_node *callable = file_scope_resolve_call(scope, call);
+ ret = actualize(state, scope, AST_CALL(call).expr);
+ if (ret)
+ return ret;
+
+ /** @todo check if call args and expr types match */
+ struct ast_node *callable = file_scope_find_proc(scope, call);
if (!callable) {
char *str = call_str(call);
semantic_error(scope->fctx, call, "no such callable: %s", str);
@@ -609,6 +593,8 @@ static int actualize_call(struct act_state *state,
}
assert(callable->node_type == AST_PROC);
+ /** @todo we should probably start with just iterating over all procs and check
+ * if they're valid rather than generating them on 'demand' */
return actualize_proc_call(state, scope, call, callable);
}
@@ -622,7 +608,7 @@ static void warn_unused_labels(struct act_state *state, struct scope *scope)
struct ast_node *label = labels->node;
if (!ast_flags(label, AST_FLAG_ACTUAL))
semantic_warn(scope->fctx, label,
- "unused label");
+ "unused label");
} while ((labels = labels->next));
}
@@ -638,7 +624,7 @@ static int undefined_gotos(struct act_state *state, struct scope *scope)
struct ast_node *got = gotos->node;
if (!ast_flags(got, AST_FLAG_ACTUAL)) {
semantic_warn(scope->fctx, got,
- "undefined label");
+ "undefined label");
ret = -1;
}
@@ -808,27 +794,27 @@ static int actualize_id(struct act_state *state,
/** @todo at the moment we always assume an ID is a variable, but stuff
* like function callbacks should be added in the future */
struct ast_node *decl = file_scope_find_var(scope, id);
- if (!decl) {
- semantic_error(scope->fctx, id, "no such object");
- return -1;
+ if (decl) {
+ id->type = decl->type;
+ return 0;
}
- if (!decl->type) {
- semantic_error(scope->fctx, id,
- "no type associated with object");
- return -1;
+ decl = file_scope_find_proc(scope, id);
+ if (decl) {
+ id->type = decl->type;
+ return 0;
}
- id->type = decl->type;
- return 0;
+ semantic_error(scope->fctx, id, "no such object");
+ return -1;
}
static int actualize_var(struct act_state *state,
struct scope *scope, struct ast_node *var)
{
assert(var && var->node_type == AST_VAR);
- struct ast_node *init = var->_var.init;
- struct ast_node *type = var->_var.type;
+ struct ast_node *init = AST_VAR(var).init;
+ struct ast_node *type = AST_VAR(var).type;
/* one of these must be defined, otherwise the parser fucked up */
assert(type || init);
@@ -881,11 +867,11 @@ static int actualize_var(struct act_state *state,
enum act_flags old_flags = state->flags; \
struct ast_node *old_trait = state->cur_trait;
-#define EXIT_ACT(r) \
- do { \
+#define EXIT_ACT(r) \
+ do { \
state->cur_trait = old_trait; \
- state->flags = old_flags; \
- return r; \
+ state->flags = old_flags; \
+ return r; \
} while (0);
static int actualize_type(struct act_state *state,
@@ -908,10 +894,12 @@ static int actualize_type(struct act_state *state,
* they're missing, void */
if (!AST_ID_TYPE(type).id) {
/* no ID means void */
- AST_ID_TYPE(type).id = gen_id(strdup("void"), NULL_LOC());
+ AST_ID_TYPE(type).id =
+ gen_id(strdup("void"), NULL_LOC());
}
- struct ast_node *exists = file_scope_find_type(scope, AST_ID_TYPE(type).id);
+ struct ast_node *exists = file_scope_find_type(scope, AST_ID_TYPE(
+ type).id);
if (!exists) {
semantic_error(scope->fctx, type, "no such type");
EXIT_ACT(-1);
@@ -945,26 +933,16 @@ static int actualize_type(struct act_state *state,
break;
}
- case AST_TYPE_ARR:
- /* TODO: expression should be expandable to integer constant */
+ case AST_TYPE_CONSTRUCT:
+ semantic_info(scope->fctx, type,
+ "constructs unimplemented, continuing with compilation to see what breaks");
break;
- case AST_TYPE_TYPEOF: {
- struct ast_node *expr = AST_TYPEOF_TYPE(type).expr;
- /* TODO: expressions in top-level type declarations should
- * probably be checked for, as we might not want to accidentally
- * actualize procedure calls? */
- if (actualize(state, scope, expr))
- EXIT_ACT(-1);
-
- /* TODO: for now just trust that the expression is not looped or
- * anything dumb like that, but I would feel better if I figure
- * out some check */
- assert(type->_type.next == NULL);
- /** @todo add in some 'from' field for this situation? */
- type->type = expr->type;
+ case AST_TYPE_ARR:
+ /* TODO: expression should be expandable to integer constant */
+ semantic_info(scope->fctx, type,
+ "arrays unimplemented, continuing with compilation to see what breaks");
break;
- }
case AST_TYPE_POINTER:
assert(AST_PTR_TYPE(type).base);
@@ -1019,7 +997,7 @@ static int actualize_empty(struct act_state *state,
return -1;
}
- node->type = gen_type(AST_TYPE_ID, void_id, NULL, NULL);
+ node->type = gen_type(AST_TYPE_ID, void_id, NULL, NULL_LOC());
if (!node->type) {
internal_error("couldn't allocate type for empty statement\n");
return -1;
@@ -1186,11 +1164,11 @@ static int init_struct(struct act_state *state, struct scope *scope,
break;
}
- if (!implements(0, scope, args->type, member->type)) {
+ if (!types_match(args->type, member->type)) {
char *astr = type_str(args->type);
char *mstr = type_str(member->type);
semantic_error(scope->fctx, args,
- "%s does not implement %s", astr, mstr);
+ "%s does not match %s", astr, mstr);
free(astr);
free(mstr);
ret = -1;
@@ -1351,7 +1329,7 @@ static int actualize_alias(struct act_state *state, struct scope *scope,
}
static int actualize_trait(struct act_state *state, struct scope *scope,
- struct ast_node *trait)
+ struct ast_node *trait)
{
assert(trait->node_type == AST_TRAIT);
ast_set_flags(trait, AST_FLAG_ACTUAL);
@@ -1565,8 +1543,9 @@ static int actualize_unop(struct act_state *state,
}
case AST_REF: {
- node->type = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL);
- node->type->_type.next = expr->type;
+ node->type = gen_type(AST_TYPE_POINTER, NULL, NULL,
+ NULL_LOC());
+ node->AST_TYPE(type).next = expr->type;
break;
}
@@ -1613,7 +1592,8 @@ static int actualize_struct(struct act_state *state,
/* cloning slightly odd, but I guess it's fine? */
struct ast_node *clone_id = clone_ast_node(node->_struct.id);
- node->type = gen_type(AST_TYPE_STRUCT, clone_id, NULL, NULL);
+ node->type =
+ gen_type(AST_TYPE_STRUCT, clone_id, NULL, NULL_LOC());
ast_set_flags(node, AST_FLAG_ACTUAL);
return 0;
@@ -1634,6 +1614,9 @@ static int has_members(struct ast_node *type)
if (AST_TYPE(type).kind == AST_TYPE_TRAIT)
return 1;
+ if (AST_TYPE(type).kind == AST_TYPE_CONSTRUCT)
+ return 1;
+
return 0;
}
@@ -1708,7 +1691,8 @@ static int actualize_assign(struct act_state *state, struct scope *scope,
/** @todo rvalue vs lvalue? */
if (!is_lvalue(to)) {
- semantic_error(scope->fctx, node, "rvalue used where lvalue required");
+ semantic_error(scope->fctx, node,
+ "rvalue used where lvalue required");
return -1;
}
@@ -1730,7 +1714,8 @@ static int actualize_fetch(struct act_state *state, struct scope *scope,
}
struct ast_node *id = fetch->_fetch.id;
- struct ast_node *def = file_scope_find_type(scope, AST_ID_TYPE(type).id);
+ struct ast_node *def =
+ file_scope_find_type(scope, AST_ID_TYPE(type).id);
assert(def);
struct ast_node *member = lookup_enum_member(def, id);
@@ -1806,7 +1791,8 @@ static int actualize(struct act_state *state, struct scope *scope,
if (!node->scope)
node->scope = scope;
- if (ast_flags(node, AST_FLAG_INIT) && !ast_flags(node, AST_FLAG_ACTUAL)) {
+ if (ast_flags(node,
+ AST_FLAG_INIT) && !ast_flags(node, AST_FLAG_ACTUAL)) {
semantic_error(scope->fctx, node, "detected dependency loop");
return -1;
}
@@ -1823,8 +1809,10 @@ 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_CONSTRUCT: ret |= actualize_macro_construct(state, scope, node); break;
- case AST_MACRO_EXPAND: ret |= actualize_macro_expand(state, scope, node); break;
+ case AST_MACRO_CONSTRUCT: ret |= actualize_macro_construct(state, scope,
+ node); break;
+ case AST_MACRO_EXPAND: ret |=
+ actualize_macro_expand(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;
@@ -1866,12 +1854,11 @@ static int actualize(struct act_state *state, struct scope *scope,
int actualize_main(struct scope *root)
{
struct ast_node *main_id = gen_id(strdup("main"), NULL_LOC());
- struct ast_node *main_call = gen_call(main_id, NULL);
struct act_state state = {0};
/* skip checking signature for now */
- struct ast_node *main = file_scope_resolve_call(root, main_call);
+ struct ast_node *main = file_scope_find_proc(root, main_id);
if (!main) {
/* libraries are not really compilable... */
error("no main");
diff --git a/src/asm.c b/src/asm.c
index e2076f5..8e49aa9 100644
--- a/src/asm.c
+++ b/src/asm.c
@@ -5,8 +5,10 @@
/* I guess using the zero register might be okay in some scenarios, but for now
* I'll just keep it an illegal register */
-#define ASSERT_REG(x) {assert(x->kind == LOC_REG); assert(x->reg > 0 && x->reg < 81);}
-#define ASSERT_MEM(x) {assert(x->kind == LOC_MEM); assert(x->reg > 0 && x->reg < 81);}
+#define ASSERT_REG(x) {assert(x->kind == LOC_REG); assert( \
+ x->reg > 0 && x->reg < 81);}
+#define ASSERT_MEM(x) {assert(x->kind == LOC_MEM); assert( \
+ x->reg > 0 && x->reg < 81);}
static int print_comment(struct op *op, FILE *f)
{
@@ -59,6 +61,7 @@ static int print_stt(struct op *op, FILE *f)
static int print_ret(struct op *op, FILE *f)
{
+ (void)op;
/* technically speaking ret takes a number of inputs, but they should be
* marshaled into registers with moves etc. so don't worry about them
* here */
@@ -84,16 +87,8 @@ static int print_op(struct op *op, FILE *f)
return ret;
}
-int print_asm(struct ops *ops, const char *output)
+int print_asm(struct ops *ops, FILE *f)
{
- FILE *f = fopen(output, "w");
-
- /* main should probably be mangled here as well */
- fprintf(f, "jal x21, main\n");
- /* tell simulator to turn off (very much temp) */
- fprintf(f, "li x1, 3\n");
- fprintf(f, "csrrw mpower, x0, x1\n");
-
int ret = 0;
struct op *op = ops->base;
while (op) {
@@ -103,6 +98,5 @@ int print_asm(struct ops *ops, const char *output)
op = op->next;
}
- fclose(f);
return ret;
}
diff --git a/src/ast.c b/src/ast.c
index 0fc7c8c..8660ae2 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -31,9 +31,9 @@ static void destroy_ast_node(struct ast_node *node)
switch (node->node_type) {
case AST_ID: free((void *)AST_ID(node).id); break;
case AST_CONST:
- if (AST_CONST(node).kind == AST_CONST_STRING)
- free((void *)AST_CONST(node).str);
- break;
+ if (AST_CONST(node).kind == AST_CONST_STRING)
+ free((void *)AST_CONST(node).str);
+ break;
default:
}
@@ -59,7 +59,9 @@ static struct ast_node *create_ast_node()
else if (ast_nodes.n >= ast_nodes.s) {
ast_nodes.s *= 2;
- ast_nodes.v = realloc(ast_nodes.v, ast_nodes.s * sizeof(struct ast_node *));
+ ast_nodes.v =
+ realloc(ast_nodes.v,
+ ast_nodes.s * sizeof(struct ast_node *));
}
struct ast_node *n = calloc(1, sizeof(struct ast_node));
@@ -69,11 +71,11 @@ static struct ast_node *create_ast_node()
/** @todo alloc should maybe also keep track of all nodes in a vector or
* something and mass free all AST at a time to keep my sanity */
-#define ALLOC_NODE(n, type) \
- struct ast_node *n = create_ast_node(); \
- if (!n) { \
- fprintf(stderr, "failed allocating" type "\n"); \
- return NULL; \
+#define ALLOC_NODE(n, type) \
+ struct ast_node *n = create_ast_node(); \
+ if (!n) { \
+ fprintf(stderr, "failed allocating" type "\n"); \
+ return NULL; \
}
#define DESTROY_LIST(x) \
@@ -86,7 +88,8 @@ static struct ast_node *create_ast_node()
} while ((prev = cur)); \
}
-struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc)
+struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx,
+ struct src_loc loc)
{
ALLOC_NODE(n, "arr_access");
n->node_type = AST_ARR_ACCESS;
@@ -96,7 +99,8 @@ struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, str
return n;
}
-struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args, struct src_loc loc)
+struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args,
+ struct src_loc loc)
{
ALLOC_NODE(n, "macro_expand");
n->node_type = AST_MACRO_EXPAND;
@@ -106,23 +110,9 @@ struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args, st
return n;
}
-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;
- AST_TYPE_CONSTRUCT(n).id = id;
- AST_TYPE_CONSTRUCT(n).params = params;
- AST_TYPE_CONSTRUCT(n).body = body;
- n->loc = loc;
- return n;
-}
-
struct ast_node *gen_type_expand(struct ast_node *id,
- struct ast_node *args,
- struct src_loc loc)
+ struct ast_node *args,
+ struct src_loc loc)
{
ALLOC_NODE(n, "type_expand");
n->node_type = AST_TYPE_EXPAND;
@@ -134,8 +124,8 @@ struct ast_node *gen_type_expand(struct ast_node *id,
struct ast_node *gen_binop(enum ast_binops op,
struct ast_node *left,
- struct ast_node *right,
- struct src_loc loc)
+ struct ast_node *right,
+ struct src_loc loc)
{
ALLOC_NODE(n, "binop");
n->node_type = AST_BINOP;
@@ -156,13 +146,14 @@ struct ast_node *gen_unop(enum ast_unops op, struct ast_node *expr)
return n;
}
-struct ast_node *gen_call(struct ast_node *id, struct ast_node *args)
+struct ast_node *gen_call(struct ast_node *expr, struct ast_node *args,
+ struct src_loc loc)
{
ALLOC_NODE(n, "call");
n->node_type = AST_CALL;
- n->_call.id = id;
- n->_call.args = args;
- n->loc = id->loc;
+ AST_CALL(n).expr = expr;
+ AST_CALL(n).args = args;
+ n->loc = loc;
return n;
}
@@ -251,12 +242,13 @@ struct ast_node *gen_goto(struct ast_node *label)
return n;
}
-struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id)
+struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id, struct src_loc loc)
{
ALLOC_NODE(n, "dot");
n->node_type = AST_DOT;
- n->_dot.expr = expr;
- n->_dot.id = id;
+ AST_DOT(n).expr = expr;
+ AST_DOT(n).id = id;
+ n->loc = loc;
return n;
}
@@ -289,8 +281,8 @@ struct ast_node *gen_fetch(struct ast_node *id, struct ast_node *type)
}
struct ast_node *gen_macro_construct(struct ast_node *id,
- struct ast_node *params,
- struct ast_node *body)
+ struct ast_node *params,
+ struct ast_node *body)
{
ALLOC_NODE(n, "macro_construct");
n->node_type = AST_MACRO_CONSTRUCT;
@@ -347,13 +339,15 @@ struct ast_node *gen_primitive(enum ast_primitive type, struct src_loc loc)
}
struct ast_node *gen_type(enum ast_type_kind kind,
- struct ast_node *t0,
+ struct ast_node *t0,
struct ast_node *t1,
- struct ast_node *t2)
+ struct src_loc loc)
{
ALLOC_NODE(n, "type");
n->node_type = AST_TYPE;
AST_TYPE(n).kind = kind;
+ n->loc = loc;
+
switch (kind) {
case AST_TYPE_TRAIT:
AST_TRAIT_TYPE(n).def = t0;
@@ -363,15 +357,16 @@ struct ast_node *gen_type(enum ast_type_kind kind,
AST_ID_TYPE(n).id = t0;
break;
+ case AST_TYPE_CONSTRUCT:
+ AST_CONSTRUCT_TYPE(n).id = t0;
+ AST_CONSTRUCT_TYPE(n).args = t1;
+ break;
+
case AST_TYPE_ARR:
AST_ARR_TYPE(n).size = t0;
AST_ARR_TYPE(n).base = t1;
break;
- case AST_TYPE_TYPEOF:
- AST_TYPEOF_TYPE(n).expr = t0;
- break;
-
case AST_TYPE_POINTER:
AST_PTR_TYPE(n).base = t0;
break;
@@ -438,17 +433,14 @@ void destroy_defer(struct ast_node *defer)
}
struct ast_node *gen_var(struct ast_node *id, struct ast_node *type,
- struct ast_node *init)
+ struct ast_node *init, struct src_loc loc)
{
ALLOC_NODE(n, "var");
n->node_type = AST_VAR;
- n->_var.id = id;
- n->_var.type = type;
- n->_var.init = init;
- if (id)
- n->loc = id->loc;
- else
- n->loc = type->loc;
+ AST_VAR(n).id = id;
+ AST_VAR(n).type = type;
+ AST_VAR(n).init = init;
+ n->loc = loc;
return n;
}
@@ -521,13 +513,15 @@ struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type)
return n;
}
-struct ast_node *gen_trait(struct ast_node *id, struct ast_node *body)
+struct ast_node *gen_trait(struct ast_node *id, struct ast_node *params,
+ struct ast_node *body, struct src_loc loc)
{
ALLOC_NODE(n, "trait");
n->node_type = AST_TRAIT;
- n->_trait.id = id;
- n->_trait.body = body;
- n->loc = id->loc;
+ AST_TRAIT(n).id = id;
+ AST_TRAIT(n).params = params;
+ AST_TRAIT(n).body = body;
+ n->loc = loc;
return n;
}
@@ -777,8 +771,8 @@ static void __dump_ast(int depth, struct ast_node *node)
dump_flags(node);
putchar('\n');
- dump_ast(depth + 1, node->_call.id);
- dump_ast(depth + 1, node->_call.args);
+ dump_ast(depth + 1, AST_CALL(node).expr);
+ dump_ast(depth + 1, AST_CALL(node).args);
dump(depth, "}\n");
break;
@@ -894,7 +888,8 @@ static void __dump_ast(int depth, struct ast_node *node)
switch (node->_type.kind) {
case AST_TYPE_PRIMITIVE:
- printf(" PRIMITIVE %s\n", primitive_str(AST_PRIMITIVE_TYPE(node).type));
+ printf(" PRIMITIVE %s\n",
+ primitive_str(AST_PRIMITIVE_TYPE(node).type));
break;
case AST_TYPE_TRAIT:
@@ -919,11 +914,6 @@ static void __dump_ast(int depth, struct ast_node *node)
dump_ast(depth + 1, AST_PTR_TYPE(node).base);
break;
- case AST_TYPE_TYPEOF:
- printf(" TYPEOF\n");
- dump_ast(depth + 1, AST_TYPEOF_TYPE(node).expr);
- break;
-
case AST_TYPE_STRUCT:
printf(" STRUCT\n");
/* oh yeah, struc is at least right now just an ID that
@@ -1073,7 +1063,8 @@ static void __dump_ast(int depth, struct ast_node *node)
dump(depth, "{CONST:");
dump_flags(node);
switch (node->_const.kind) {
- case AST_CONST_INTEGER: printf(" %lli", AST_CONST(node).integer);
+ case AST_CONST_INTEGER: printf(" %lli",
+ AST_CONST(node).integer);
break;
case AST_CONST_STRING: printf(" \"%s\"", AST_CONST(node).str);
break;
@@ -1131,24 +1122,16 @@ struct ast_node *clone_ast_node(struct ast_node *node)
switch (node->node_type) {
case AST_ARR_ACCESS:
new = gen_arr_access(
- clone_ast_node(AST_ARR_ACCESS(node).base),
- clone_ast_node(AST_ARR_ACCESS(node).idx),
- node->loc);
- break;
-
- case AST_TYPE_CONSTRUCT:
- new = gen_type_construct(
- clone_ast_node(AST_TYPE_CONSTRUCT(node).id),
- clone_ast_node(AST_TYPE_CONSTRUCT(node).params),
- clone_ast_node(AST_TYPE_CONSTRUCT(node).body),
- node->loc);
+ clone_ast_node(AST_ARR_ACCESS(node).base),
+ clone_ast_node(AST_ARR_ACCESS(node).idx),
+ node->loc);
break;
case AST_TYPE_EXPAND:
new = gen_type_expand(
- clone_ast_node(AST_TYPE_EXPAND(node).id),
- clone_ast_node(AST_TYPE_EXPAND(node).args),
- node->loc);
+ clone_ast_node(AST_TYPE_EXPAND(node).id),
+ clone_ast_node(AST_TYPE_EXPAND(node).args),
+ node->loc);
break;
case AST_FETCH:
@@ -1167,8 +1150,9 @@ struct ast_node *clone_ast_node(struct ast_node *node)
case AST_SIZEOF: new = gen_sizeof(clone_ast_node(node->_sizeof.expr));
break;
- case AST_DOT: new = gen_dot(clone_ast_node(node->_dot.expr),
- clone_ast_node(node->_dot.id));
+ case AST_DOT: new = gen_dot(clone_ast_node(AST_DOT(node).expr),
+ clone_ast_node(AST_DOT(node).id),
+ node->loc);
break;
case AST_AS: new = gen_as(clone_ast_node(node->_as.type));
@@ -1183,31 +1167,32 @@ struct ast_node *clone_ast_node(struct ast_node *node)
case AST_BINOP: new = gen_binop(node->binop.op,
clone_ast_node(node->binop.left),
clone_ast_node(node->binop.right),
- node->loc);
+ node->loc);
break;
case AST_UNOP: new = gen_unop(node->_unop.op,
clone_ast_node(node->_unop.expr));
break;
- case AST_CALL: new = gen_call(clone_ast_node(node->_call.id),
- clone_ast_node(node->_call.args));
+ case AST_CALL: new = gen_call(clone_ast_node(AST_CALL(node).expr),
+ clone_ast_node(AST_CALL(node).args),
+ node->loc);
break;
case AST_DEFER: new = gen_defer(clone_ast_node(node->_defer.expr));
break;
case AST_MACRO_CONSTRUCT: new = gen_macro_construct(
- clone_ast_node(AST_MACRO_CONSTRUCT(node).id),
- clone_ast_node(AST_MACRO_CONSTRUCT(node).params),
- clone_ast_node(AST_MACRO_CONSTRUCT(node).body));
- break;
+ clone_ast_node(AST_MACRO_CONSTRUCT(node).id),
+ clone_ast_node(AST_MACRO_CONSTRUCT(node).params),
+ clone_ast_node(AST_MACRO_CONSTRUCT(node).body));
+ break;
case AST_MACRO_EXPAND: new = gen_macro_expand(
- clone_ast_node(AST_MACRO_EXPAND(node).id),
- clone_ast_node(AST_MACRO_EXPAND(node).args),
- node->loc);
- break;
+ clone_ast_node(AST_MACRO_EXPAND(node).id),
+ clone_ast_node(AST_MACRO_EXPAND(node).args),
+ node->loc);
+ break;
case AST_CAST: new = gen_cast(clone_ast_node(node->_cast.expr),
clone_ast_node(node->_cast.type));
@@ -1216,26 +1201,14 @@ struct ast_node *clone_ast_node(struct ast_node *node)
case AST_PROC: new = gen_proc(clone_ast_node(node->_proc.id),
clone_ast_node(node->_proc.sign),
clone_ast_node(node->_proc.body),
- node->loc);
+ node->loc);
break;
- case AST_VAR: {
- /* I don't like how messy this is, should maybe try and come up
- * with something better */
- struct ast_node *type = NULL;
- if (node->type)
- type = clone_ast_node(node->type);
- else
- type = clone_ast_node(node->_var.type);
-
- new = gen_var(clone_ast_node(node->_var.id),
- type,
- clone_ast_node(node->_var.init));
- /* vars always reference the type associated with them? */
- if (node->type)
- new->type = type;
+ case AST_VAR: new = gen_var(clone_ast_node(AST_VAR(node).id),
+ clone_ast_node(AST_VAR(node).type),
+ clone_ast_node(AST_VAR(node).init),
+ node->loc);
break;
- }
case AST_FOR: new = gen_for(clone_ast_node(node->_for.pre),
clone_ast_node(node->_for.cond),
@@ -1258,60 +1231,55 @@ struct ast_node *clone_ast_node(struct ast_node *node)
* correctly... */
switch (node->_type.kind) {
case AST_TYPE_PRIMITIVE:
- new = gen_primitive(AST_PRIMITIVE_TYPE(node).type, node->loc);
+ new = gen_primitive(AST_PRIMITIVE_TYPE(
+ node).type, node->loc);
break;
case AST_TYPE_TRAIT:
new = gen_type(AST_TYPE_TRAIT,
AST_TRAIT_TYPE(node).def,
- NULL,
- NULL);
+ NULL,
+ node->loc);
break;
case AST_TYPE_ID:
new = gen_type(AST_TYPE_ID,
clone_ast_node(AST_ID_TYPE(node).id),
NULL,
- NULL);
+ node->loc);
break;
case AST_TYPE_ARR:
new = gen_type(AST_TYPE_ARR,
clone_ast_node(AST_ARR_TYPE(node).size),
clone_ast_node(AST_ARR_TYPE(node).base),
- NULL);
- break;
-
- case AST_TYPE_TYPEOF:
- new = gen_type(AST_TYPE_TYPEOF,
- clone_ast_node(AST_TYPEOF_TYPE(node).expr),
- NULL,
- NULL);
+ node->loc);
break;
case AST_TYPE_POINTER:
- new = gen_type(AST_TYPE_POINTER, AST_PTR_TYPE(node).base, NULL, NULL);
+ new = gen_type(AST_TYPE_POINTER, AST_PTR_TYPE(node).base,
+ NULL,
+ node->loc);
break;
case AST_TYPE_STRUCT:
new = gen_type(AST_TYPE_STRUCT,
clone_ast_node(AST_STRUCT_TYPE(node).def),
- NULL,
- NULL);
+ NULL, node->loc);
break;
case AST_TYPE_ENUM:
new = gen_type(AST_TYPE_ENUM,
clone_ast_node(AST_ENUM_TYPE(node).def),
- NULL,
- NULL);
+ NULL,
+ node->loc);
break;
case AST_TYPE_SIGN:
new = gen_type(AST_TYPE_SIGN,
clone_ast_node(AST_SIGN_TYPE(node).params),
clone_ast_node(AST_SIGN_TYPE(node).ret),
- NULL);
+ node->loc);
break;
}
@@ -1386,8 +1354,10 @@ struct ast_node *clone_ast_node(struct ast_node *node)
break;
case AST_TRAIT:
- new = gen_trait(clone_ast_node(node->_trait.id),
- clone_ast_node(node->_trait.body));
+ new = gen_trait(clone_ast_node(AST_TRAIT(node).id),
+ clone_ast_node(AST_TRAIT(node).params),
+ clone_ast_node(AST_TRAIT(node).body),
+ node->loc);
break;
case AST_IF:
@@ -1506,10 +1476,10 @@ static int identical_unop(int exact, struct ast_node *a, struct ast_node *b)
static int identical_call(int exact, struct ast_node *a, struct ast_node *b)
{
- if (!identical_ast_nodes(exact, a->_call.id, b->_call.id))
+ if (!identical_ast_nodes(exact, AST_CALL(a).expr, AST_CALL(b).expr))
return 0;
- if (!identical_ast_nodes(exact, a->_call.args, b->_call.args))
+ if (!identical_ast_nodes(exact, AST_CALL(a).args, AST_CALL(b).args))
return 0;
return 1;
@@ -1531,23 +1501,31 @@ 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_construct(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, AST_MACRO_CONSTRUCT(a).id, AST_MACRO_CONSTRUCT(b).id))
+ if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).id,
+ AST_MACRO_CONSTRUCT(b).id))
return 0;
- if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).params, AST_MACRO_CONSTRUCT(b).params))
+ if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).params,
+ AST_MACRO_CONSTRUCT(b).params))
return 0;
- return identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).body, AST_MACRO_CONSTRUCT(b).body);
+ return identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(
+ a).body,
+ AST_MACRO_CONSTRUCT(b).body);
}
-static int identical_macro_expand(int exact, struct ast_node *a, struct ast_node *b)
+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))
+ 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))
+ if (!identical_ast_nodes(exact, a->_macro_expand.args,
+ b->_macro_expand.args))
return 0;
return 1;
@@ -1627,29 +1605,27 @@ static int identical_type_id(int exact, struct ast_node *a, struct ast_node *b)
static int identical_type_arr(int exact, struct ast_node *a, struct ast_node *b)
{
- if (!identical_ast_nodes(exact, AST_ARR_TYPE(a).size, AST_ARR_TYPE(b).size))
+ if (!identical_ast_nodes(exact, AST_ARR_TYPE(a).size,
+ AST_ARR_TYPE(b).size))
return 0;
- return identical_ast_nodes(exact, AST_ARR_TYPE(a).base, AST_ARR_TYPE(b).base);
+ return identical_ast_nodes(exact, AST_ARR_TYPE(a).base, AST_ARR_TYPE(
+ b).base);
}
-static int identical_type_trait(int exact, struct ast_node *a, struct ast_node *b)
+static int identical_type_trait(int exact, struct ast_node *a,
+ struct ast_node *b)
{
- return identical_ast_nodes(exact, AST_TRAIT_TYPE(a).def, AST_TRAIT_TYPE(b).def);
+ return identical_ast_nodes(exact, AST_TRAIT_TYPE(a).def,
+ AST_TRAIT_TYPE(b).def);
}
-static int identical_type_primitive(int exact, struct ast_node *a, struct ast_node *b)
+static int identical_type_primitive(int exact, struct ast_node *a,
+ struct ast_node *b)
{
return AST_PRIMITIVE_TYPE(a).type == AST_PRIMITIVE_TYPE(b).type;
}
-static int identical_type_typeof(int exact, struct ast_node *a,
- struct ast_node *b)
-{
- return identical_ast_nodes(exact, AST_TYPEOF_TYPE(a).expr,
- AST_TYPEOF_TYPE(b).expr);
-}
-
static int identical_type_sign(int exact, struct ast_node *a,
struct ast_node *b)
{
@@ -1657,19 +1633,22 @@ static int identical_type_sign(int exact, struct ast_node *a,
AST_SIGN_TYPE(b).params))
return 0;
- return identical_ast_nodes(exact, AST_SIGN_TYPE(a).ret, AST_SIGN_TYPE(b).ret);
+ return identical_ast_nodes(exact, AST_SIGN_TYPE(a).ret, AST_SIGN_TYPE(
+ b).ret);
}
static int identical_type_struct(int exact, struct ast_node *a,
struct ast_node *b)
{
- return identical_ast_nodes(exact, AST_STRUCT_TYPE(a).def, AST_STRUCT_TYPE(b).def);
+ return identical_ast_nodes(exact, AST_STRUCT_TYPE(
+ a).def, AST_STRUCT_TYPE(b).def);
}
static int identical_type_enum(int exact, struct ast_node *a,
struct ast_node *b)
{
- return identical_ast_nodes(exact, AST_ENUM_TYPE(a).def, AST_ENUM_TYPE(b).def);
+ return identical_ast_nodes(exact, AST_ENUM_TYPE(a).def, AST_ENUM_TYPE(
+ b).def);
}
static int identical_type(int exact, struct ast_node *a, struct ast_node *b)
@@ -1679,12 +1658,12 @@ static int identical_type(int exact, struct ast_node *a, struct ast_node *b)
int ret = 0;
switch (a->_type.kind) {
- case AST_TYPE_PRIMITIVE: ret = identical_type_primitive(exact, a, b); break;
+ case AST_TYPE_PRIMITIVE: ret = identical_type_primitive(exact, a, b);
+ break;
case AST_TYPE_ENUM: ret = identical_type_enum(exact, a, b); break;
case AST_TYPE_TRAIT: ret = identical_type_trait(exact, a, b); break;
case AST_TYPE_ID: ret = identical_type_id(exact, a, b); break;
case AST_TYPE_ARR: ret = identical_type_arr(exact, a, b); break;
- case AST_TYPE_TYPEOF: ret = identical_type_typeof(exact, a, b); break;
case AST_TYPE_SIGN: ret = identical_type_sign(exact, a, b); break;
case AST_TYPE_STRUCT: ret = identical_type_struct(exact, a, b); break;
case AST_TYPE_POINTER: break;
@@ -1850,31 +1829,26 @@ 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, AST_TYPE_EXPAND(a).id, AST_TYPE_EXPAND(b).id))
- return 0;
-
- return identical_ast_nodes(exact, AST_TYPE_EXPAND(a).args, AST_TYPE_EXPAND(b).args);
-}
-
-static int identical_type_construct(int exact, struct ast_node *a, struct ast_node *b)
+static int identical_type_expand(int exact, struct ast_node *a,
+ struct ast_node *b)
{
- if (!identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).id, AST_TYPE_CONSTRUCT(b).id))
- return 0;
-
- if (!identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).params, AST_TYPE_CONSTRUCT(b).params))
+ if (!identical_ast_nodes(exact, AST_TYPE_EXPAND(a).id,
+ AST_TYPE_EXPAND(b).id))
return 0;
- return identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).body, AST_TYPE_CONSTRUCT(b).body);
+ return identical_ast_nodes(exact, AST_TYPE_EXPAND(
+ a).args, AST_TYPE_EXPAND(b).args);
}
-static int identical_arr_access(int exact, struct ast_node *a, struct ast_node *b)
+static int identical_arr_access(int exact, struct ast_node *a,
+ struct ast_node *b)
{
- if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).base, AST_ARR_ACCESS(b).base))
+ if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).base,
+ AST_ARR_ACCESS(b).base))
return 0;
- if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).idx, AST_ARR_ACCESS(b).idx))
+ if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).idx,
+ AST_ARR_ACCESS(b).idx))
return 0;
return 1;
@@ -1913,7 +1887,6 @@ 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_ASSIGN: ret = identical_assign(exact, a, b); break;
@@ -1928,7 +1901,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_CONSTRUCT: ret = identical_macro_construct(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;
@@ -2068,7 +2042,7 @@ static int call_on_alias(int (*call)(struct ast_node *,
}
static int call_on_trait(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
+ void *), struct ast_node *node, void *data)
{
int ret = 0;
ret |= call(node->_trait.id, data);
@@ -2134,7 +2108,7 @@ static int call_on_case(int (*call)(struct ast_node *,
}
static int call_on_type_trait(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
+ void *), struct ast_node *node, void *data)
{
int ret = 0;
ret |= call(AST_TRAIT_TYPE(node).def, data);
@@ -2153,12 +2127,6 @@ static int call_on_type_arr(int (*call)(struct ast_node *,
return call(AST_ARR_TYPE(node).size, data);
}
-static int call_on_type_typeof(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_TYPEOF_TYPE(node).expr, data);
-}
-
static int call_on_type_struct(int (*call)(struct ast_node *,
void *), struct ast_node *node, void *data)
{
@@ -2193,8 +2161,8 @@ static int call_on_type(int (*call)(struct ast_node *,
case AST_TYPE_TRAIT: ret = call_on_type_trait(call, node, data); break;
case AST_TYPE_ID: ret = call_on_type_id(call, node, data); break;
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_STRUCT: ret = call_on_type_struct(call, node, data); break;
+ case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data);
+ break;
case AST_TYPE_SIGN: ret = call_on_type_sign(call, node, data); break;
case AST_TYPE_POINTER: break;
case AST_TYPE_PRIMITIVE: break;
@@ -2234,13 +2202,13 @@ static int call_on_call(int (*call)(struct ast_node *,
void *), struct ast_node *node, void *data)
{
int ret = 0;
- ret |= call(node->_call.id, data);
- ret |= call(node->_call.args, data);
+ ret |= call(AST_CALL(node).expr, data);
+ ret |= call(AST_CALL(node).args, data);
return ret;
}
static int call_on_macro_construct(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
+ void *), struct ast_node *node, void *data)
{
int ret = 0;
ret |= call(AST_MACRO_CONSTRUCT(node).id, data);
@@ -2274,7 +2242,8 @@ static int call_on_fetch(int (*call)(struct ast_node *,
return ret;
}
-static int call_on_macro_expand(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);
@@ -2282,17 +2251,8 @@ static int call_on_macro_expand(int (*call)(struct ast_node *, void *), struct a
return ret;
}
-static int call_on_type_construct(int (*call)(struct ast_node *, void *), struct ast_node *type_construct, void *data)
-{
- int ret = 0;
- /* pretty verbose, hmm */
- ret |= call(AST_TYPE_CONSTRUCT(type_construct).id, data);
- ret |= call(AST_TYPE_CONSTRUCT(type_construct).params, data);
- ret |= call(AST_TYPE_CONSTRUCT(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)
+static int call_on_type_expand(int (*call)(struct ast_node *,
+ void *), struct ast_node *type_expand, void *data)
{
int ret = 0;
ret |= call(AST_TYPE_EXPAND(type_expand).id, data);
@@ -2316,8 +2276,8 @@ int ast_call_on(int (*call)(struct ast_node *,
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_TYPE_EXPAND: ret = call_on_type_expand(call, node, data);
+ break;
case AST_FETCH: ret = call_on_fetch(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;
@@ -2344,8 +2304,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_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_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_EMBED: break;
diff --git a/src/compiler.c b/src/compiler.c
index a096878..5845283 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -103,7 +103,6 @@ static int process(struct scope **parent, int public, const char *file)
scope->fctx.fbuf = buf;
scope->fctx.fname = strdup(file);
- scope->actuals = create_actuals();
scope_set_flags(scope, SCOPE_FILE);
if (*parent)
@@ -173,31 +172,21 @@ int compile(const char *input, const char *output) {
return ret;
}
- ret = actualize_main(root);
- if (ret) {
+ if ((ret = actualize_main(root))) {
destroy_scope(root);
destroy_ast_nodes();
error("compilation of %s stopped due to errors", input);
return ret;
}
- struct ops *ops = create_ops();
- ret = lower_ops(root, ops);
- destroy_scope(root);
- destroy_ast_nodes();
-
- if (ret) {
- destroy_ops(ops);
- error("compilation of %s stopped due to errors", input);
- return ret;
- }
-
- ret = alloc_regs(ops);
- if (ret) {
- destroy_ops(ops);
+ if ((ret = lower_ops(root, output))) {
+ destroy_scope(root);
+ destroy_ast_nodes();
error("compilation of %s stopped due to errors", input);
return ret;
}
- return print_asm(ops, output);
+ destroy_scope(root);
+ destroy_ast_nodes();
+ return 0;
}
diff --git a/src/debug.c b/src/debug.c
index b110b9b..2c873a2 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -225,14 +225,9 @@ static void _type_str(FILE *fp, struct ast_node *type)
break;
}
- case AST_TYPE_TYPEOF: {
- fprintf(fp, "(typeof)");
- break;
- }
-
case AST_TYPE_PRIMITIVE: {
fprintf(fp, "%s", primitive_str(AST_PRIMITIVE_TYPE(type).type));
- break;
+ break;
}
default:
@@ -271,11 +266,13 @@ char *type_str(struct ast_node *node)
*/
static void _call_str(FILE *f, struct ast_node *call)
{
- struct ast_node *id = call->_call.id;
- const char *id_str = id->_id.id;
- fprintf(f, "%s", id_str);
+ struct ast_node *expr = AST_CALL(call).expr;
+ if (expr->node_type == AST_ID) {
+ const char *id_str = AST_ID(expr).id;
+ fprintf(f, "%s", id_str);
+ }
- struct ast_node *args = call->_call.args;
+ struct ast_node *args = AST_CALL(call).args;
fprintf(f, "(");
while (args) {
diff --git a/src/lexer.l b/src/lexer.l
index a446c49..c819328 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -39,7 +39,7 @@ HEXF [+-]?0[xX][0-9a-fA-F]+([pP][+-]?[0-9]+)
DECF [+-]?[0-9]+[.]([eE]?[+-]?[0-9]+)?[fF]?
ID [_a-zA-Z][_a-zA-Z0-9]*
-APPLY {ID}[[:space:]]*!
+APPLY {ID}!
STRING \"(\\.|[^"\\])*\"
@@ -151,7 +151,6 @@ STRING \"(\\.|[^"\\])*\"
"struct" {return STRUCT;}
"typedef" {return TYPEDEF;}
"import" {return IMPORT;}
-"typeof" {return TYPEOF;}
"sizeof" {return SIZEOF;}
"embed" {return EMBED;}
"if" {return IF;}
diff --git a/src/ops.c b/src/ops.c
index 9562035..cc2650c 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -43,7 +43,7 @@ static size_t trivial_type_width(struct ast_node *type)
return 3;
}
-struct ops *create_ops()
+static struct ops *create_ops()
{
struct ops *ops = calloc(1, sizeof(struct ops));
@@ -56,15 +56,22 @@ struct ops *create_ops()
return ops;
}
-void destroy_ops(struct ops *ops)
+static void destroy_ops(struct ops *ops)
{
if (!ops)
return;
- struct op *base = ops->base;
- while (base) {
- struct op *prev = base;
- base = base->next;
+ struct op *op = ops->base;
+ while (op) {
+ struct op *prev = op;
+ op = op->next;
+
+ switch (prev->opcode) {
+ case OP_COMMENT: free((void *)prev->string); break;
+ case OP_LABEL: free((void *)prev->string); break;
+ default:
+ }
+
free(prev);
}
@@ -143,9 +150,9 @@ static int lower_var(struct ast_node *n, struct ops *ops)
* immediately run out of registers? */
struct ast_node *type = d->type;
if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE
- && AST_TYPE(type).kind != AST_TYPE_POINTER) {
+ && AST_TYPE(type).kind != AST_TYPE_POINTER) {
semantic_error(n->scope->fctx, n,
- "only trivial type lowering implemented");
+ "only trivial type lowering implemented");
return -1;
}
@@ -177,7 +184,8 @@ static int lower_cast(struct ast_node *n, struct ops *ops)
static int lower_const(struct ast_node *n, struct ops *ops)
{
if (AST_CONST(n).kind != AST_CONST_INTEGER) {
- semantic_error(n->scope->fctx, n, "only integer constant lowering implemented");
+ semantic_error(n->scope->fctx, n,
+ "only integer constant lowering implemented");
return -1;
}
@@ -209,7 +217,8 @@ static int lower_assign(struct ast_node *n, struct ops *ops)
static int lower_unop(struct ast_node *n, struct ops *ops)
{
if (AST_UNOP(n).op != AST_DEREF) {
- semantic_error(n->scope->fctx, n, "unop lowering not implemented");
+ semantic_error(n->scope->fctx, n,
+ "unop lowering not implemented");
return -1;
}
@@ -281,8 +290,8 @@ static int lower_op(struct ast_node *n, struct ops *ops)
case AST_ID: ret = lower_id(n, ops); break;
case AST_RETURN: ret = lower_ret(n, ops); break;
default:
- semantic_error(n->scope->fctx, n, "unimplemented lowering");
- return -1;
+ semantic_error(n->scope->fctx, n, "unimplemented lowering");
+ return -1;
}
if (ret)
@@ -353,21 +362,6 @@ static void print_ops(struct ops *ops)
}
}
-int lower_ops(struct scope *root, struct ops *ops)
-{
- for (struct actual *a = root->actuals; a; a = a->next) {
- assert(a->node);
- int ret = lower_op(a->node, ops);
- if (ret)
- return ret;
- }
-
- printf("Lowered ops before lifetime analysis:\n");
- print_ops(ops);
-
- return 0;
-}
-
static enum opcode st_opc(struct loc *loc)
{
switch (loc->width) {
@@ -395,8 +389,9 @@ static int realize_moves(struct ops *ops)
/* completely arbitrary and *will* have to be made better in the near
* future */
static const size_t tmp_reg = 9;
+ struct op *prev = NULL;
struct op *op = ops->base;
- for (; op; op = op->next) {
+ for (; op; prev = op, op = op->next) {
if (op->opcode != OP_MV) {
continue;
}
@@ -407,12 +402,18 @@ static int realize_moves(struct ops *ops)
assert(i->next == NULL);
if (i->kind == LOC_REG && o->kind == LOC_REG) {
- continue;
- } else if (i->kind == LOC_REG && o->kind == LOC_MEM) {
+ /* if move is between the same register, skip it */
+ if (i->reg == o->reg && prev)
+ prev->next = op->next;
+
+ }
+ else if (i->kind == LOC_REG && o->kind == LOC_MEM) {
op->opcode = st_opc(o);
- } else if (i->kind == LOC_MEM && o->kind == LOC_REG) {
+ }
+ else if (i->kind == LOC_MEM && o->kind == LOC_REG) {
op->opcode = ld_opc(i);
- } else if (i->kind == LOC_MEM && o->kind == LOC_MEM) {
+ }
+ else if (i->kind == LOC_MEM && o->kind == LOC_MEM) {
op->opcode = ld_opc(i);
/* our input/output are references, so call this before
* setting registers for our original operation. Also,
@@ -428,12 +429,59 @@ static int realize_moves(struct ops *ops)
return 0;
}
-int alloc_regs(struct ops *ops)
+static int alloc_regs(struct ops *ops)
{
/** @todo analyze lifetime, for now just convert moves to correct ldst
* etc. */
- int ret = realize_moves(ops);
- printf("Lowered ops after lifetime analysis:\n");
- print_ops(ops);
+ /** @todo lifetime analysis could be done by looping over all ops, and
+ * when we encounter a virtual register we haven't seen before, add it
+ * to a list. When we encounter it used again, extend its lifetime to
+ * wherever we are in the function. */
+ return realize_moves(ops);
+}
+
+int lower_ops(struct scope *root, const char *fname)
+{
+ FILE *f = fopen(fname, "w");
+
+ /* main should probably be mangled here as well */
+ fprintf(f, "jal x21, main\n");
+ /* tell simulator to turn off (very much temp) */
+ fprintf(f, "li x1, 3\n");
+ fprintf(f, "csrrw mpower, x0, x1\n");
+
+ /* this can potentially be parallelized in the future */
+ int ret = 0;
+ for (struct actual *a = root->actuals; a; a = a->next) {
+ assert(a->node);
+
+ struct ops *ops = create_ops();
+ if ((ret = lower_op(a->node, ops))) {
+ destroy_ops(ops);
+ break;
+ }
+
+ printf("Lowered ops before lifetime analysis:\n");
+ print_ops(ops);
+
+ if ((ret = alloc_regs(ops))) {
+ destroy_ops(ops);
+ break;
+ }
+
+ printf("Lowered ops after lifetime analysis:\n");
+ print_ops(ops);
+
+ if ((ret = print_asm(ops, f))) {
+ /* kind of silly as of now but eh */
+ destroy_ops(ops);
+ break;
+ }
+
+ destroy_ops(ops);
+ }
+
+ fclose(f);
return ret;
}
+
diff --git a/src/parser.y b/src/parser.y
index 4def5fd..1d09856 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -44,9 +44,6 @@
%token SEMICOLON ";"
%token COLON ":"
%token BANG "!"
-/* still not sure if this should be just typeof, would be slower to type I guess */
-%token TYPEOF "typeof"
-/* typeof does sort of fit into sizeof, hmmm */
%token SIZEOF "sizeof"
%token STAR "*"
%token DIV "/"
@@ -119,7 +116,7 @@
%left "<<" ">>"
%left "+" "-"
%left "*" "/" "%"
-%left "as" "sizeof" "typeof"
+%left "as" "sizeof"
%right "'" "!" "~"
%left "." "=>" "(" ")"
%left "::"
@@ -129,12 +126,12 @@
%nterm <node> while do_while statement statements body references macro
%nterm <node> exprs if for case cases switch const
%nterm <node> func_sign type var_decl var
-%nterm <node> var_init proc trait_elem trait_elems
+%nterm <node> var_init proc
%nterm <node> alias trait enum_val enums enum top unit id
-%nterm <node> embed param_decl members struct_elem
+%nterm <node> embed param_decl members
%nterm <node> top_if const_if const_for defer goto assign
%nterm <node> construct construct_args construct_arg
-%nterm <node> statelet apply
+%nterm <node> statelet apply types
%nterm <node> tagged_struct anon_struct tagged_union anon_union
@@ -143,11 +140,15 @@
%nterm <node> macro_expand type_expand
-%nterm <node> type_construct type_params type_param
+%nterm <node> type_params type_param
/* array stuff */
%nterm <node> arr arr_inits arr_init
+/* optional stuff */
+%nterm <node> opt_args opt_exprs proc_decl member opt_members
+%nterm <node> opt_statements opt_types
+
%{
/** Modifies the signature of yylex to fit our parser better. */
@@ -278,8 +279,12 @@ unop
| "*" expr { $$ = gen_unop(AST_DEREF, $2); }
arr_init
- : "=>" const_expr "..." const_expr "=" arg { $$ = gen_var($2, $4, $6); }
- | "=>" const_expr "=" arg { $$ = gen_var($2, NULL, $4); }
+ : "=>" const_expr "..." const_expr "=" arg {
+ $$ = gen_var($2, $4, $6, src_loc(@$));
+ }
+ | "=>" const_expr "=" arg {
+ $$ = gen_var($2, NULL, $4, src_loc(@$));
+ }
| arg
arr_inits
@@ -302,7 +307,7 @@ args
| arg
param_decl
- : type { $$ = gen_var(NULL, $1, NULL); }
+ : type { $$ = gen_var(NULL, $1, NULL, src_loc(@$)); }
| var_decl
decls
@@ -366,15 +371,15 @@ const_expr
/* TODO: concatenate multiple strings together? Or is that the lexer's job? */
expr
- : expr "." id { $$ = gen_dot($1, $3); }
+ : expr "." id { $$ = gen_dot($1, $3, src_loc(@$)); }
| "..." id { $$ = $2; }
| INT { $$ = gen_int($1); }
| STRING {
$$ = gen_string(clone_string($1));
}
| "(" expr ")" { $$ = $2; }
- | expr "(" args ")" { $$ = gen_call($1, $3); }
- | expr "(" ")" { $$ = gen_call($1, NULL); }
+ | expr "(" args ")" { $$ = gen_call($1, $3, src_loc(@$)); }
+ | expr "(" ")" { $$ = gen_call($1, NULL, src_loc(@$)); }
| expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); /** @todo add arr access */}
| "(" var_init ")" { $$ = $2; }
| "sizeof" expr { $$ = gen_sizeof($2); }
@@ -404,16 +409,14 @@ goto
statelet
: "return" args { $$ = gen_return($2); }
| "return" { $$ = gen_return(NULL); }
- | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(yylloc)); }
- | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(yylloc)); }
+ | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(@$)); }
+ | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(@$)); }
| trait
| import
| alias
| exprs
- | const
| goto
| var
- | ";" { $$ = gen_empty(); }
| error {
/* TODO: figure out how to destroy any and all possible ast nodes we
* may have generated up until the error */
@@ -439,8 +442,10 @@ statement
| for
| defer
| if
+ | const
| enum
| macro
+ | ";" { $$ = gen_empty(); }
| id ":" { $$ = gen_label($1); }
statements
@@ -448,10 +453,12 @@ statements
| statement
| statelet
+opt_statements
+ : statements
+ | {$$ = NULL;}
body
- : "{" statements "}" { $$ = gen_block($2); }
- | "{" "}" { $$ = gen_block(gen_empty()); }
+ : "{" opt_statements "}" { $$ = gen_block($2); }
references
: id "," references { $$ = $1; $$->next = $3; }
@@ -481,7 +488,7 @@ exprs
construct_arg
: "." id "=" expr {
- $$ = gen_var($2, NULL, $4);
+ $$ = gen_var($2, NULL, $4, src_loc(@$));
ast_set_flags($$, AST_FLAG_MEMBER);
}
@@ -497,9 +504,17 @@ if
| "if" expr body "else" body { $$ = gen_if($2, $3, $5); }
| "if" expr body "else" if { $$ = gen_if($2, $3, $5); }
-/* todo how about leaving out some parts? */
+opt_args
+ : args
+ | {$$ = NULL;}
+
+opt_exprs
+ : exprs
+ | {$$ = NULL;}
+
for
- : "for" arg ";" expr ";" expr body { $$ = gen_for($2, $4, $6, $7); }
+ : "for" opt_args ";" opt_exprs ";" exprs body { $$ = gen_for($2, $4, $6, $7); }
+ | "for" opt_args ";" opt_exprs ";" body {}
case
: "case" const_expr ":" statements {
@@ -509,6 +524,8 @@ case
$$ = gen_case($2, $4);
}
| "default" ":" statements {
+ /* default seems like it would be useful as something other than
+ * a keyword... */
$$ = gen_case(NULL, $3);
}
@@ -550,29 +567,26 @@ const
func_sign
: "(" decls "=>" type ")" {
- $$ = gen_type(AST_TYPE_SIGN, $2, $4, NULL);
+ $$ = gen_type(AST_TYPE_SIGN, $2, $4, src_loc(@$));
}
- | "(" decls ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, NULL); }
- | "(" decls "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, NULL); }
- | "(" "=>" type ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, $3, NULL); }
- | "(" "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, NULL); }
- | "(" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, NULL); }
+ | "(" decls ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, src_loc(@$)); }
+ | "(" decls "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, src_loc(@$)); }
+ | "(" "=>" type ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, $3, src_loc(@$)); }
+ | "(" "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, src_loc(@$)); }
+ | "(" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, src_loc(@$)); }
type
- : id { $$ = gen_type(AST_TYPE_ID, $1, NULL, NULL); }
+ : id { $$ = gen_type(AST_TYPE_ID, $1, NULL, src_loc(@$)); }
| "^" func_sign {
/* still not entirely sold on this signature, but it's not terrible I
* guess */
- $$ = gen_type(AST_TYPE_POINTER, $2, NULL, NULL);
+ $$ = gen_type(AST_TYPE_POINTER, $2, NULL, src_loc(@$));
}
| "*" type {
- $$ = gen_type(AST_TYPE_POINTER, $2, NULL, NULL);
+ $$ = gen_type(AST_TYPE_POINTER, $2, NULL, src_loc(@$));
}
| "[" const_expr "]" type {
- $$ = gen_type(AST_TYPE_ARR, $2, $4, NULL);
- }
- | "typeof" expr {
- $$ = gen_type(AST_TYPE_TYPEOF, $2, NULL, NULL);
+ $$ = gen_type(AST_TYPE_ARR, $2, $4, src_loc(@$));
}
| "const" type {
$$ = $2;
@@ -581,32 +595,37 @@ type
$$ = $2; ast_set_flags($$, AST_FLAG_MUTABLE);
}
| anon_struct
- /* syntactic sugar for struct {union {...} } */
| anon_union
- /* syntactic sugar for anon_struct */
- | type_expand
+ | apply "[" opt_types "]" {
+ $$ = gen_type(AST_TYPE_CONSTRUCT, $1, $3, src_loc(@$));
+ }
types
- : type "," types
+ : type "," types { $$ = $1; $$->next = $3; }
| type
-/* vec![int] is effectively struct {vec![int]} */
+opt_types
+ : types
+ | { $$ = NULL; }
+
type_expand
- : apply "[" types "]"
- /* legal, but weird */
- | apply "[" "]"
+ : apply "[" opt_types "]" { $$ = gen_type_expand($1, $3, src_loc(@$)); }
var_decl
- : type id { $$ = gen_var($2, $1, NULL); }
+ : type id { $$ = gen_var($2, $1, NULL, src_loc(@$)); }
var_init
: var_decl "=" arg { $$ = $1; $$->_var.init = $3; }
- | "const" id "=" arg { $$ = gen_var($2, NULL, $4); }
+ | "const" id "=" arg { $$ = gen_var($2, NULL, $4, src_loc(@$)); }
| "mut" id "=" arg {
- $$ = gen_var($2, NULL, $4);
+ $$ = gen_var($2, NULL, $4, src_loc(@$));
ast_set_flags($$, AST_FLAG_MUTABLE);
}
+proc_decl
+ : id func_sign {
+ $$ = gen_proc($1, $2, NULL, src_loc(@$));
+ }
proc
: id func_sign body {
$$ = gen_proc($1, $2, $3, src_loc(@$));
@@ -619,74 +638,55 @@ proc
ast_set_flags($$, AST_FLAG_EXTERN);
}
-struct_elem
- : var_decl
- | type_expand
+member
+ : var_decl ";"
+ | type_expand ";"
+ | proc_decl ";"
+ | id ";"
+ | proc
;
members
- : struct_elem ";" members { $$ = $1; $1->next = $3; }
- | struct_elem ";"
+ : member members { $$ = $1; $1->next = $2; }
+ | member
+
+opt_members
+ : members
+ | {$$ = NULL;}
tagged_union
- : "union" id "{" members "}" {
+ : "union" id "{" opt_members "}" {
/* essentially struct {union{members}} */
$$ = gen_struct($2, NULL, $4);
}
anon_union
- : "union" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); }
+ : "union" "{" opt_members "}" { $$ = gen_struct(NULL, NULL, $3); }
macro_expand
- : apply "(" ")" { $$ = gen_macro_expand($1, NULL, src_loc(@$)); }
- | apply "(" args ")" { $$ = gen_macro_expand($1, $3, src_loc(@$)); }
+ : apply "(" opt_args ")" { $$ = gen_macro_expand($1, $3, src_loc(@$)); }
tagged_struct
- : "struct" id "{" members "}" {
+ : "typedef" id "{" opt_members "}" {
$$ = gen_struct($2, NULL, $4);
}
anon_struct
- : "struct" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); }
-
-trait_elem
- : id /* trait */
- | id func_sign { $$ = gen_proc($1, $2, NULL, src_loc(@$)); } /* proc */
- | var_decl /* member */
- | type_expand /* type construction */
-
-trait_elems
- : trait_elem ";" trait_elems { $$ = $1; $1->next = $3; }
- | trait_elem ";"
- | trait_elem
+ : "typedef" "{" opt_members "}" { $$ = gen_struct(NULL, NULL, $3); }
alias
: "typedef" id type { $$ = gen_alias($2, $3); }
-/* we'll parse the arg list later in the AST and check that each node is of some
- * specific type */
-trait
- : "typedef" id "{" trait_elems "}" {
- $$ = gen_trait($2, $4);
- }
- | "typedef" id "{" "}" {
- /* should match anything, but doesn't implement anything */
- $$ = gen_trait($2, NULL);
- }
-
type_param
- : id id { $$ = gen_var($2, $1, NULL); }
+ : id id { $$ = gen_var($2, $1, NULL, src_loc(@$)); }
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(@$));
+trait
+ : "typedef" id "[" type_params "]" "{" opt_members "}" {
+ $$ = gen_trait($2, $4, $7, src_loc(@$));
}
enum_val
@@ -726,7 +726,6 @@ top
| proc
| tagged_struct
| tagged_union
- | type_construct
| macro { $$ = $1; }
| top_if { $$ = $1; ast_set_flags($$, AST_FLAG_CONST); }
| import { $$ = $1; }
@@ -735,7 +734,6 @@ 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); }
diff --git a/src/scope.c b/src/scope.c
index 6c94aec..329b5f1 100644
--- a/src/scope.c
+++ b/src/scope.c
@@ -17,158 +17,6 @@
#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 struct param_node *find_matching_param(struct resolve_node *node,
- struct ast_node *type)
-{
- struct param_node *param = node->params;
- while (param) {
- if (types_match(type, param->type))
- return param;
-
- param = param->next;
- }
-
- return NULL;
-}
-
-static int traits_resolve(struct ast_node *arg_type, struct ast_node *param_type)
-{
- /** @todo are more checks required? arg_type should already be in
- * `as`-form*/
- return AST_TRAIT_TYPE(arg_type).def == AST_TRAIT_TYPE(param_type).def;
-}
-
-static int types_resolve(struct ast_node *arg_type, struct ast_node *param_type)
-{
- /* untyped resolves all */
- if (!param_type)
- return 1;
-
- /* if arg is specifying to be matches as `as`, then do it */
- if (AST_TYPE(arg_type).as)
- return types_resolve(AST_TYPE(arg_type).as, param_type);
-
- if (AST_TYPE(param_type).kind == AST_TYPE_TRAIT)
- return traits_resolve(arg_type, param_type);
-
- /* typeof is matched later */
- if (AST_TYPE(param_type).kind == AST_TYPE_TYPEOF)
- return 1;
-
- return types_match(arg_type, param_type);
-}
-
-static struct param_node *find_resolving_param(struct resolve_node *node,
- struct ast_node *type)
-{
- struct param_node *param = node->params;
- while (param) {
- if (types_resolve(type, param->type))
- return param;
-
- param = param->next;
- }
-
- return NULL;
-}
-
-static struct resolve_node *insert_resolve(struct resolve_node *node,
- struct ast_node *type)
-{
- struct param_node *new = calloc(1, sizeof(struct param_node));
- if (!new) {
- return NULL;
- }
- new->type = type;
-
- struct resolve_node *next = calloc(1, sizeof(struct resolve_node));
- if (!next) {
- free(new);
- return NULL;
- }
- new->resolved = next;
-
- if (!node->params) {
- node->params = new;
- return next;
- }
-
- new->next = node->params;
- node->params = new;
-
- return next;
-}
-
-static int add_next_resolve(struct scope *scope, struct ast_node *resolve,
- struct resolve_node *node, struct ast_node *params)
-{
- assert(node);
-
- /* 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->resolved) {
- semantic_error(scope->fctx, resolve, "ambiguous resolution");
- semantic_error(scope->fctx, node->resolved, "matches here");
- return -1;
- }
-
- node->resolved = resolve;
- return 0;
- }
-
- assert(params->node_type == AST_VAR);
- struct param_node *match = find_matching_param(node, params->type);
- if (match)
- return add_next_resolve(scope, resolve,
- match->resolved,
- params->next);
-
- /** @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;
-
- return add_next_resolve(scope, resolve, next, params->next);
-}
-
-static int add_resolve(struct scope *scope, struct resolve *resolve,
- struct ast_node *proc)
-{
- struct ast_node *sign = AST_PROC(proc).sign;
- struct ast_node *params = AST_SIGN_TYPE(sign).params;
- return add_next_resolve(scope, proc, resolve->root, params);
-}
-
-static struct ast_node *resolve(struct scope *scope,
- struct resolve_node *node,
- struct ast_node *args)
-{
- assert(node);
- /* check for no parameters case */
- if (!args) {
- if (node->resolved)
- return node->resolved;
-
- return NULL;
- }
-
- struct param_node *found = find_resolving_param(node, args->type);
- if (found)
- return resolve(scope, found->resolved, args->next);
-
- return NULL;
-}
-
struct scope *create_scope()
{
/* if I ever try making the parser multithreaded, this should be atomic. */
@@ -184,17 +32,6 @@ struct scope *create_scope()
return scope;
}
-struct actual *create_actuals()
-{
- struct actual *actuals = calloc(1, sizeof(struct actual));
- if (!actuals) {
- internal_error("ran out of memory allocating actuals");
- return NULL;
- }
-
- return actuals;
-}
-
void destroy_visible(struct scope *scope, struct visible *visible)
{
struct visible *prev = visible, *cur;
@@ -206,63 +43,16 @@ void destroy_visible(struct scope *scope, struct visible *visible)
} while ((prev = cur));
}
-void destroy_actuals(struct actual *actuals)
-{
- struct actual *prev = actuals, *cur;
- if (prev)
- do {
- cur = prev->next;
- free(prev);
- } while ((prev = cur));
-}
-
-void destroy_resolve_node(struct resolve_node *);
-
-void destroy_param_nodes(struct param_node *param)
-{
- if (!param)
- return;
-
- destroy_resolve_node(param->resolved);
- destroy_param_nodes(param->next);
- free(param);
-}
-
-void destroy_resolve_node(struct resolve_node *resolve)
-{
- if (!resolve)
- return;
-
- destroy_param_nodes(resolve->params);
- free(resolve);
-}
-
-void destroy_resolve(struct resolve *resolve)
-{
- struct resolve *prev = resolve, *cur;
- if (prev)
- do {
- cur = prev->next;
- destroy_resolve_node(prev->root);
- free(prev);
- } while ((prev = cur));
-}
-
void destroy_scope(struct scope *scope)
{
if (!scope)
return;
if (scope_flags(scope, SCOPE_FILE)) {
- destroy_actuals(scope->actuals);
free((void *)scope->fctx.fbuf);
free((void *)scope->fctx.fname);
}
- 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->types);
@@ -297,7 +87,8 @@ static struct visible *create_visible(struct ast_node *id,
return visible;
}
-struct visible *create_type(struct scope *scope, struct ast_node *id, struct ast_node *type)
+struct visible *create_type(struct scope *scope, struct ast_node *id,
+ struct ast_node *type)
{
struct visible *n = create_visible(id, type);
if (!n)
@@ -305,10 +96,12 @@ struct visible *create_type(struct scope *scope, struct ast_node *id, struct ast
n->next = scope->types;
scope->types = n;
+
return n;
}
-struct visible *create_var(struct scope *scope, struct ast_node *id, struct ast_node *var)
+struct visible *create_var(struct scope *scope, struct ast_node *id,
+ struct ast_node *var)
{
struct visible *n = create_visible(id, var);
if (!n)
@@ -316,6 +109,33 @@ struct visible *create_var(struct scope *scope, struct ast_node *id, struct ast_
n->next = scope->vars;
scope->vars = n;
+
+ return n;
+}
+
+struct visible *create_macro(struct scope *scope, struct ast_node *id,
+ struct ast_node *macro)
+{
+ struct visible *n = create_visible(id, macro);
+ if (!n)
+ return NULL;
+
+ n->next = scope->macros;
+ scope->macros = n;
+
+ return n;
+}
+
+struct visible *create_proc(struct scope *scope, struct ast_node *id,
+ struct ast_node *proc)
+{
+ struct visible *n = create_visible(id, proc);
+ if (!n)
+ return NULL;
+
+ n->next = scope->procs;
+ scope->procs = n;
+
return n;
}
@@ -329,13 +149,15 @@ int scope_add_var(struct scope *scope, struct ast_node *var)
}
create_var(scope, AST_VAR(var).id, var);
- if (scope_flags(scope, SCOPE_FILE) && ast_flags(var, AST_FLAG_PUBLIC))
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(var, AST_FLAG_PUBLIC))
return scope_add_var(scope->parent, var);
return 0;
}
-int scope_add_type(struct scope *scope, struct ast_node *id, struct ast_node *type)
+int scope_add_type(struct scope *scope, struct ast_node *id,
+ struct ast_node *type)
{
struct ast_node *exists = file_scope_find_type(scope, id);
if (exists) {
@@ -345,333 +167,74 @@ int scope_add_type(struct scope *scope, struct ast_node *id, struct ast_node *ty
}
create_type(scope, id, type);
- if (scope_flags(scope, SCOPE_FILE) && ast_flags(type, AST_FLAG_PUBLIC))
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(type, AST_FLAG_PUBLIC))
return scope_add_type(scope->parent, id, type);
return 0;
}
-static void remove_implementation(struct ast_node *trait,
- struct ast_node *type)
-{
- assert(trait->node_type == AST_TRAIT);
- struct trait_implemented *prev = trait->_trait.impl_by, *cur;
- if (prev)
- do {
- cur = prev->next;
- if (!cur)
- break;
-
- if (identical_ast_nodes(0, cur->type, type)) {
- struct trait_implemented *next = cur->next;
- prev->next = next;
- free(cur);
- return;
- }
- } while ((prev = cur));
-}
-
-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)
-{
- (void)(flags);
- (void)(scope);
- (void)(arg_type);
- (void)(param_type);
- assert(proc->node_type == AST_PROC);
- /** @todo implement */
- return 0;
-}
-
-static int implements_var(enum match_flags flags, struct scope *scope,
- struct ast_node *arg_type,
- struct ast_node *param_type, struct ast_node *var)
-{
- (void)(flags);
- (void)(scope);
- (void)(arg_type);
- (void)(param_type);
- assert(var->node_type == AST_VAR);
- /** @todo implement */
- return 0;
-}
-
-static int implements_trait(enum match_flags flags, struct scope *scope,
- struct ast_node *arg_type,
- struct ast_node *param_type)
-{
- assert(AST_TYPE(param_type).kind == AST_TYPE_TRAIT);
- struct ast_node *trait = AST_TRAIT_TYPE(param_type).def;
- struct ast_node *body = AST_TRAIT(trait).body;
-
- /* if the body is empty, match */
- struct ast_node *elem = body;
- if (!elem)
- return 1;
-
- /* this is somewhat ugly, hmmm */
- do {
- if (elem->node_type == AST_VAR) {
- if (implements_var(flags, scope, arg_type,
- param_type,
- elem))
- continue;
-
- char *type = type_str(arg_type);
- struct ast_node *id = elem->_proc.id;
- semantic_error(scope->fctx, elem,
- "%s does not have member %s",
- type, id->_id.id);
- free(type);
- goto not_implemented;
- }
-
- else if (elem->node_type == AST_PROC) {
- if (implements_proc(flags, scope, arg_type,
- param_type,
- elem))
- continue;
-
- char *type = type_str(arg_type);
- struct ast_node *id = elem->_proc.id;
- semantic_error(scope->fctx, elem,
- "%s does not implement %s",
- type, id->_id.id);
- free(type);
- goto not_implemented;
- }
-
- else {
- semantic_error(scope->fctx, elem,
- "illegal trait element");
- goto not_implemented;
- }
- } while ((elem = elem->next));
-
- return 1;
-
-not_implemented:
- remove_implementation(trait, arg_type);
- return 0;
-}
-
-static int implements_typeof(enum match_flags flags, struct scope *scope,
- struct ast_node *arg_type,
- struct ast_node *param_type)
-{
- internal_error("typeof implementation unimplemented");
- return implements(flags, scope, arg_type, param_type);
-}
-
-int implements(enum match_flags flags, struct scope *scope,
- struct ast_node *arg_type, struct ast_node *param_type)
-{
- /* if both types are null, they are uninitialized and we'll assume they
- * don't implement eachother. This essentially means that during the
- * analysis phase everything is added to the procs */
- if (!arg_type && !param_type)
- return 0;
-
- /* slight hack: macro arguments also don't have a type, so they will
- * also 'implement' type */
- if (!param_type)
- return 1;
-
- /* at this point, we should always have some type for the argument */
- assert(arg_type);
-
- if (AST_TYPE(param_type).kind == AST_TYPE_TYPEOF)
- return implements_typeof(flags, scope, arg_type, param_type);
-
- if (AST_TYPE(param_type).kind == AST_TYPE_TRAIT)
- return implements_trait(flags, scope, arg_type, param_type);
-
- return types_match(arg_type, param_type);
-}
-
-static int match_actual_params(enum match_flags flags, struct scope *scope,
- struct ast_node *args, struct ast_node *params)
-{
- /** @todo essentially just iterate over the parameters, right? */
- return 0;
-}
-
-static struct ast_node *match_resolve(struct scope *scope,
- struct resolve *s,
- struct ast_node *id,
- struct ast_node *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);
-
- 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);
-}
-
-
-static 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);
-}
-
-static 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, AST_MACRO_CONSTRUCT(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(AST_MACRO_CONSTRUCT(macro).id);
- resolve->next = scope->macro_resolve;
- scope->macro_resolve = resolve;
-
- return add_resolve(scope, resolve, macro);
-}
-
int scope_add_macro(struct scope *scope, struct ast_node *macro)
{
assert(macro->node_type == AST_MACRO_CONSTRUCT);
- struct ast_node *id = AST_MACRO_CONSTRUCT(macro).id;
- struct ast_node *params = AST_MACRO_CONSTRUCT(macro).params;
-
- struct ast_node *exists = match_macro(scope, id, params);;
+ struct ast_node *exists = file_scope_find_macro(scope, AST_MACRO_CONSTRUCT(
+ macro).id);
if (exists) {
semantic_error(scope->fctx, macro, "macro redefined");
semantic_info(scope->fctx, exists, "previously here");
return -1;
}
- add_macro_resolve(scope, macro);
-
- if (scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC))
+ /* always add to scope, do resolve checking later */
+ create_macro(scope, AST_MACRO_CONSTRUCT(macro).id, macro);
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC))
return scope_add_macro(scope->parent, macro);
return 0;
}
-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_TYPE_CONSTRUCT(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_TYPE_CONSTRUCT(type_construct).id);
- resolve->next = scope->type_construct_resolve;
- scope->type_construct_resolve = resolve;
-
- return add_resolve(scope, resolve, type_construct);
-}
-
int scope_add_proc(struct scope *scope, struct ast_node *proc)
{
assert(proc->node_type == AST_PROC);
-
- struct ast_node *id = AST_PROC(proc).id;
- struct ast_node *sign = AST_PROC(proc).sign;
- struct ast_node *params = AST_SIGN_TYPE(sign).params;
-
- struct ast_node *exists = match_proc(scope, id, params);
-
+ struct ast_node *exists =
+ file_scope_find_proc(scope, AST_PROC(proc).id);
if (exists) {
semantic_error(scope->fctx, proc, "proc redefined");
semantic_info(scope->fctx, exists, "previously here");
return -1;
}
-
- add_proc_resolve(scope, proc);
-
- if (scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC))
+ /* always add to scope, do resolve checking later */
+ create_proc(scope, AST_PROC(proc).id, proc);
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC))
return scope_add_proc(scope->parent, proc);
return 0;
}
-int scope_add_type_construct(struct scope *scope, struct ast_node *type_construct)
+int scope_add_trait(struct scope *scope, struct ast_node *trait)
{
- assert(type_construct->node_type == AST_TYPE_CONSTRUCT);
-
- struct ast_node *id = AST_TYPE_CONSTRUCT(type_construct).id;
- struct ast_node *params = AST_TYPE_CONSTRUCT(type_construct).params;
+ assert(trait->node_type == AST_TRAIT);
- struct ast_node *exists = match_type_construct(scope, id, params);
+ struct ast_node *id = AST_TRAIT(trait).id;
+ struct ast_node *exists = file_scope_find_type(scope, id);
if (exists) {
- semantic_error(scope->fctx, type_construct, "type construct redefined");
+ semantic_error(scope->fctx, trait, "type redefined");
semantic_info(scope->fctx, exists, "previously here");
return -1;
}
- add_type_construct_resolve(scope, type_construct);
-
- if (scope_flags(scope, SCOPE_FILE) && ast_flags(type_construct, AST_FLAG_PUBLIC))
- return scope_add_type_construct(scope->parent, type_construct);
+ create_type(scope, id, trait);
+ if (scope->parent &&
+ scope_flags(scope, SCOPE_FILE) && ast_flags(trait, AST_FLAG_PUBLIC))
+ return scope_add_trait(scope->parent, trait);
return 0;
}
-static struct ast_node *scope_find_visible(struct visible *v, struct ast_node *id)
+static struct ast_node *scope_find_visible(struct visible *v,
+ struct ast_node *id)
{
if (!v)
return NULL;
@@ -708,134 +271,71 @@ struct ast_node *file_scope_find_type(struct scope *scope,
return NULL;
}
-struct ast_node *scope_find_var(struct scope *scope, struct ast_node *var)
+struct ast_node *scope_find_macro(struct scope *scope, struct ast_node *macro)
{
- return scope_find_visible(scope->vars, var);
+ return scope_find_visible(scope->macros, macro);
}
-struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *var)
+struct ast_node *file_scope_find_macro(struct scope *scope,
+ struct ast_node *macro)
{
- assert(var->node_type == AST_ID);
+ assert(macro->node_type == AST_ID);
if (!scope)
return NULL;
- struct ast_node *found = scope_find_var(scope, var);
+ struct ast_node *found = scope_find_macro(scope, macro);
if (found)
return found;
if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_find_var(scope->parent, var);
+ return file_scope_find_macro(scope->parent, macro);
return NULL;
}
-struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *macro)
-{
- 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);
-}
-
-struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call)
+struct ast_node *scope_find_proc(struct scope *scope, struct ast_node *proc)
{
- assert(call->node_type == AST_CALL);
- struct ast_node *id = call->_call.id;
- struct ast_node *args = call->_call.args;
- return match_proc(scope, id, args);
+ return scope_find_visible(scope->procs, proc);
}
-struct ast_node *scope_resolve_actual(struct scope *scope,
- struct ast_node *call)
+struct ast_node *file_scope_find_proc(struct scope *scope,
+ struct ast_node *proc)
{
- assert(call->node_type == AST_CALL);
- struct actual *prev = scope->actuals, *cur;
-
- if (prev)
- do {
- cur = prev->next;
- struct ast_node *actual = prev->node;
- if (!actual)
- continue;
-
- if (!identical_ast_nodes(0, actual->_proc.id,
- call->_call.id))
- continue;
-
- assert(!ast_flags(actual, AST_FLAG_VARIADIC));
- /* could also check that arguments aren't traits */
- struct ast_node *args = AST_CALL(call).args;
- struct ast_node *sign = AST_PROC(actual).sign;
- struct ast_node *params = AST_SIGN_TYPE(sign).params;
- if (match_actual_params(0, scope, args, params))
- return actual;
-
- } while ((prev = cur));
-
- return NULL;
-}
+ assert(proc->node_type == AST_ID);
+ if (!scope)
+ return NULL;
-struct ast_node *scope_resolve_call(struct scope *scope, struct ast_node *call)
-{
- assert(call->node_type == AST_CALL);
- /* unsure if actual should be here or somewhere else but eh */
- struct ast_node *found = scope_resolve_actual(scope, call);
+ struct ast_node *found = scope_find_proc(scope, proc);
if (found)
return found;
- found = scope_resolve_proc(scope, call);
- if (found)
- return found;
+ if (!scope_flags(scope, SCOPE_FILE))
+ return file_scope_find_proc(scope->parent, proc);
return NULL;
}
-struct ast_node *file_scope_resolve_call(struct scope *scope,
- struct ast_node *call)
+struct ast_node *scope_find_var(struct scope *scope, struct ast_node *var)
{
- struct ast_node *found = scope_resolve_call(scope, call);
- if (found)
- return found;
-
- if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_resolve_call(scope->parent, call);
-
- return NULL;
+ return scope_find_visible(scope->vars, var);
}
-struct ast_node *file_scope_resolve_macro(struct scope *scope, struct ast_node *macro)
+struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *var)
{
- struct ast_node *found = scope_resolve_macro(scope, macro);
+ assert(var->node_type == AST_ID);
+ if (!scope)
+ return NULL;
+
+ struct ast_node *found = scope_find_var(scope, var);
if (found)
return found;
if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_resolve_macro(scope->parent, macro);
+ return file_scope_find_var(scope->parent, var);
return NULL;
}
-/* this might be useful somewhere else as well */
-static enum ast_primitive default_types[] = {AST_VOID, AST_I9, AST_I27};
-static const char *default_names[] = {"void", "i9", "i27"};
-
-/* TODO: add error checking */
-int scope_add_defaults(struct scope *root)
-{
- for (size_t i = 0;
- i < sizeof(default_types) / sizeof(default_types[0]);
- ++i) {
- struct ast_node *n = gen_id(strdup(default_names[i]), NULL_LOC());
- struct ast_node *a = gen_primitive(default_types[i], NULL_LOC());
- if (!a)
- return -1;
-
- scope_add_type(root, n, a);
- }
-
- return 0;
-}
-
void scope_add_scope(struct scope *parent, struct scope *child)
{
assert(parent);
@@ -874,38 +374,3 @@ int scope_add_actual(struct scope *scope, struct ast_node *node)
{
return add_actual(scope->actuals, node);
}
-
-static struct ast_node *find_actual(struct actual *actuals,
- struct ast_node *node)
-{
- assert(node->node_type == AST_ID);
-
- if (!actuals)
- return NULL;
-
- do {
- struct ast_node *actual = actuals->node;
- if (identical_ast_nodes(0, actual->_proc.id, node))
- return actual;
-
- } while ((actuals = actuals->next));
-
- return NULL;
-}
-
-struct ast_node *scope_find_actual(struct scope *scope, struct ast_node *node)
-{
- return find_actual(scope->actuals, node);
-}
-
-struct scope *create_temp_scope(struct scope *parent)
-{
- struct scope *scope = create_scope();
- if (!scope) {
- internal_error("failed allocating temp scope");
- }
-
- scope->parent = parent;
- scope->fctx = parent->fctx;
- return scope;
-}