aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--include/ek/actualize.h61
-rw-r--r--include/ek/ast.h1546
-rw-r--r--include/ek/debug.h20
-rw-r--r--include/ek/lower.h2
-rw-r--r--include/ek/parser.h2
-rw-r--r--include/ek/scope.h61
-rw-r--r--include/ek/vec.h3
-rw-r--r--src/actualize.c1855
-rw-r--r--src/ast.c2019
-rw-r--r--src/compiler.c12
-rw-r--r--src/debug.c133
-rw-r--r--src/lexer.l36
-rw-r--r--src/lower.c365
-rw-r--r--src/parser.y265
-rw-r--r--src/scope.c118
-rw-r--r--tests/if2.ek6
-rw-r--r--tests/loop.ek3
18 files changed, 2212 insertions, 4297 deletions
diff --git a/Makefile b/Makefile
index fe2837c..4ded5db 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
DO != echo -n > deps.mk
DEBUGFLAGS != [ $(RELEASE) ] && echo "-flto=auto -O2 -DNODEBUG" || echo "-O0 -DDEBUG"
-CFLAGS = -Wall -Wextra -Wconversion -g
+CFLAGS = -Wall -Wextra -Wconversion -ggdb3
DEPFLAGS = -MT $@ -MMD -MP -MF $@.d
LINTFLAGS = -fsyntax-only
INCLUDEFLAGS = -Iinclude
diff --git a/include/ek/actualize.h b/include/ek/actualize.h
index 486f19e..9dc5948 100644
--- a/include/ek/actualize.h
+++ b/include/ek/actualize.h
@@ -25,47 +25,7 @@
* @param b Type to compare against \p a.
* @return \c 1 if types match, \c 0 otherwise.
*/
-int types_match(struct ast_node *a, struct ast_node *b);
-
-/**
- * Replace type in \p type that matches with \p from
- * with \p to.
- *
- * @param type Whole type to replace part in.
- * @param from Part of type to replace.
- * @param to Type to replace \p from with.
- */
-void replace_type(struct ast_node *type,
- struct ast_node *from, struct ast_node *to);
-
-/**
- * Loop over parameters and replace types that match with \p param_type
- * with \p arg_type.
- *
- * @param param Parameters to replace types for.
- * @param param_type Type to replace with \p arg_type.
- * @param arg_type Type to replace \p param_type with.
- */
-void replace_param_types(struct ast_node *param,
- struct ast_node *param_type,
- struct ast_node *arg_type);
-
-/**
- * Extract trait type, that is strip pointer/expression/alias stuff
- * and get the trait itself from the type.
- *
- * @param type Type to extract trait from.
- * @return Pointer to trait node when found, \c NULL otherwise.
- */
-struct ast_node *extract_trait(struct ast_node *type);
-
-/**
- * Extract typeof expression.
- *
- * @param type Type to extract typeof from.
- * @return Pointer to typeof expression node when found, \c NULL otherwise.
- */
-struct ast_node *extract_typeof(struct ast_node *type);
+int types_match(struct type *a, struct type *b);
/**
* Analyze raw AST, assumed to be file scope.
@@ -77,23 +37,6 @@ struct ast_node *extract_typeof(struct ast_node *type);
* @param tree Raw AST to analyze.
* @return \c 0 when successful, non-zero otherwise.
*/
-int analyze_root(struct scope *scope, struct ast_node *tree);
-
-/**
- * Start actual compilation by trying to actualize main.
- *
- * @param scope Scope \c main() should be visible to, likely root scope.
- * @return \c 0 when succesful, non-zero otherwise.
- */
-int actualize_main(struct scope *scope);
-
-/**
- * Create temporary actualization context and actualizes \p type within it.
- *
- * @param scope Scope to actualize \p type in.
- * @param type Type to actualize.
- * @return \c 0 when succesful, non-zero otherwise.
- */
-int actualize_temp_type(struct scope *scope, struct ast_node *type);
+int analyze_root(struct scope *scope, struct ast *tree);
#endif /* ANALYZE_H */
diff --git a/include/ek/ast.h b/include/ek/ast.h
index f7c6201..27e82e3 100644
--- a/include/ek/ast.h
+++ b/include/ek/ast.h
@@ -5,6 +5,7 @@
#define AST_H
#include <stddef.h>
+#include <stdbool.h>
/**
* @file ast.h
@@ -12,118 +13,6 @@
* Abstract syntax tree handling.
*/
-#define AST_ID(x) x->_id
-#define AST_AS(x) x->_as
-#define AST_DOT(x) x->_dot
-#define AST_UNOP(x) x->_unop
-#define AST_IMPORT(x) x->_import
-#define AST_ALIAS(x) x->_alias
-#define AST_TRAIT(x) x->_trait
-#define AST_CAST(x) x->_cast
-#define AST_PROC(x) x->_proc
-#define AST_VAR(x) x->_var
-#define AST_RETURN(x) x->_return
-#define AST_STRUCT(x) x->_struct
-#define AST_ENUM(x) x->_enum
-#define AST_CALL(x) x->_call
-#define AST_CONST(x) x->_const
-#define AST_ASSIGN(x) x->_assign
-#define AST_BLOCK(x) x->_block
-#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_EXPAND(x) x->_type_expand
-#define AST_IF(x) x->_if
-#define AST_CASE(x) x->_case
-#define AST_SWITCH(x) x->_switch
-#define AST_VAL(x) x->_val
-#define AST_EMBED(x) x->_embed
-#define AST_CTRL(x) x->_ctrl
-#define AST_WHILE(x) x->_while
-#define AST_FOR(x) x->_for
-#define AST_DEFER(x) x->_defer
-#define AST_BINOP(x) x->_binop
-#define AST_LABEL(x) x->_label
-#define AST_GOTO(x) x->_goto
-#define AST_INIT(x) x->_init
-#define AST_SIZEOF(x) x->_sizeof
-#define AST_FETCH(x) x->_fetch
-
-#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_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_UNION_TYPE(x) x->_type._union
-#define AST_STRUCT_TYPE(x) x->_type._struct
-/* might rename primitive to something else */
-#define AST_PRIMITIVE_TYPE(x) x->_type._primitive
-#define AST_PTR_TYPE(x) x->_type._ptr
-
-/** Binary operands, that is they take two arguments and produce a result. */
-enum ast_binops {
- /** Add, \c + */
- AST_ADD,
- /** Subtract, \c - */
- AST_SUB,
- /** Multiply, \ * */
- AST_MUL,
- /** Divide, \c \ */
- AST_DIV,
- /** Remainder, \c % */
- AST_REM,
- /** Logical and, \c && */
- AST_LAND,
- /** Logical or, \c ||*/
- AST_LOR,
- /** Left shift (logical), \c << @todo add arithmetic shifts? */
- AST_LSHIFT,
- /** Right shift (logical), \c >> */
- AST_RSHIFT,
- /** Assigning add, \c += */
- AST_ASSIGN_ADD,
- /** Assigning subtraction, \c -= */
- AST_ASSIGN_SUB,
- /** Assigning multiplication, \c *= */
- AST_ASSIGN_MUL,
- /** Assigning division, \c /= */
- AST_ASSIGN_DIV,
- /** Assigning remainder, \c %= */
- AST_ASSIGN_REM,
- /** Assigning logical left shift, \c >>= */
- AST_ASSIGN_LSHIFT,
- /** Assigning logical right shift, \c <<= */
- AST_ASSIGN_RSHIFT,
- /** Less than, \c < */
- AST_LT,
- /** Greater than, \c > */
- AST_GT,
- /** Less than or equal, \c <= */
- AST_LE,
- /** Greater than or equal, \c >= */
- AST_GE,
- /** Not equal, \c != */
- AST_NE,
- /** Equal, \c == */
- AST_EQ,
-};
-
-/** Unary operations, that is they take one argument and produce a result. */
-enum ast_unops {
- /** Negation, \c - */
- AST_NEG,
- /** Logical negation, \c ! */
- AST_LNOT,
- /** Referencing, \c & */
- AST_REF,
- /** Dereferencing, \c ' */
- AST_DEREF,
-};
-
#define NULL_LOC() ((struct src_loc){0, 0, 0, 0})
/** Represents a source location, spanning over some bit of code. */
@@ -139,20 +28,16 @@ struct src_loc {
};
/** Possible AST node types. We reserve node 0 as an illegal value. */
-enum ast_node_type {
- /** Binary operation. */
- AST_BINOP = 1,
- /** Unary operation. */
- AST_UNOP,
+enum ast_kind {
/** Fetch enum constant. */
- AST_FETCH,
+ AST_FETCH = 1,
/** Value initialization. */
AST_INIT,
/** Assignment. */
AST_ASSIGN,
/** Call procedure. */
AST_CALL,
- AST_ARR_ACCESS,
+ AST_ARR,
/** Sizeof. */
AST_SIZEOF,
/** Cast. */
@@ -160,17 +45,17 @@ enum ast_node_type {
/** Defer. */
AST_DEFER,
/** Macro definition. */
- AST_MACRO_CONSTRUCT,
+ AST_MACRO_DEF,
AST_MACRO_EXPAND,
AST_TYPE_EXPAND,
/** Procedure definition. */
- AST_PROC,
+ AST_PROC_DEF,
/** Goto. */
AST_GOTO,
/** Goto label. */
AST_LABEL,
/** Variable declaration/definition. */
- AST_VAR,
+ AST_VAR_DEF,
/** For loop. */
AST_FOR,
/** Embed file contents. */
@@ -182,88 +67,99 @@ enum ast_node_type {
* \c AST_DELAYED is active for \c do loops.
*/
AST_WHILE,
+ AST_DO_WHILE,
/** Control statement, \c break or \c continue. */
- AST_CTRL,
+ AST_BREAK,
+ AST_CONTINUE,
/** Return. */
AST_RETURN,
/** Alias definition. */
- AST_ALIAS,
+ AST_ALIAS_DEF,
/** More like trait. @todo really come up with consistent naming. */
- AST_TRAIT,
+ AST_TRAIT_DEF,
/** Structure definition. */
- AST_STRUCT,
+ AST_STRUCT_DEF,
/** If. */
AST_IF,
- /** Special 'meta' node that represents a type. */
- AST_TYPE,
/** Block. E.g. \c {} */
AST_BLOCK,
/** Import. */
AST_IMPORT,
/** Enum definition. */
- AST_ENUM,
+ AST_ENUM_DEF,
/** Enum constant value. */
AST_VAL,
/** Switch. */
AST_SWITCH,
/** Switch case. */
AST_CASE,
- /** Constant value. */
- AST_CONST,
/** Any ID, variable or whatever. */
AST_ID,
/** As statement, used to determine types. */
AST_AS,
/** Empty. Essentially noop. */
AST_EMPTY,
-};
-
-/** Whether \c AST_CTRL is break or continue. */
-enum ast_ctrl_kind {
- /** Break. */
- AST_CTRL_BREAK,
- /** Continue. */
- AST_CTRL_CONTINUE
-};
-
-/** Constant value kind. */
-enum ast_const_kind {
- /** Integer, i27 */
- AST_CONST_INTEGER,
- /** String. */
- AST_CONST_STRING,
-};
-
-/** Type representation. */
-enum ast_type_kind {
- /** ID, can refer to pretty much anything. */
- AST_TYPE_ID,
- AST_TYPE_PRIMITIVE,
- /** Array. */
- AST_TYPE_ARR,
- AST_TYPE_CONSTRUCT,
- /** Trait. */
- AST_TYPE_TRAIT,
- /** Pointer to a type. */
- AST_TYPE_POINTER,
- /** Structure. */
- AST_TYPE_STRUCT,
- /** Enum. */
- AST_TYPE_ENUM,
- /** Signature, i.e. procedure signature. */
- AST_TYPE_SIGN,
-};
-
-/** Whether typedef makes an alias on trait. */
-enum ast_typedef_kind {
- /** Alias. */
- AST_TYPEDEF_ALIAS,
- /** Trait. */
- AST_TYPEDEF_TRAIT,
+ /** Add, \c + */
+ AST_ADD,
+ /** Subtract, \c - */
+ AST_SUB,
+ /** Multiply, \ * */
+ AST_MUL,
+ /** Divide, \c \ */
+ AST_DIV,
+ /** Remainder, \c % */
+ AST_REM,
+ /** Logical and, \c && */
+ AST_LAND,
+ /** Logical or, \c ||*/
+ AST_LOR,
+ /** Left shift (logical), \c << @todo add arithmetic shifts? */
+ AST_LSHIFT,
+ /** Right shift (logical), \c >> */
+ AST_RSHIFT,
+ /** Assigning add, \c += */
+ AST_ASSIGN_ADD,
+ /** Assigning subtraction, \c -= */
+ AST_ASSIGN_SUB,
+ /** Assigning multiplication, \c *= */
+ AST_ASSIGN_MUL,
+ /** Assigning division, \c /= */
+ AST_ASSIGN_DIV,
+ /** Assigning remainder, \c %= */
+ AST_ASSIGN_REM,
+ /** Assigning logical left shift, \c >>= */
+ AST_ASSIGN_LSHIFT,
+ /** Assigning logical right shift, \c <<= */
+ AST_ASSIGN_RSHIFT,
+ /** Less than, \c < */
+ AST_LT,
+ /** Greater than, \c > */
+ AST_GT,
+ /** Less than or equal, \c <= */
+ AST_LE,
+ /** Greater than or equal, \c >= */
+ AST_GE,
+ /** Not equal, \c != */
+ AST_NE,
+ /** Equal, \c == */
+ AST_EQ,
+ /** Negation, \c - */
+ AST_NEG,
+ /** Logical negation, \c ! */
+ AST_LNOT,
+ AST_NOT,
+ /** Referencing, \c & */
+ AST_REF,
+ /** Dereferencing, \c ' */
+ AST_DEREF,
+ AST_CONST_INT,
+ AST_CONST_CHAR,
+ AST_CONST_BOOL,
+ AST_CONST_STR,
};
/** Flags an AST node can have. */
-enum ast_flag {
+enum ast_flags {
/** Node is mutable. Mostly used for variables. */
AST_FLAG_MUTABLE = (1 << 0),
/** Value is constant. Constant if, for, etc. */
@@ -300,1005 +196,461 @@ enum ast_flag {
AST_FLAG_DOEXPR = (1 << 15),
};
-struct ast_node;
-
-/**
- * AST if node.
- *
- * \verbatim
- * if cond {body} [els]
- * \endverbatim
- */
-struct ast_if {
- /** Conditional block. */
- struct ast_node *cond;
- /** Body. */
- struct ast_node *body;
- /** Else block. */
- struct ast_node *els;
-};
-
-/** AST fetch enum member node. */
-struct ast_fetch {
- /** Name of member to fetch. */
- struct ast_node *id;
- /** Enum type to fetch from. */
- struct ast_node *type;
-};
-
-/** Goto label. */
-struct ast_label {
- /** Label name. */
- struct ast_node *id;
- /**
- * List of active defers.
- * Used to determine which defer statements should be executed
- * when a goto jumps to this label.
- */
- struct ast_node *defers;
-};
-
-struct ast_arr_access {
- struct ast_node *base;
- struct ast_node *idx;
-};
-
-/** Goto node. */
-struct ast_goto {
- /** Name of label to jump to. */
- struct ast_node *label;
- /**
- * List of active defers.
- * With the list in the corresponding label, we can detect which
- * defers should be triggered and which ones shouldn't.
- * See actualize_goto_defers().
- */
- struct ast_node *defers;
-};
-
-/** Alias definition. */
-struct ast_alias {
- /** Name of alias. */
- struct ast_node *id;
- /** Type to alias. */
- struct ast_node *type;
-};
-
-/** List of types that implements the template list belongs to. */
-struct trait_implemented {
- /** A type that implements the template. */
- struct ast_node *type;
- /** Next type that implements the template. */
- struct trait_implemented *next;
-};
-
-/** A trait definition. */
-struct ast_trait {
- /** Name of trait. */
- struct ast_node *id;
- /** Parameters to construct concrete type from trait. */
- struct ast_node *params;
- /** Raw body before expansion. */
- struct ast_node *raw_body;
- /** Body of trait. */
- struct ast_node *body;
-};
+struct ast;
-/** Cast. */
-struct ast_cast {
- /** Expression. */
- struct ast_node *expr;
- /** Type to cast expression result to. */
- struct ast_node *type;
+enum type_kind {
+ TYPE_VOID = 1, TYPE_BOOL, TYPE_I9, TYPE_I27, TYPE_STR, TYPE_PTR,
+ TYPE_ID, TYPE_CONSTRUCT, TYPE_STRUCT, TYPE_ENUM, TYPE_CALLABLE,
+ TYPE_TRAIT,
};
-/** Binary operation. */
-struct ast_binop {
- /** Which operation. */
- enum ast_binops op;
- /** Left operand. */
- struct ast_node *left;
- /** Right operand. */
- struct ast_node *right;
-};
-
-/** Unary operation. */
-struct ast_unop {
- /** Which operation. */
- enum ast_unops op;
- /** Expression. */
- struct ast_node *expr;
-};
+struct type {
+ enum type_kind k;
-/** A call. */
-struct ast_call {
- /** Name to call, whatever it may be. */
- struct ast_node *expr;
- /** List of arguments to call. */
- struct ast_node *args;
-};
-
-/** Defer. */
-struct ast_defer {
- /** Expression to defer. */
- struct ast_node *expr;
-};
+ /* arg */
+ struct type *t0;
+ struct type *t1;
-/** Macro definition. */
-struct ast_macro_construct {
- /** Name of macro. */
- struct ast_node *id;
- /** Parameters macro takes. */
- struct ast_node *params;
- /** Macro body. */
- struct ast_node *body;
-};
-
-struct ast_macro_expand {
- struct ast_node *id;
- struct ast_node *args;
-};
-
-struct ast_type_expand {
- struct ast_node *id;
- struct ast_node *args;
-};
+ /* definition */
+ struct ast *d;
+ /* alias */
+ struct ast *a;
+ /* id */
+ char *id;
+ /* next */
+ struct type *n;
-/** Procedure definition. */
-struct ast_proc {
- /** Procedure name. */
- struct ast_node *id;
- /** Procedure signature. */
- struct ast_node *sign;
- /** Procedure body. */
- struct ast_node *body;
-};
-
-/** Dot. */
-struct ast_dot {
- /** Expression to do dot operation on. */
- struct ast_node *expr;
- /** Name to dot. */
- struct ast_node *id;
-};
-
-/** As. */
-struct ast_as {
- /** Type to use for resolution. */
- struct ast_node *type;
-};
-
-/** Sizeof. */
-struct ast_sizeof {
- /** Expression to get type of. */
- struct ast_node *expr;
-};
-
-/** Variable declaration. */
-struct ast_var {
- /** Name of variable. */
- struct ast_node *id;
- /** Type of variable. */
- struct ast_node *type;
- /** Initialization expression. */
- struct ast_node *init;
-};
-
-/** Lambda definition. */
-struct ast_lambda {
- /** Which variables to capture from the context. */
- struct ast_node *captures;
- /** Signature of lambda. */
- struct ast_node *sign;
- /** Body of lambda. */
- struct ast_node *body;
-};
-
-/**
- * For loop.
- *
- * \verbatim
- * for (pre; cond; post) {body}
- * \endverbatim
- */
-struct ast_for {
- /** Initialization. */
- struct ast_node *pre;
- /** Condition. */
- struct ast_node *cond;
- /** Iteration. */
- struct ast_node *post;
- /** Body. */
- struct ast_node *body;
+ struct src_loc loc;
+ struct scope *scope;
};
-/** While loop. */
-struct ast_while {
- /** Condition. */
- struct ast_node *cond;
- /** Body. */
- struct ast_node *body;
-};
+struct ast {
+ enum ast_kind k;
+ struct type *t;
+ long long v;
+ char *s;
+ struct ast *a0;
+ struct ast *a1;
+ struct ast *a2;
+ struct ast *a3;
+ struct type *t2;
+ enum ast_flags f;
-/** Control. */
-struct ast_ctrl {
- /** Break or continue. */
- enum ast_ctrl_kind kind;
- /**
- * List of active defers.
- * Similarly to goto, used to figure out which defers to trigger.
- */
- struct ast_node *defers;
-};
+ struct ast *n;
+ long long uses;
-/** Return. */
-struct ast_return {
- /** Expression to return. */
- struct ast_node *expr;
- /** List of active defers. */
- struct ast_node *defers;
+ struct src_loc loc;
+ struct scope *scope;
};
-enum ast_primitive {
- AST_VOID, AST_BOOL, AST_I9, AST_I27, AST_STR
-};
+struct ast *gen_ast(enum ast_kind kind,
+ struct ast *a0,
+ struct ast *a1,
+ struct ast *a2,
+ struct ast *a3,
+ struct type *t1,
+ char *s,
+ long long v,
+ struct src_loc loc);
-/**
- * Type.
- * I'm not entirely happy with the current type system, for one
- * some parts are only used until they get initialized, which makes it
- * sort of difficult to follow what each kind means.
- *
- * @todo Could be better to have separate type nodes instead of co-opting
- * AST nodes.
- */
-struct ast_type {
- /** Type kind. */
- enum ast_type_kind kind;
- /**
- * 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;
- struct ast_node *as;
- struct ast_node *aliased;
+struct type *tgen_type(enum type_kind kind,
+ struct type *t0,
+ struct type *t1,
+ struct ast *d,
+ struct ast *a,
+ char *id,
+ struct src_loc loc);
- /** Data relevant to kind. */
- union {
- /** Name of a type, to be converted later. */
- struct {
- struct ast_node *id;
- } _id;
+#define tgen_primitive(kind, id, def, loc)\
+ tgen_type(kind, NULL, NULL, def, NULL, id, loc)
- struct {
- struct ast_node *id;
- struct ast_node *args;
- } _construct;
+#define tgen_id(id, loc)\
+ tgen_type(TYPE_ID, NULL, NULL, NULL, NULL, id, loc)
- struct {
- enum ast_primitive type;
- struct ast_node *def; // for possible user defined
- // member functions
- } _primitive;
+#define tgen_struct(id, def, loc)\
+ tgen_type(TYPE_STRUCT, NULL, NULL, def, NULL, id, loc)
- /** Array type. */
- struct {
- struct ast_node *size;
- struct ast_node *base;
- } _arr;
+#define tgen_trait(id, def, loc)\
+ tgen_type(TYPE_TRAIT, NULL, NULL, def, NULL, id, loc)
- struct {
- struct ast_node *base;
- } _ptr;
+static inline bool is_binop(struct ast *x)
+{
+ switch (x->k) {
+ case AST_ADD:
+ case AST_SUB:
+ case AST_MUL:
+ case AST_DIV:
+ case AST_REM:
+ case AST_LSHIFT:
+ case AST_RSHIFT:
+ return true;
+ default:
+ };
- /** Procedure. */
- struct {
- /** Name. */
- struct ast_node *id;
- /** Parameters. */
- struct ast_node *params;
- /** Return type. */
- struct ast_node *ret;
- } _proc;
+ return false;
+}
- /** Trait. */
- struct {
- /** Trait definition. */
- struct ast_node *def;
- } _trait;
+static inline bool is_opassign(struct ast *x)
+{
+ switch (x->k) {
+ case AST_ASSIGN_ADD:
+ case AST_ASSIGN_SUB:
+ case AST_ASSIGN_MUL:
+ case AST_ASSIGN_DIV:
+ case AST_ASSIGN_REM:
+ case AST_ASSIGN_LSHIFT:
+ case AST_ASSIGN_RSHIFT:
+ return true;
+ default:
+ };
+ return false;
+}
- /** Structure. */
- struct {
- /** Structure definition. */
- struct ast_node *def;
- } _struct;
+static inline bool is_unop(struct ast *x)
+{
+ switch (x->k) {
+ case AST_REF:
+ case AST_DEREF:
+ case AST_NOT:
+ case AST_NEG:
+ return true;
+ default:
+ }
- /** Enumeration. */
- struct {
- /** Enum definition. */
- struct ast_node *def;
- } _enum;
+ return false;
+}
- /** Union. */
- struct {
- /** Name of union. */
- struct ast_node *id;
- /** Arguments for type parameters. */
- struct ast_node *impls;
- } _union;
+static inline bool is_comparison(struct ast *x)
+{
+ switch (x->k) {
+ case AST_LT:
+ case AST_GT:
+ case AST_LE:
+ case AST_GE:
+ case AST_NE:
+ case AST_EQ:
+ return true;
+ default:
+ }
- struct {
- /** Parameter types. */
- struct ast_node *params;
- /** Return type. */
- struct ast_node *ret;
- } _sign;
- };
-};
+ return false;
+}
-/** Block. */
-struct ast_block {
- /** Body of block. */
- struct ast_node *body;
- /** List of defers. */
- struct ast_node *defers;
-};
+static inline bool is_const(struct ast *x)
+{
+ /* note that const strings are sort of their own entity */
+ switch (x->k) {
+ case AST_CONST_INT:
+ case AST_CONST_CHAR:
+ case AST_CONST_BOOL:
+ return true;
+ default:
+ }
-/** Import. */
-struct ast_import {
- /** File to import. */
- const char *file;
-};
+ return false;
+}
-/** Embed. @todo figure out how embedding should be done, just *u8? */
-struct ast_embed {
- /** File to embed. */
- const char *file;
-};
+static inline bool is_primitive(struct type *t)
+{
+ switch (t->k) {
+ case TYPE_I27:
+ case TYPE_I9:
+ case TYPE_BOOL:
+ case TYPE_PTR:
+ return true;
+ default:
+ }
-/** Enum definition. */
-struct ast_enum {
- /** Name of enum. */
- struct ast_node *id;
- /** Type enum is convertible to/from. */
- struct ast_node *type;
- /** Body. */
- struct ast_node *body;
-};
+ return false;
+}
-/** Structure definition. */
-struct ast_struct {
- /** Name of structure. */
- struct ast_node *id;
- /** List of type parameters, if any. */
- struct ast_node *generics;
- /** Body. */
- struct ast_node *body;
- struct trait_implemented *implemented_by;
-};
+#define gen_str_type1(k, s, t, a, loc) gen_ast(k, a, NULL, NULL, NULL, t, s, 0, loc)
+#define gen_str_type(k, s, t, loc) gen_str_type1(k, s, t, NULL, loc)
+#define gen_type(k, a, type, loc) gen_ast(k, a, NULL, NULL, NULL, type, NULL, 0, loc)
+#define gen_str2(k, s, a, b, loc) gen_ast(k, a, b, NULL, NULL, NULL, s, 0, loc)
+#define gen_str1(k, s, a, loc) gen_str2(k, s, a, NULL, loc)
+#define gen_str(k, s, loc) gen_ast(k, NULL, NULL, NULL, NULL, NULL, s, 0, loc)
-/** Enum member constant value. */
-struct ast_val {
- /** Name of member. */
- struct ast_node *id;
- /** Constant value of member. */
- struct ast_node *val;
-};
-/** Switch. */
-struct ast_switch {
- /** Condition. */
- struct ast_node *cond;
- /** List of cases. */
- struct ast_node *cases;
-};
+#define gen4(k, a, b, c, d, loc) gen_ast(k, a, b, c, d, NULL, NULL, 0, loc)
+#define gen3(k, a, b, c, loc) gen4(k, a, b, c, NULL, loc)
+#define gen2(k, a, b, loc) gen3(k, a, b, NULL, loc)
+#define gen1(k, a, loc) gen2(k, a, NULL, loc)
-/** Switch case. */
-struct ast_case {
- /** Condition. */
- struct ast_node *cond;
- /** Body. */
- struct ast_node *body;
-};
+#define tgen2(k, a, b, loc) tgen_type(k, a, b, NULL, NULL, NULL, loc)
+#define tgen1(k, a, loc) tgen2(k, a, NULL, loc)
-/** Constant value. */
-struct ast_const {
- /** Constant kind. */
- enum ast_const_kind kind;
- union {
- /** Integer. */
- long long integer;
- /** String. */
- const char *str;
- };
-};
+#define tgen_str1(k, s, a, loc) tgen_type(k, a, NULL, NULL, NULL, s, loc)
-/** Value initialization. */
-struct ast_init {
- /** Body. @todo maybe come up with a better name? */
- struct ast_node *body;
-};
+/* kind of hacky but I guess it works, and allows us to check that the type is
+ * correct every time */
+#define return_s(x, kind) *({assert((x)->k == kind); &(x)->s;})
+#define return_a0(x, kind) *({assert((x)->k == kind); &(x)->a0;})
+#define return_a1(x, kind) *({assert((x)->k == kind); &(x)->a1;})
+#define return_a2(x, kind) *({assert((x)->k == kind); &(x)->a2;})
+#define return_a3(x, kind) *({assert((x)->k == kind); &(x)->a3;})
-/** Assignment. */
-struct ast_assign {
- /** Where to assign to. */
- struct ast_node *to;
- /** What to assign from. */
- struct ast_node *from;
-};
+#define return_t0(x, kind) *({assert((x)->k == kind); &(x)->t0;})
+#define return_t1(x, kind) *({assert((x)->k == kind); &(x)->t1;})
+/* note that this one is in ast, the other two are in type */
+#define return_t2(x, kind) *({assert((x)->k == kind); &(x)->t2;})
-/**
- * An ID.
- * @todo One optimization would be to reduce number of ast_ids,
- * replacing them with raw strings.
- */
-struct ast_id {
- /** Actual ID. */
- const char *id;
-};
+#define if_cond(x) return_a0(x, AST_IF)
+#define if_body(x) return_a1(x, AST_IF)
+#define if_else(x) return_a2(x, AST_IF)
+#define gen_if(cond, body, else, loc)\
+ gen3(AST_IF, cond, body, else, loc)
-/** Empty node. */
-struct ast_empty {
-};
+#define fetch_id(x) return_s(x, AST_FETCH)
+#define fetch_type(x) return_t2(x, AST_FETCH)
+#define gen_fetch(id, type, loc)\
+ gen_str_type(AST_FETCH, id, type, loc)
-/** AST node. */
-struct ast_node {
- /** Node type. */
- enum ast_node_type node_type;
- /** Node flags. */
- enum ast_flag flags;
- /** Next node, when applicable. I.e. body statements. */
- struct ast_node *next;
- /** Source location. */
- struct src_loc loc;
- /** Scope node belongs to. */
- struct scope *scope;
- /** Ek type. */
- struct ast_node *type;
+#define label_id(x) return_s(x, AST_LABEL)
+#define label_defers(x) return_a0(x, AST_LABEL)
+#define gen_label(id, defers, loc)\
+ gen_str1(AST_LABEL, id, defers, loc)
- size_t uses;
+#define arr_base(x) return_a0(x, AST_ARR)
+#define arr_idx(x) return_a1(x, AST_ARR)
+#define gen_arr(base, idx, loc)\
+ gen2(AST_ARR, base, idx, loc)
- /** Data relevant to kind. */
- union {
- struct ast_arr_access _arr_access;
- /** Binary operation. */
- struct ast_binop _binop;
- /** Unary operation. */
- struct ast_unop _unop;
- /** Call. */
- struct ast_call _call;
- /** Cast. */
- struct ast_cast _cast;
- /** Macro definition. */
- struct ast_macro_construct _macro_construct;
- struct ast_macro_expand _macro_expand;
- struct ast_type_expand _type_expand;
- /** Procedure definition. */
- struct ast_proc _proc;
- /** Goto. */
- struct ast_goto _goto;
- /** Goto label. */
- struct ast_label _label;
- /** Variable. */
- struct ast_var _var;
- /** Lambda. */
- struct ast_lambda _lambda;
- /** If. */
- struct ast_if _if;
- /** For. */
- struct ast_for _for;
- /** While. */
- struct ast_while _while;
- /** Break/continue. */
- struct ast_ctrl _ctrl;
- /** Defer. */
- struct ast_defer _defer;
- /** Type. */
- struct ast_type _type;
- /** Dot. */
- struct ast_dot _dot;
- /** Block. */
- struct ast_block _block;
- /** Import. */
- struct ast_import _import;
- /** Embed. */
- struct ast_embed _embed;
- /** Return. */
- struct ast_return _return;
- /** Switch. */
- struct ast_switch _switch;
- /** Alias. */
- struct ast_alias _alias;
- /** Trait definition. */
- struct ast_trait _trait;
- /** Enum definition. */
- struct ast_enum _enum;
- /** Structure definition. */
- struct ast_struct _struct;
- /** Enum value. */
- struct ast_val _val;
- /** Switch case. */
- struct ast_case _case;
- /** Constant value. */
- struct ast_const _const;
- /** Initialization. */
- struct ast_init _init;
- /** Assignment. */
- struct ast_assign _assign;
- /** ID. */
- struct ast_id _id;
- /** As type. */
- struct ast_as _as;
- /** Sizeof. */
- struct ast_sizeof _sizeof;
- /** Fetch enum member. */
- struct ast_fetch _fetch;
- /** Empty. */
- struct ast_empty _empty;
- };
-};
+#define goto_label(x) return_s(x, AST_GOTO)
+#define goto_defers(x) return_a0(x, AST_GOTO)
+#define gen_goto(label, defers, loc)\
+ gen_str1(AST_GOTO, label, defers, loc)
-struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx,
- struct src_loc loc);
+#define alias_id(x) return_s(x, AST_ALIAS_DEF)
+#define alias_type(x) return_t2(x, AST_ALIAS_DEF)
+#define gen_alias(id, type, loc)\
+ gen_str_type(AST_ALIAS_DEF, id, type, loc)
-/**
- * Generate binary operation node.
- *
- * @param op Which operation.
- * @param left Left operand.
- * @param right Right operand.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_binop(enum ast_binops op,
- struct ast_node *left,
- struct ast_node *right,
- struct src_loc loc);
+#define trait_id(x) return_s(x, AST_TRAIT_DEF)
+#define trait_params(x) return_a0(x, AST_TRAIT_DEF)
+#define trait_raw_body(x) return_a1(x, AST_TRAIT_DEF)
+#define trait_body(x) return_a2(x, AST_TRAIT_DEF)
+#define gen_trait(id, params, body, loc)\
+ gen_str2(AST_TRAIT_DEF, id, params, body, loc)
-/**
- * Generate unary operation.
- *
- * @param op Which operation.
- * @param expr Expression.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_unop(enum ast_unops op, struct ast_node *expr,
- struct src_loc loc);
+#define cast_expr(x) return_a0(x, AST_CAST)
+#define cast_type(x) return_t2(x, AST_CAST)
+#define gen_cast(expr, type, loc)\
+ gen_type(AST_CAST, expr, type, loc)
-/**
- * Generate call.
- *
- * @param id ID to call.
- * @param args Arguments to call.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_call(struct ast_node *id, struct ast_node *args,
- struct src_loc loc);
+#define opassign_left(x) ({assert(is_opassign(x)); x->a0;})
+#define opassign_right(x) ({assert(is_opassign(x)); x->a1;})
+#define gen_opassign(op, left, right, loc)\
+ gen2(op, left, right, loc)
-/**
- * Generate ID.
- *
- * @param id ID.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_id(const char *id, struct src_loc loc);
+#define binop_left(x) ({assert(is_binop(x)); x->a0;})
+#define binop_right(x) ({assert(is_binop(x)); x->a1;})
+#define gen_binop(op, left, right, loc)\
+ gen2(op, left, right, loc)
-/**
- * Generate constant integer.
- *
- * @param integer Integer.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_int(long long integer, struct src_loc loc);
+#define comparison_left(x) ({assert(is_comparison(x)); x->a0;})
+#define comparison_right(x) ({assert(is_comparison(x)); x->a1;})
+#define gen_comparison(op, left, right, loc)\
+ gen2(op, left, right, loc)
-/**
- * Generate constant string.
- *
- * @param str String.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_string(const char *str, struct src_loc loc);
+#define unop_expr(x) ({assert(is_unop(x)); x->a0;})
+#define gen_unop(op, expr, loc)\
+ gen1(op, expr, loc)
-/**
- * Generate constant float.
- *
- * @param dbl Double.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_float(double dbl, struct src_loc loc);
+#define call_expr(x) return_a0(x, AST_CALL)
+#define call_args(x) return_a1(x, AST_CALL)
+#define gen_call(expr, args, loc)\
+ gen2(AST_CALL, expr, args, loc)
-/**
- * Generate assignment.
- *
- * @param to Where to assign to.
- * @param from Where to assign from.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_assign(struct ast_node *to, struct ast_node *from,
- struct src_loc loc);
+#define defer_expr(x) return_a0(x, AST_DEFER)
+#define gen_defer(expr, loc)\
+ gen1(AST_DEFER, expr, loc)
-/**
- * Generate initialization.
- *
- * @param body Body of initialization.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_init(struct ast_node *body, struct src_loc loc);
+#define macro_def_id(x) return_s(x, AST_MACRO_DEF)
+#define macro_def_params(x) return_a0(x, AST_MACRO_DEF)
+#define macro_def_body(x) return_a1(x, AST_MACRO_DEF)
+#define gen_macro_def(id, params, body, loc)\
+ gen_str2(AST_MACRO_DEF, id, params, body, loc)
-/**
- * Generate while loop.
- *
- * @param cond Condition.
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_while(struct ast_node *cond, struct ast_node *body,
- struct src_loc loc);
+#define macro_expand_id(x) return_s(x, AST_MACRO_EXPAND)
+#define macro_expand_args(x) return_a0(x, AST_MACRO_EXPAND)
+#define gen_macro_expand(id, args, loc)\
+ gen_str1(AST_MACRO_EXPAND, id, args, loc)
-/**
- * Generate for loop.
- *
- * @param pre Pre condition.
- * @param cond Condition.
- * @param post Post condition.
- * @param body Loop body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_for(struct ast_node *pre, struct ast_node *cond,
- struct ast_node *post, struct ast_node *body,
- struct src_loc loc);
+#define type_expand_id(x) return_s(x, AST_TYPE_EXPAND)
+#define type_expand_args(x) return_t2(x, AST_TYPE_EXPAND)
+#define gen_type_expand(id, args, loc)\
+ gen_str_type(AST_TYPE_EXPAND, id, args, loc)
-/**
- * Generate return.
- *
- * @param expr Expression.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_return(struct ast_node *expr, struct src_loc loc);
+#define proc_id(x) return_s(x, AST_PROC_DEF)
+#define proc_params(x) return_a0(x, AST_PROC_DEF)
+#define proc_rtype(x) return_t2(x, AST_PROC_DEF)
+#define proc_body(x) return_a1(x, AST_PROC_DEF)
+#define gen_proc(id, params, rtype, body, loc)\
+ gen_ast(AST_PROC_DEF, params, body, NULL, NULL, rtype, id, 0, loc)
-/**
- * Generate control statement.
- * @note Some generators take source location info, which is then
- * propagated to higher level nodes.
- *
- * @todo not sure where to best place the note about location
- *
- * @param kind Break or continue.
- * @param loc Source location.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_ctrl(enum ast_ctrl_kind kind, struct src_loc loc);
+#define dot_id(x) return_s(x, AST_DOT)
+#define dot_expr(x) return_a0(x, AST_DOT)
+#define gen_dot(id, expr, loc)\
+ gen_str1(AST_DOT, id, expr, loc)
-/**
- * Generate macro definition.
- *
- * @param id Macro name.
- * @param params Macro parameters.
- * @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 src_loc loc);
+#define as_type(x) return_t2(x, AST_AS)
+#define gen_as(type, loc)\
+ gen_type(NULL, type, loc)
-struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args,
- struct src_loc loc);
+#define sizeof_expr(x) return_a0(x, AST_SIZEOF)
+#define gen_sizeof(expr, loc)\
+ gen1(AST_SIZEOF, expr, 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);
+#define var_id(x) return_s(x, AST_VAR_DEF)
+#define var_type(x) return_t2(x, AST_VAR_DEF)
+#define var_init(x) return_a0(x, AST_VAR_DEF)
+#define gen_var(id, type, init, loc)\
+ gen_ast(AST_VAR_DEF, init, NULL, NULL, NULL, type, id, 1, loc)
-/**
- * Generate if.
- *
- * @param cond Condition.
- * @param body Body.
- * @param els Else.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_if(struct ast_node *cond, struct ast_node *body,
- struct ast_node *els, struct src_loc loc);
+#define for_pre(x) return_a0(x, AST_FOR)
+#define for_cond(x) return_a1(x, AST_FOR)
+#define for_post(x) return_a2(x, AST_FOR)
+#define for_body(x) return_a3(x, AST_FOR)
+#define gen_for(pre, cond, post, body, loc)\
+ gen4(AST_FOR, pre, cond, post, body, loc)
-/**
- * Generate switch.
- *
- * @param cond Condition.
- * @param cases List of cases.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_switch(struct ast_node *cond, struct ast_node *cases,
- struct src_loc loc);
+#define while_cond(x) return_a0(x, AST_WHILE)
+#define while_body(x) return_a1(x, AST_WHILE)
+#define gen_while(cond, body, loc)\
+ gen2(AST_WHILE, cond, body, loc)
-/**
- * Generate switch case.
- *
- * @param expr Condition.
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_case(struct ast_node *expr, struct ast_node *body,
- struct src_loc loc);
+#define do_while_cond(x) return_a0(x, AST_DO_WHILE)
+#define do_while_body(x) return_a1(x, AST_DO_WHILE)
+#define gen_do_while(cond, body, loc)\
+ gen2(AST_DO_WHILE, cond, body, loc)
-struct ast_node *gen_primitive(enum ast_primitive type, struct ast_node *def,
- struct src_loc loc);
-/**
- * Generate Ek type (besides primitive).
- *
- * @param kind Type kind.
- * @param id Name of type.
- * @param decl List of parameters, when applicable.
- * @param rets Return type, when applicable.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *t2,
- struct ast_node *t1,
- struct src_loc loc);
+#define continue_defers(x) return_a0(x, AST_CONTINUE)
+#define gen_continue(defers, loc)\
+ gen1(AST_CONTINUE, defers, loc)
-/**
- * Generate block.
- *
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_block(struct ast_node *body, struct src_loc loc);
+#define break_defers(x) return_a0(x, AST_BREAK)
+#define gen_break(defers, loc)\
+ gen1(AST_BREAK, defers, loc)
-/**
- * Generate variable.
- *
- * @param id Name of variable.
- * @param type Type of varibable.
- * @param init Initialization, when applicable.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_var(struct ast_node *id, struct ast_node *type,
- struct ast_node *init, struct src_loc loc);
+#define return_expr(x) return_a0(x, AST_RETURN)
+#define return_defers(x) return_a1(x, AST_RETURN)
+#define gen_return(expr, defers, loc)\
+ gen2(AST_RETURN, expr, defers, loc)
-/**
- * Generate lambda.
- *
- * @param captures List of captures.
- * @param type Signature of lambda.
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_lambda(struct ast_node *captures,
- struct ast_node *type, struct ast_node *body,
- struct src_loc loc);
+#define block_body(x) return_a0(x, AST_BLOCK)
+#define block_defers(x) return_a1(x, AST_BLOCK)
+#define gen_block(body, defers, loc)\
+ gen2(AST_BLOCK, body, defers, loc)
-/**
- * Generate procedure definition.
- *
- * @param id Name of procedure.
- * @param type Signature of procedure.
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_proc(struct ast_node *id, struct ast_node *type,
- struct ast_node *body, struct src_loc loc);
+#define import_file(x) return_s(x, AST_IMPORT)
+#define gen_import(f, loc)\
+ gen_str(AST_IMPORT, f, loc)
-/**
- * Generate dot operation.
- *
- * @param expr Expression to do dot operation to.
- * @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 src_loc loc);
+#define embed_file(x) return_s(x, AST_EMBED)
+#define gen_embed(f, loc)\
+ gen_str(AST_EMBED, f, loc)
-/**
- * Generate enum definition.
- *
- * @param id Name of enumeration type.
- * @param type Type of enum.
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_enum(struct ast_node *id, struct ast_node *type,
- struct ast_node *body, struct src_loc loc);
+#define enum_id(x) return_s(x, AST_ENUM_DEF)
+#define enum_type(x) return_t2(x, AST_ENUM_DEF)
+#define enum_body(x) return_a0(x, AST_ENUM_DEF)
+#define gen_enum(id, type, body, loc)\
+ gen_ast(AST_ENUM_DEF, body, NULL, NULL, NULL, type, id, 0, loc)
-/**
- * Generate enum member value.
- *
- * @param id Name of enumeration member.
- * @param val Value of enumeration member.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_val(struct ast_node *id, struct ast_node *val,
- struct src_loc loc);
+#define struct_id(x) return_s(x, AST_STRUCT_DEF)
+#define struct_params(x) return_a0(x, AST_STRUCT_DEF)
+#define struct_body(x) return_a1(x, AST_STRUCT_DEF)
+#define gen_struct(id, params, body, loc)\
+ gen_str2(AST_STRUCT_DEF, id, params, body, loc)
-/**
- * Generate alias definition.
- *
- * @param id Name of alias.
- * @param type Type to alias.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type,
- struct src_loc loc);
+#define val_id(x) return_s(x, AST_VAL)
+#define val_val(x) return_a0(x, AST_VAL)
+#define gen_val(id, val, loc)\
+ gen_str1(AST_VAL, id, val, loc)
-/**
- * Generate trait definition.
- *
- * @param id Name of trait.
- * @param body Body.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_trait(struct ast_node *id, struct ast_node *params,
- struct ast_node *raw_body, struct ast_node *body,
- struct src_loc loc);
+#define switch_cond(x) return_a0(x, AST_SWITCH)
+#define switch_cases(x) return_a1(x, AST_SWITCH)
+#define gen_switch(cond, cases, loc)\
+ gen2(AST_SWITCH, cond, cases, loc)
-/**
- * Generate import;
- *
- * @param file File to import.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_import(const char *file, struct src_loc loc);
+#define case_cond(x) return_a0(x, AST_CASE)
+#define case_body(x) return_a1(x, AST_CASE)
+#define gen_case(cond, body, loc)\
+ gen2(AST_CASE, cond, body, loc)
-/**
- * Generate cast.
- *
- * @param expr Expression.
- * @param type Type to cast expression result to.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_cast(struct ast_node *expr, struct ast_node *type,
- struct src_loc loc);
+#define str_val(x) return_s(x, AST_CONST_STR)
+#define gen_const_str(s, loc)\
+ gen_ast(AST_CONST_STR, NULL, NULL, NULL, NULL, NULL, s, 0, loc)
-/**
- * Generate embed.
- *
- * @param file File to embed.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_embed(const char *file, struct src_loc loc);
+#define int_val(x) *({assert(x->k == AST_CONST_INT); &x->v;})
+#define gen_const_int(i, loc)\
+ gen_ast(AST_CONST_INT, NULL, NULL, NULL, NULL, NULL, NULL, i, loc)
-/**
- * Generate goto.
- *
- * @param label Name of label to jump to.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_goto(struct ast_node *label, struct src_loc loc);
+#define char_val(x) *({assert(x->k == AST_CONST_CHAR); &x->v;})
+#define gen_const_char(i, loc)\
+ gen_ast(AST_CONST_CHAR, NULL, NULL, NULL, NULL, NULL, NULL, i, loc)
-/**
- * Generate goto label.
- *
- * @param id Name of label.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_label(struct ast_node *id, struct src_loc loc);
+#define bool_val(x) *({assert(x->k == AST_CONST_CHAR); &x->v;})
+#define gen_const_bool(i, loc)\
+ gen_ast(AST_CONST_BOOL, NULL, NULL, NULL, NULL, NULL, NULL, i, loc)
-/**
- * Generate defer.
- *
- * @param expr Expression to defer.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_defer(struct ast_node *expr, struct src_loc loc);
+#define init_body(x) return_a0(x, AST_ASSIGN)
+#define gen_init(body, loc)\
+ gen1(AST_INIT, body, loc)
-/**
- * Generate as.
- *
- * @param type Type to resolve with.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_as(struct ast_node *type, struct src_loc loc);
+#define assign_to(x) return_a0(x, AST_ASSIGN)
+#define assign_from(x) return_a1(x, AST_ASSIGN)
+#define gen_assign(from, to, loc)\
+ gen2(AST_ASSIGN, from, to, loc)
-/**
- * Generate sizeof.
- *
- * @param expr Expression to take type of.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_sizeof(struct ast_node *expr, struct src_loc loc);
+#define id_str(x) return_s(x, AST_ID)
+#define gen_id(id, loc)\
+ gen_str(AST_ID, id, loc)
-/**
- * Generate structure definition.
- *
- * @param id Name of structure.
- * @param generics List of type parameters.
- * @param body Body of structure.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_struct(struct ast_node *id, struct ast_node *generics,
- struct ast_node *body, struct src_loc loc);
+#define gen_empty(loc)\
+ gen1(AST_EMPTY, NULL, loc)
-/**
- * Generate enum member fetch.
- *
- * @param id Name of enum member to fetch.
- * @param type Enum type to fetch from.
- * @return Corresponding AST node.
- */
-struct ast_node *gen_fetch(struct ast_node *id, struct ast_node *type,
- struct src_loc loc);
+/* types */
+#define callable_ptypes(x) return_t0(x, TYPE_CALLABLE)
+#define callable_rtype(x) return_t0(x, TYPE_CALLABLE)
+#define tgen_callable(ptypes, rtype, loc)\
+ tgen2(TYPE_CALLABLE, ptypes, rtype, loc)
-/**
- * Generate empty AST node.
- *
- * @return Corresponding AST node.
- */
-struct ast_node *gen_empty();
+#define ptr_base(x) return_t0(x, TYPE_PTR)
+#define tgen_ptr(base, loc)\
+ tgen1(TYPE_PTR, base, loc)
-/**
- * Clone AST node.
- *
- * @param node Node to clone.
- * @return A clone of \p node.
- */
-struct ast_node *clone_ast_node(struct ast_node *node);
+#define construct_id(x) return_t0(x, TYPE_CONSTRUCT)
+#define construct_atypes(x) return_t1(x, TYPE_CONSTRUCT)
+#define tgen_construct(id, atypes, loc)\
+ tgen_str1(TYPE_CONSTRUCT, id, atypes, loc)
-/**
- * Check if two nodes are identical.
- *
- * @param exact Ignore some less important checks, such as flags, location and
- * scope.
- * @param left One AST node to compare.
- * @param right Other AST node to compare.
- * @return \c 0 if nodes aren't identical, \c 1 otherwise.
- */
-int identical_ast_nodes(int exact, struct ast_node *left,
- struct ast_node *right);
+struct ast *clone_ast(struct ast *n);
+struct ast *clone_ast_list(struct ast *l);
-/**
- * Dump textual representation of AST to stdout.
- *
- * @param depth How many spaces to prepend.
- * @param root AST node to dump.
- */
-void dump_ast(int depth, struct ast_node *root);
-void dump_ast_node(int depth, struct ast_node *node);
+struct type *clone_type(struct type *n);
+struct type *clone_type_list(struct type *l);
-/**
- * Add \p elem to end of \p list.
- *
- * @param list List of AST nodes.
- * @param elem Add to end of \p list.
- */
-void ast_append(struct ast_node *list, struct ast_node *elem);
+void ast_dump_list(int depth, struct ast *root);
+void ast_dump(int depth, struct ast *node);
-/**
- * Set AST node flags.
- *
- * @param node Node to set flags for.
- * @param flags Flags to set.
- */
-void ast_set_flags(struct ast_node *node, enum ast_flag flags);
+void type_dump_list(struct type *root);
+void type_dump(struct type *node);
-/**
- * Clear AST node flags.
- *
- * @param node Node to clear flags for.
- * @param flags Flags to set.
- */
-void ast_clear_flags(struct ast_node *node, enum ast_flag flags);
+void ast_append(struct ast *list, struct ast *elem);
+void type_append(struct type *list, struct type *elem);
-/**
- * Check if \p node has \p flags set.
- * All flags have to be set.
- *
- * @param node Node to check flags for.
- * @param flags Flags to check.
- * @return \c 1 if all \p flags are set, \c 0 othewise.
- */
-unsigned ast_flags(struct ast_node *node, enum ast_flag flags);
+void ast_set_flags(struct ast *node, enum ast_flags flags);
+void ast_clear_flags(struct ast *node, enum ast_flags flags);
+unsigned ast_flags(struct ast *node, enum ast_flags flags);
-/**
- * Call external callback on all nodes in tree.
- *
- * @param call Callback to call.
- * @param node Node whose all subnodes should be passed to \p call.
- * @param data Extra data to pass to \p call.
- * @return Whatever \p call returns.
- */
-int ast_call_on(int (*call)(struct ast_node *, void *),
- struct ast_node *node, void *data);
+typedef int (*ast_callback_t)(struct ast *, void *);
+typedef int (*type_callback_t)(struct type *, void *);
+int ast_visit(ast_callback_t before, ast_callback_t after, struct ast *node, void *data);
+int ast_visit_list(ast_callback_t before, ast_callback_t after, struct ast *node, void *data);
-int ast_call_on_chain(int (*call)(struct ast_node *, void *),
- struct ast_node *node, void *data);
+int type_visit(type_callback_t before, type_callback_t after, struct type *node, void *data);
+int type_visit_list(type_callback_t before, type_callback_t after, struct type *node, void *data);
/**
* Number of elements in AST list.
@@ -1306,7 +658,7 @@ int ast_call_on_chain(int (*call)(struct ast_node *, void *),
* @param list List whose elements to count.
* @return Number of elements in \p list.
*/
-size_t ast_list_len(struct ast_node *list);
+size_t ast_list_len(struct ast *list);
/**
* Get last nose in ASt list.
@@ -1314,7 +666,7 @@ size_t ast_list_len(struct ast_node *list);
* @param list List whose last element to get.
* @return Last node in \p list.
*/
-struct ast_node *ast_last_node(struct ast_node *list);
+struct ast *ast_last(struct ast *list);
/**
* Get last element in block.
@@ -1322,16 +674,22 @@ struct ast_node *ast_last_node(struct ast_node *list);
* @param block Block whose last element to get.
* @return Last node in block.
*/
-struct ast_node *ast_block_last(struct ast_node *block);
+struct ast *ast_block_last(struct ast *block);
-void destroy_ast_nodes();
-const char *primitive_str(enum ast_primitive type);
+void destroy_allocs();
+const char *primitive_str(struct type *kind);
-int same_id(struct ast_node *id1, struct ast_node *id2);
-int equiv_nodes(struct ast_node *n1, struct ast_node *n2);
-int equiv_node_chains(struct ast_node *c1, struct ast_node *c2);
+int same_id(char *id1, char *id2);
+int equiv_nodes(struct ast *n1, struct ast *n2);
+int equiv_node_lists(struct ast *c1, struct ast *c2);
+
+int equiv_types(struct type *t1, struct type *t2);
+int equiv_type_lists(struct type *t1, struct type *t2);
#define foreach_node(iter, nodes) \
- for (struct ast_node *iter = nodes; iter; iter = iter->next)
+ for (struct ast *iter = nodes; iter; iter = iter->n)
+
+#define foreach_type(iter, nodes) \
+ for (struct type *iter = nodes; iter; iter = iter->n)
#endif /* AST_H */
diff --git a/include/ek/debug.h b/include/ek/debug.h
index 588fc6b..79cc1d1 100644
--- a/include/ek/debug.h
+++ b/include/ek/debug.h
@@ -65,15 +65,7 @@ struct file_ctx {
* @param type Type to generate string representation of.
* @return \p type as string.
*/
-char *type_str(struct ast_node *type);
-
-/**
- * Generate string representation of call.
- *
- * @param call Call to generate string representation of.
- * @return \p call as string.
- */
-char *call_str(struct ast_node *call);
+char *type_str(struct type *type);
/**
* Print info that relates to a specific AST node.
@@ -84,8 +76,8 @@ char *call_str(struct ast_node *call);
* @param node AST node to print message with.
* @param fmt Format string. Follows standard printf() formatting.
*/
-void semantic_info(struct file_ctx ctx, struct ast_node *node, const char *fmt,
- ...);
+void semantic_info(struct file_ctx ctx, struct ast *node, const char *fmt, ...);
+void type_info(struct file_ctx ctx, struct type *node, const char *fmt, ...);
/**
* Print warning that relates to a specific AST node.
@@ -100,7 +92,7 @@ void semantic_info(struct file_ctx ctx, struct ast_node *node, const char *fmt,
* @param node AST node to print message with.
* @param fmt Format string. Follows standard printf() formatting.
*/
-void semantic_warn(struct file_ctx ctx, struct ast_node *node, const char *fmt,
+void semantic_warn(struct file_ctx ctx, struct ast *node, const char *fmt,
...);
/**
@@ -111,8 +103,8 @@ void semantic_warn(struct file_ctx ctx, struct ast_node *node, const char *fmt,
* @param node AST node to print message with.
* @param fmt Format string. Follows standard printf() formatting.
*/
-void semantic_error(struct file_ctx ctx, struct ast_node *node, const char *fmt,
- ...);
+void semantic_error(struct file_ctx ctx, struct ast *node, const char *fmt, ...);
+void type_error(struct file_ctx ctx, struct type *type, const char *fmt, ...);
/**
* Print internal error.
diff --git a/include/ek/lower.h b/include/ek/lower.h
index af203d6..d635178 100644
--- a/include/ek/lower.h
+++ b/include/ek/lower.h
@@ -4,6 +4,6 @@
#include <ek/ast.h>
#include <stdio.h>
-int lower_actuals(struct scope *root);
+int lower(struct scope *root);
#endif /* EK_OPS_H */
diff --git a/include/ek/parser.h b/include/ek/parser.h
index c548f7f..49d9302 100644
--- a/include/ek/parser.h
+++ b/include/ek/parser.h
@@ -30,7 +30,7 @@ struct parser {
/** How deeply we've nested comments. */
size_t comment_nesting;
/** Raw AST. */
- struct ast_node *tree;
+ struct ast *tree;
};
/**
diff --git a/include/ek/scope.h b/include/ek/scope.h
index 4cef3a1..4858b55 100644
--- a/include/ek/scope.h
+++ b/include/ek/scope.h
@@ -34,9 +34,9 @@ enum scope_flags {
*/
struct visible {
/** Name of the visible node. */
- struct ast_node *id;
+ char *id;
/** AST node that is visible. */
- struct ast_node *node;
+ struct ast *node;
/** Next visible object in the scope we're in. */
struct visible *next;
};
@@ -44,15 +44,15 @@ struct visible {
/** Actualized nodes visible to scope. */
struct actual {
/** Actualized AST node. */
- struct ast_node *node;
+ struct ast *node;
/** Next actual node. */
struct actual *next;
};
-struct types {
- struct ast_node *id;
- struct ast_node *type;
- struct ast_node *next;
+struct type_defs {
+ char *id;
+ struct ast *type_def;
+ struct type_defs *next;
};
/**
@@ -160,7 +160,7 @@ void scope_destroy_defaults(struct scope *root);
* @param scratch Scratch node to add to \p scope.
* @return \c 0 when successful, non-zero otherwise.
*/
-int scope_add_scratch(struct scope *scope, struct ast_node *scratch);
+int scope_add_scratch(struct scope *scope, struct ast *scratch);
/**
* Set scope flags.
@@ -178,7 +178,7 @@ void scope_set_flags(struct scope *scope, enum scope_flags flags);
* @return \c 1 if flags are set, \c 0 if flags are unset.
* @note All flags have to be set for the result to be \c 1.
*/
-int scope_flags(struct scope *scope, enum scope_flags flags);
+unsigned scope_flags(struct scope *scope, enum scope_flags flags);
/**
* Add child scope to \p parent.
@@ -196,7 +196,7 @@ void scope_add_scope(struct scope *parent, struct scope *child);
* @param node Actualized AST node.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_actual(struct scope *scope, struct ast_node *node);
+int scope_add_actual(struct scope *scope, struct ast *node);
/**
* Add variable to scope.
@@ -206,7 +206,7 @@ int scope_add_actual(struct scope *scope, struct ast_node *node);
* @param var Variable to add to scope.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_var(struct scope *scope, struct ast_node *var);
+int scope_add_var(struct scope *scope, struct ast *var);
/**
* Add type to scope.
@@ -216,8 +216,7 @@ 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, char *id, struct ast *type);
/**
* Add procedure to scope.
@@ -227,7 +226,7 @@ int scope_add_type(struct scope *scope, struct ast_node *id,
* @param proc Procedure to add to scope.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_proc(struct scope *scope, struct ast_node *proc);
+int scope_add_proc(struct scope *scope, struct ast *proc);
/**
* Add macro to scope.
@@ -237,7 +236,7 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc);
* @param macro Macro to add to scope.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_macro(struct scope *scope, struct ast_node *macro);
+int scope_add_macro(struct scope *scope, struct ast *macro);
/**
* Add template to scope.
@@ -247,7 +246,7 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro);
* @param type_template Template to add to scope.
* @return \c 0 when succesful, non-zero otherwise.
*/
-int scope_add_trait(struct scope *scope, struct ast_node *trait);
+int scope_add_trait(struct scope *scope, struct ast *trait);
int scope_resolve(struct scope *scope);
@@ -261,7 +260,7 @@ int scope_resolve(struct scope *scope);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_var(struct scope *scope, struct ast_node *id);
+struct ast *scope_find_var(struct scope *scope, char *id);
/**
* Find a type with ID in \p scope.
@@ -273,7 +272,7 @@ struct ast_node *scope_find_var(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_type(struct scope *scope, struct ast_node *id);
+struct ast *scope_find_type(struct scope *scope, char *id);
/**
* Find a procedure with ID in \p scope.
@@ -285,7 +284,7 @@ struct ast_node *scope_find_type(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_proc(struct scope *scope, struct ast_node *id);
+struct ast *scope_find_proc(struct scope *scope, char *id);
/**
* Find a macro with ID in \p scope.
@@ -297,7 +296,7 @@ struct ast_node *scope_find_proc(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_macro(struct scope *scope, struct ast_node *id);
+struct ast *scope_find_macro(struct scope *scope, char *id);
/**
* Find an alias with ID in \p scope.
@@ -309,7 +308,7 @@ struct ast_node *scope_find_macro(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_alias(struct scope *scope, struct ast_node *id);
+struct ast *scope_find_alias(struct scope *scope, char *id);
/**
* Find a template with ID in \p scope.
@@ -321,7 +320,7 @@ struct ast_node *scope_find_alias(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *scope_find_trait(struct scope *scope, struct ast_node *id);
+struct ast *scope_find_trait(struct scope *scope, char *id);
/**
* Find a variable with ID visible to \p scope.
@@ -331,7 +330,7 @@ struct ast_node *scope_find_trait(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *id);
+struct ast *file_scope_find_var(struct scope *scope, char *id);
/**
* Find a type with ID visible to \p scope.
@@ -341,7 +340,7 @@ struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_type(struct scope *scope, struct ast_node *id);
+struct ast *file_scope_find_type(struct scope *scope, char *id);
/**
* Find a procedure with ID visible to \p scope.
@@ -351,7 +350,7 @@ struct ast_node *file_scope_find_type(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_proc(struct scope *scope, struct ast_node *id);
+struct ast *file_scope_find_proc(struct scope *scope, char *id);
/**
* Find a macro with ID visible to \p scope.
@@ -361,8 +360,7 @@ struct ast_node *file_scope_find_proc(struct scope *scope, struct ast_node *id);
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_macro(struct scope *scope,
- struct ast_node *id);
+struct ast *file_scope_find_macro(struct scope *scope, char *id);
/**
* Find a alias with ID visible to \p scope.
*
@@ -371,8 +369,7 @@ struct ast_node *file_scope_find_macro(struct scope *scope,
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_alias(struct scope *scope,
- struct ast_node *id);
+struct ast *file_scope_find_alias(struct scope *scope, char *id);
/**
* Find a template with ID visible to \p scope.
@@ -382,7 +379,9 @@ struct ast_node *file_scope_find_alias(struct scope *scope,
* @return Pointer to the AST node corresponding to \p id if found,
* otherwise \c NULL.
*/
-struct ast_node *file_scope_find_trait(struct scope *scope,
- struct ast_node *id);
+struct ast *file_scope_find_trait(struct scope *scope, char *id);
+
+#define foreach_visible(iter, init)\
+ for (struct visible *iter = init; iter; iter = iter->next)
#endif /* SCOPE_H */
diff --git a/include/ek/vec.h b/include/ek/vec.h
index 8d5cae1..d9048fe 100644
--- a/include/ek/vec.h
+++ b/include/ek/vec.h
@@ -35,4 +35,7 @@ void vec_append(struct vec *v, void *n);
#define vect_pop(type, v) \
*(type *)vec_pop(&v)
+#define vec_uninit(v) \
+ (v.buf == NULL)
+
#endif /* VEC_H */
diff --git a/src/actualize.c b/src/actualize.c
index 744dc1a..6d85640 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -18,11 +18,8 @@
#define UNUSED(x) do { (void)(x); } while (0)
-static int replace_type_id(struct ast_node *nodes, struct ast_node *id,
- struct ast_node *replacement);
-
struct act_stack {
- struct ast_node *node;
+ struct ast *node;
struct act_stack *next;
};
@@ -35,23 +32,36 @@ enum act_flags {
struct act_state {
enum act_flags flags;
- struct ast_node *last_var;
- struct ast_node *cur_trait;
- struct ast_node *cur_proc;
+ struct ast *cur_proc;
struct act_stack *defer_stack;
struct act_stack *goto_stack;
struct act_stack *label_stack;
};
-static int is_lvalue(struct ast_node *n)
+static int replace_type_id(struct ast *nodes, char *id,
+ struct type *replacement);
+
+static int actualize(struct act_state *state, struct scope *scope,
+ struct ast *node);
+
+static int actualize_list(struct act_state *state, struct scope *scope,
+ struct ast *l);
+
+static int actualize_type(struct act_state *state, struct scope *scope,
+ struct type *node);
+
+static int actualize_type_list(struct act_state *state, struct scope *scope,
+ struct type *node);
+
+static int is_lvalue(struct ast *n)
{
- if (n->node_type == AST_ARR_ACCESS)
+ if (n->k == AST_ARR)
return 1;
- if (n->node_type == AST_ID)
+ if (n->k == AST_ID)
return 1;
- if (n->node_type == AST_UNOP && AST_UNOP(n).op == AST_DEREF)
+ if (n->k == AST_DEREF)
return 1;
return 0;
@@ -68,85 +78,65 @@ static enum act_flags act_flags(struct act_state *state, enum act_flags flags)
return state->flags & flags;
}
-/* TODO: this could be improved if we get a global void thing */
-static int is_void(struct ast_node *type)
+static bool is_void(struct type *t)
{
- assert(type->node_type == AST_TYPE);
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE)
- return 0;
+ /* missing return is void */
+ if (!t)
+ return 1;
- return AST_PRIMITIVE_TYPE(type).type == AST_VOID;
+ return t->k == TYPE_VOID;
}
-static struct ast_node *void_type()
+static struct type *void_type()
{
- struct ast_node *v = gen_primitive(AST_VOID, NULL, NULL_LOC());
- ast_set_flags(v, AST_FLAG_INIT | AST_FLAG_ACTUAL);
- v->type = v;
- return v;
+ return tgen_primitive(TYPE_VOID, strdup("void"), NULL, NULL_LOC());
}
-static struct ast_node *i27_type(struct scope *scope)
+static struct type *i27_type(struct scope *scope)
{
- struct ast_node *i27 = gen_id(strdup("i27"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, i27);
+ struct ast *def = file_scope_find_type(scope, "i27");
if (!def) {
error("missing definition of type 'i27'");
return NULL;
}
- struct ast_node *a = gen_primitive(AST_I27, def, def->loc);
- ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_I27, strdup("i27"), def, def->loc);
}
-static struct ast_node *i9_type(struct scope *scope)
+static struct type *i9_type(struct scope *scope)
{
- struct ast_node *i27 = gen_id(strdup("i9"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, i27);
+ struct ast *def = file_scope_find_type(scope, "i9");
if (!def) {
error("missing definition of type 'i9'");
return NULL;
}
- struct ast_node *a = gen_primitive(AST_I9, def, def->loc);
- ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_I9, strdup("i9"), def, def->loc);
}
-static struct ast_node *str_type(struct scope *scope)
+static struct type *str_type(struct scope *scope)
{
- struct ast_node *str = gen_id(strdup("str"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, str);
+ struct ast *def = file_scope_find_type(scope, "str");
if (!def) {
error("missing definition of type 'str'");
return NULL;
}
- struct ast_node *a = gen_primitive(AST_STR, def, def->loc);
- ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_STR, strdup("str"), def, def->loc);
}
-static struct ast_node *bool_type(struct scope *scope)
+static struct type *bool_type(struct scope *scope)
{
- struct ast_node *b = gen_id(strdup("bool"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, b);
+ struct ast *def = file_scope_find_type(scope, "bool");
if (!def) {
error("missing definition of type 'bool'");
return NULL;
}
- struct ast_node *a = gen_primitive(AST_BOOL, def, def->loc);
- ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_BOOL, strdup("bool"), def, def->loc);
}
-static int push_defer(struct act_state *state, struct ast_node *expr)
+static int push_defer(struct act_state *state, struct ast *expr)
{
struct act_stack *new = calloc(1, sizeof(struct act_stack));
if (!new) {
@@ -160,7 +150,7 @@ static int push_defer(struct act_state *state, struct ast_node *expr)
return 0;
}
-static int push_label(struct act_state *state, struct ast_node *label)
+static int push_label(struct act_state *state, struct ast *label)
{
struct act_stack *new = calloc(1, sizeof(struct act_stack));
if (!new) {
@@ -174,23 +164,20 @@ static int push_label(struct act_state *state, struct ast_node *label)
return 0;
}
-static struct ast_node *find_label(struct act_state *state,
- struct ast_node *label)
+static struct ast *find_label(struct act_state *state, char *label)
{
- assert(label->node_type == AST_LABEL);
struct act_stack *prev = state->label_stack, *cur;
if (prev)
do {
cur = prev->next;
- if (same_id(AST_LABEL(prev->node).id,
- AST_LABEL(label).id))
+ if (same_id(label_id(prev->node), label))
return prev->node;
} while ((prev = cur));
return NULL;
}
-static int push_goto(struct act_state *state, struct ast_node *got)
+static int push_goto(struct act_state *state, struct ast *got)
{
struct act_stack *new = calloc(1, sizeof(struct act_stack));
if (!new) {
@@ -204,17 +191,17 @@ static int push_goto(struct act_state *state, struct ast_node *got)
return 0;
}
-static struct ast_node *clone_defers(struct act_state *state,
+static struct ast *clone_defers(struct act_state *state,
struct act_stack *to)
{
struct act_stack *from = state->defer_stack;
/* maintain reverse order */
- struct ast_node *defers = NULL, *prev = NULL;
+ struct ast *defers = NULL, *prev = NULL;
while (from != to) {
- struct ast_node *defer = clone_ast_node(from->node);
+ struct ast *defer = clone_ast(from->node);
if (prev)
- prev->next = defer;
+ prev->n = defer;
if (!defers)
defers = defer;
@@ -263,130 +250,78 @@ static void destroy_act_state(struct act_state *state)
clear_gotos(state, NULL);
}
-static int actualize(struct act_state *state, struct scope *scope,
- struct ast_node *node);
-static int analyze(struct scope *scope, struct ast_node *tree);
+static void type_mismatch(struct scope *scope, struct ast *node, struct type *a, struct type *b)
+{
+ char *left_type = type_str(a);
+ char *right_type = type_str(b);
+ semantic_error(scope->fctx, node,
+ "type mismatch: %s vs %s",
+ left_type, right_type);
+ free(left_type);
+ free(right_type);
+}
+
+static int analyze(struct scope *scope, struct ast *tree);
-static int eval_const_if(struct scope *scope, struct ast_node *node)
+static int eval_const_if(struct scope *scope, struct ast *node)
{
assert(node
- && node->node_type == AST_IF
+ && node->k == AST_IF
&& ast_flags(node, AST_FLAG_CONST));
- int eval = 0;
- struct ast_node *cond = node->_if.cond;
- struct ast_node *next = node->next;
-
- switch (cond->node_type) {
- /* for now just check if the variable exists, might change in
- * the future */
- case AST_ID: eval = file_scope_find_var(scope, cond) != NULL;
- break;
- default: semantic_error(scope->fctx, node,
- "const if conditional at file scope unimplemented");
- return -1;
- }
-
- if (eval) {
- /* condition evaluated true, so keep the if block */
- struct ast_node *body = node->_if.body;
- ast_last_node(body)->next = node->next;
-
- /* an if must have a body, otherwise the parser messed up */
- assert(body);
-
- *node = *body;
- free(body);
- return 0;
- }
-
- struct ast_node *els = node->_if.els;
- if (els) {
- *node = *els;
- ast_last_node(els)->next = next;
- free(els);
- return 0;
- }
-
- if (next) {
- /* copy the next node into our place */
- *node = *next;
- free(next);
- return 0;
- }
-
- free(node);
- return 0;
+ semantic_error(scope->fctx, node,
+ "const if unimplemented");
+ return -1;
}
-static int analyze_visibility(struct scope *scope, struct ast_node *node)
+static int analyze_visibility(struct scope *scope, struct ast *node)
{
if (!node)
return 0;
- int ret = 0;
node->scope = scope;
- /* TODO: add error checking */
- switch (node->node_type) {
- case AST_PROC: {
- ret |= scope_add_proc(scope, node);
- break;
- }
-
- case AST_VAR: {
- ret |= scope_add_var(scope, node);
- break;
- }
+ switch (node->k) {
+ case AST_PROC_DEF: return scope_add_proc(scope, node);
+ case AST_MACRO_DEF: return scope_add_macro(scope, node);
+ case AST_VAR_DEF: return scope_add_var(scope, node);
case AST_IMPORT: {
- const char *file = AST_IMPORT(node).file;
- ret |= process_file(&scope,
+ const char *file = import_file(node);
+ return process_file(&scope,
(int)ast_flags(node, AST_FLAG_PUBLIC),
file);
- break;
}
case AST_IF: {
assert(ast_flags(node, AST_FLAG_CONST));
- ret |= eval_const_if(scope, node);
- if (ret)
+ if (eval_const_if(scope, node))
return -1;
/* since a const if likely replaced the current node with
* something else, we have to analyze the replacement */
- ret = analyze(scope, node);
- break;
+ return analyze(scope, node);
}
- case AST_STRUCT: {
+ case AST_STRUCT_DEF: {
/* we shouldn't get any anonymous structs at this stage */
- struct ast_node *id = AST_STRUCT(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
+ char *id = struct_id(node);
+ return scope_add_type(scope, id, node);
}
- case AST_ENUM: {
- struct ast_node *id = AST_ENUM(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
+ case AST_ENUM_DEF: {
+ char *id = enum_id(node);
+ return scope_add_type(scope, id, node);
}
- case AST_ALIAS: {
- struct ast_node *id = AST_ALIAS(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
+ case AST_ALIAS_DEF: {
+ char *id = alias_id(node);
+ return scope_add_type(scope, id, node);
}
- case AST_TRAIT: {
- struct ast_node *id = AST_TRAIT(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
- }
-
- case AST_MACRO_CONSTRUCT: {
- ret |= scope_add_macro(scope, node);
- break;
+ case AST_TRAIT_DEF: {
+ char *id = trait_id(node);
+ return scope_add_type(scope, id, node);
}
case AST_EMPTY: {
@@ -394,145 +329,188 @@ static int analyze_visibility(struct scope *scope, struct ast_node *node)
}
default:
- ret = -1;
semantic_error(scope->fctx, node, "unknown top element");
- break;
+ return -1;
};
- return ret;
+ return 0;
}
-static int analyze_var(struct scope *scope, struct ast_node *node)
+static int analyze_var(struct scope *scope, struct ast *node)
{
struct act_state state = {0};
return actualize(&state, scope, node);
}
-static void set_type(struct ast_node *node, struct ast_node *type)
+static void set_type(struct ast *node, struct type *type)
+{
+ node->t = clone_type_list(type);
+}
+
+static void replace_type(struct type *t, struct type *r)
{
- assert(type->node_type == AST_TYPE);
- node->type = clone_ast_node(type);
+ /* free strings before they get overwritten */
+ if (t->id)
+ free(t->id);
+
+ struct src_loc loc = t->loc;
+ struct scope *scope = t->scope;
+
+ *t = *r;
+
+ /* clone so we don't accidentally free same string twice later */
+ if (t->id)
+ t->id = strdup(t->id);
+
+ /* these things we generally don't want to replace */
+ t->loc = loc;
+ t->scope = scope;
}
-static int analyze_proc(struct scope *scope, struct ast_node *node)
+static void replace_ast(struct ast *n, struct ast *t)
{
- /* not sure if this is the best place for this */
- AST_PROC(node).id->scope = scope;
+ if (n->s)
+ free(n->s);
+
+ struct src_loc loc = n->loc;
+ struct scope *scope = n->scope;
+ *n = *t;
+
+ if (n->s)
+ n->s = strdup(n->s);
+
+ n->loc = loc;
+ t->scope = scope;
+}
+
+static int analyze_proc(struct scope *scope, struct ast *node)
+{
struct scope *proc_scope = create_scope();
scope_add_scope(scope, proc_scope);
node->scope = proc_scope;
- struct ast_node *sign = AST_PROC(node).sign;
-
+ struct ast *params = proc_params(node);
struct act_state state = {0};
- int ret = actualize(&state, proc_scope, sign);
- set_type(node, sign);
- return ret;
+ if (actualize_list(&state, proc_scope, params))
+ return -1;
+
+ struct type *rtype = proc_rtype(node);
+
+ if (actualize_type_list(&state, proc_scope, rtype))
+ return -1;
+
+ if (!rtype)
+ proc_rtype(node) = void_type();
+
+ struct type *callable = tgen_callable(NULL, proc_rtype(node), node->loc);
+ foreach_node(p, params) {
+ /* we must manually 'start' the chain **/
+ if (!callable_ptypes(callable)) {
+ callable_ptypes(callable) = clone_type(p->t);
+ continue;
+ }
+
+ type_append(callable_ptypes(callable), p->t);
+ }
+
+ set_type(node, callable);
+ return 0;
}
-static struct ast_node *analyze_type_expand(struct scope *scope,
- struct ast_node *n)
+static struct ast *analyze_type_expand(struct scope *scope,
+ struct ast *n)
{
- assert(n->node_type == AST_TYPE_EXPAND);
- struct ast_node *trait = file_scope_find_type(scope,
- AST_TYPE_EXPAND(n).id);
+ assert(n->k == AST_TYPE_EXPAND);
+ struct ast *trait = file_scope_find_type(scope, type_expand_id(n));
if (!trait) {
semantic_error(scope->fctx, n, "no such type");
return NULL;
}
- if (trait->node_type != AST_TRAIT) {
+ if (trait->k != AST_TRAIT_DEF) {
semantic_error(scope->fctx, n, "not a trait");
return NULL;
}
semantic_info(scope->fctx, n,
"FIXME: skipping type param check for now");
- struct ast_node *body = AST_TRAIT(trait).raw_body;
- body = clone_ast_node(body);
+ struct ast *body = trait_raw_body(trait);
+ body = clone_ast(body);
- struct ast_node *pa = AST_TYPE_EXPAND(n).args;
- foreach_node(pt, AST_TRAIT(trait).params) {
- replace_type_id(body, AST_VAR(pt).id, pa);
- pa = pa->next;
+ struct type *pa = type_expand_args(n);
+ foreach_node(pt, trait_params(trait)) {
+ replace_type_id(body, var_id(pt), pa);
+ pa = pa->n;
}
return body;
}
-static int implements_trait(struct ast_node *body, struct ast_node *id)
+static int implements_trait(struct ast *body, char *id)
{
foreach_node(n, body) {
- if (n->node_type != AST_ID)
+ /* traits don't currently take generic parameters I guess? */
+ if (n->k != AST_ID)
continue;
- if (same_id(n, id))
+ if (same_id(id_str(n), id))
return 1;
}
return 0;
}
-static void mark_implemented(struct ast_node *n)
-{
- assert(n->node_type == AST_TYPE_EXPAND);
- /** @todo very hacky but good enough for now */
- struct ast_node *id = AST_TYPE_EXPAND(n).id;
- n->node_type = AST_ID;
- AST_ID(n).id = strdup(AST_ID(id).id);
-}
-
-static int analyze_struct(struct scope *scope, struct ast_node *node)
+static int analyze_struct(struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_STRUCT);
- struct ast_node *generics = AST_STRUCT(node).generics;
+ assert(node->k == AST_STRUCT_DEF);
+ struct ast *params = struct_params(node);
struct scope *struct_scope = create_scope();
if (!struct_scope)
return -1;
scope_add_scope(node->scope, struct_scope);
node->scope = struct_scope;
- if (generics)
+ if (params)
ast_set_flags(node, AST_FLAG_GENERIC);
- struct ast_node *type = gen_type(AST_TYPE_STRUCT, node, NULL,
- node->loc);
+ struct type *type = tgen_type(TYPE_STRUCT,
+ NULL, NULL,
+ node, NULL,
+ strdup(struct_id(node)),
+ node->loc);
- foreach_node(n, AST_STRUCT(node).body) {
- if (n->node_type != AST_TYPE_EXPAND)
+ foreach_node(n, struct_body(node)) {
+ if (n->k != AST_TYPE_EXPAND)
continue;
- if (implements_trait(AST_STRUCT(node).body,
- AST_TYPE_EXPAND(n).id)) {
- n->node_type = AST_EMPTY;
+ if (implements_trait(struct_body(node), type_expand_id(n))) {
+ n->k = AST_EMPTY;
continue;
}
- if (same_id(AST_STRUCT(node).id, AST_TYPE_EXPAND(n).id)) {
+ if (same_id(struct_id(node), type_expand_id(n))) {
semantic_error(scope->fctx, n,
"recursive trait implementations not allowed");
return -1;
}
- struct ast_node *body = analyze_type_expand(scope, n);
+ struct ast *body = analyze_type_expand(scope, n);
if (!body) {
- n->node_type = AST_EMPTY;
+ n->k = AST_EMPTY;
continue;
}
- replace_type_id(body, AST_TYPE_EXPAND(n).id, type);
- ast_block_last(body)->next = n->next;
- n->next = body;
-
- mark_implemented(n);
+ replace_type_id(body, type_expand_id(n), type);
+ ast_block_last(body)->n = n->n;
+ n->n = body;
}
- foreach_node(n, AST_STRUCT(node).body) {
- switch (n->node_type) {
+ foreach_node(n, struct_body(node)) {
+ switch (n->k) {
case AST_EMPTY: continue;
case AST_ID: continue;
/* prototypes are checked later */
- case AST_PROC: if (!AST_PROC(n).body) continue;
+ case AST_PROC_DEF: if (!proc_body(n)) continue;
default:
}
@@ -540,9 +518,9 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
return -1;
}
- foreach_node(n, AST_STRUCT(node).body) {
+ foreach_node(n, struct_body(node)) {
/* also checks prototypes */
- if (n->node_type != AST_PROC)
+ if (n->k != AST_PROC_DEF)
continue;
if (analyze_proc(struct_scope, n))
@@ -550,38 +528,47 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
}
/* check that all prototypes are implemented */
- foreach_node(n, AST_STRUCT(node).body) {
- if (n->node_type != AST_PROC)
+ foreach_node(n, struct_body(node)) {
+ if (n->k != AST_PROC_DEF)
continue;
- if (AST_PROC(n).body)
+ if (proc_body(n))
continue;
- struct ast_node *proc = scope_find_proc(struct_scope,
- AST_PROC(n).id);
+ struct ast *proc = scope_find_proc(struct_scope, proc_id(n));
if (!proc) {
semantic_error(scope->fctx, n,
"missing implementation");
return -1;
}
- if (!equiv_nodes(AST_PROC(n).sign, AST_PROC(proc).sign)) {
+ if (!types_match(n->t, proc->t)) {
semantic_error(scope->fctx, n, "mismatched signatures");
semantic_info(scope->fctx, proc, "note: here");
return -1;
}
}
+ char *id = strdup(struct_id(node));
+ if (same_id(id, "i27"))
+ node->t = tgen_primitive(TYPE_I27, id, node, node->loc);
+ else if (same_id(id, "i9"))
+ node->t = tgen_primitive(TYPE_I9, id, node, node->loc);
+ else if (same_id(id, "bool"))
+ node->t = tgen_primitive(TYPE_BOOL, id, node, node->loc);
+ else
+ node->t = tgen_struct(id, node, node->loc);
+
/** @todo there is the possibility that two different traits add the
* same prototype, which is reported in traits but not structs? */
return 0;
}
/* quite a lot of overlap with analyze_struct, kind of ugly I guess */
-static int analyze_trait(struct scope *scope, struct ast_node *node)
+static int analyze_trait(struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_TRAIT);
- struct ast_node *generics = AST_TRAIT(node).params;
+ assert(node->k == AST_TRAIT_DEF);
+ struct ast *params = trait_params(node);
struct scope *trait_scope = create_scope();
if (!trait_scope)
return -1;
@@ -589,54 +576,55 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
scope_add_scope(node->scope, trait_scope);
node->scope = trait_scope;
/** @todo should probably add in aliases for the traits in scope? */
- if (generics)
+ if (params)
ast_set_flags(node, AST_FLAG_GENERIC);
- struct ast_node *type = gen_type(AST_TYPE_TRAIT, node, NULL, node->loc);
+ struct type *type = tgen_type(TYPE_TRAIT, NULL, NULL,
+ node, NULL, strdup(trait_id(node)),
+ node->loc);
+
+ /* copy body */
+ node->a2 = clone_ast(trait_raw_body(node));
- AST_TRAIT(node).body = clone_ast_node(AST_TRAIT(node).raw_body);
/* do type expansions */
- foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_TYPE_EXPAND)
+ foreach_node(n, trait_body(node)) {
+ if (n->k != AST_TYPE_EXPAND)
continue;
/* don't re-expand already implemented traits */
- if (implements_trait(AST_TRAIT(node).body,
- AST_TYPE_EXPAND(n).id)) {
+ if (implements_trait(trait_body(node), type_expand_id(n))) {
/* not sure about this, but at least we don't have stray
* type expands everywhere */
- n->node_type = AST_EMPTY;
+ n->k = AST_EMPTY;
continue;
}
- if (same_id(AST_TRAIT(node).id, AST_TYPE_EXPAND(n).id)) {
+ if (same_id(trait_id(node), type_expand_id(n))) {
semantic_error(scope->fctx, n,
"recursive trait implementations not allowed");
return -1;
}
- struct ast_node *body = analyze_type_expand(scope, n);
+ struct ast *body = analyze_type_expand(scope, n);
if (!body) {
- n->node_type = AST_EMPTY;
+ n->k = AST_EMPTY;
continue;
}
- replace_type_id(body, AST_TYPE_EXPAND(n).id, type);
- ast_last_node(body)->next = n->next;
- n->next = body;
-
- mark_implemented(n);
+ replace_type_id(body, type_expand_id(n), type);
+ ast_last(body)->n = n->n;
+ n->n = body;
}
/* add all procedure definitions to scope */
- foreach_node(n, AST_TRAIT(node).body) {
+ foreach_node(n, trait_body(node)) {
/* kind of a hack but these shouldn't be shown to
* analyze_visibility */
- switch (n->node_type) {
+ switch (n->k) {
case AST_EMPTY: continue;
case AST_ID: continue;
/* prototypes are added later */
- case AST_PROC: if (!AST_PROC(n).body) continue;
+ case AST_PROC_DEF: if (!proc_body(n)) continue;
default:
}
@@ -649,47 +637,49 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
* would be. Add a prototypes -list to scopes? */
/* add all prototypes that don't have matching definition to scope */
- foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_PROC)
+ foreach_node(n, trait_body(node)) {
+ if (n->k != AST_PROC_DEF)
continue;
- if (AST_PROC(n).body)
+ if (proc_body(n))
continue;
/* prototypes are checked only if there's no implementation */
- if (scope_find_proc(trait_scope, AST_PROC(n).id))
+ if (scope_find_proc(trait_scope, proc_id(n)))
continue;
if (analyze_visibility(trait_scope, n))
return -1;
}
- foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_PROC)
+ foreach_node(n, trait_body(node)) {
+ if (n->k != AST_PROC_DEF)
continue;
if (analyze_proc(trait_scope, n))
return -1;
}
+ node->t = tgen_trait(strdup(struct_id(node)), node, node->loc);
+
return 0;
}
-static int analyze_signs(struct scope *scope, struct ast_node *node)
+static int analyze_signs(struct scope *scope, struct ast *node)
{
/** @todo aliases? */
- switch (node->node_type) {
- case AST_VAR: return analyze_var(scope, node); break;
- case AST_PROC: return analyze_proc(scope, node); break;
- case AST_STRUCT: return analyze_struct(scope, node); break;
- case AST_TRAIT: return analyze_trait(scope, node); break;
+ switch (node->k) {
+ case AST_VAR_DEF: return analyze_var(scope, node); break;
+ case AST_PROC_DEF: return analyze_proc(scope, node); break;
+ case AST_STRUCT_DEF: return analyze_struct(scope, node); break;
+ case AST_TRAIT_DEF: return analyze_trait(scope, node); break;
default:
}
return 0;
}
-static int analyze(struct scope *scope, struct ast_node *tree)
+static int analyze(struct scope *scope, struct ast *tree)
{
foreach_node(node, tree) {
if (analyze_visibility(scope, node))
@@ -707,13 +697,13 @@ static int analyze(struct scope *scope, struct ast_node *tree)
return -1;
printf("//actualized:\n");
- dump_ast_node(0, node);
+ ast_dump(0, node);
}
return 0;
}
-int analyze_root(struct scope *scope, struct ast_node *tree)
+int analyze_root(struct scope *scope, struct ast *tree)
{
if (analyze(scope, tree))
return -1;
@@ -721,22 +711,13 @@ int analyze_root(struct scope *scope, struct ast_node *tree)
return 0;
}
-static int structs_match(struct ast_node *a, struct ast_node *b)
+static int structs_match(struct type *a, struct type *b)
{
- /** @todo: iterate over elements in structure */
- /** @todo: check tag as well? */
- return 0;
+ /* dunno, let's go with this for now */
+ return a->d == b->d;
}
-static int primitives_match(struct ast_node *a, struct ast_node *b)
-{
- enum ast_primitive at = AST_PRIMITIVE_TYPE(a).type;
- enum ast_primitive bt = AST_PRIMITIVE_TYPE(b).type;
-
- return at == bt;
-}
-
-int types_match(struct ast_node *a, struct ast_node *b)
+int types_match(struct type *a, struct type *b)
{
if (!a && !b)
return 1;
@@ -744,111 +725,85 @@ int types_match(struct ast_node *a, struct ast_node *b)
if (!a || !b)
return 0;
- assert(a->node_type == AST_TYPE);
- assert(b->node_type == AST_TYPE);
-
/* if the type kind doesn't match, we're done. */
- if (AST_TYPE(a).kind != AST_TYPE(b).kind)
+ if (a->k != b->k)
return 0;
- if (AST_TYPE(a).kind == AST_TYPE_STRUCT)
+ if (a->k == TYPE_STRUCT)
return structs_match(a, b);
- if (AST_TYPE(a).kind == AST_TYPE_POINTER)
- return types_match(AST_PTR_TYPE(a).base,
- AST_PTR_TYPE(b).base);
-
- if (AST_TYPE(a).kind == AST_TYPE_PRIMITIVE)
- return primitives_match(a, b);
+ if (a->k == TYPE_PTR)
+ return types_match(ptr_base(a), ptr_base(b));
- return 0;
+ return 1;
}
-static int _replace_id(struct ast_node *node, void *data)
+static int _replace_id(struct ast *node, void *data)
{
if (!node)
return 0;
- if (node->node_type != AST_ID)
- return ast_call_on(_replace_id, node, data);
+ if (node->k != AST_ID)
+ return 0;
- struct ast_node **pair = data;
- struct ast_node *id = pair[0];
- struct ast_node *expr = pair[1];
+ struct ast **pair = data;
+ struct ast *id = pair[0];
+ struct ast *expr = pair[1];
- if (!same_id(node, id))
- return ast_call_on(_replace_id, node, data);
+ /* no match, continue */
+ if (!same_id(id_str(node), id_str(id)))
+ return 0;
- struct ast_node *clone = clone_ast_node(expr);
+ struct ast *clone = clone_ast(expr);
if (!clone) {
internal_error("failed cloning replacement expr");
return -1;
}
- clone->next = node->next;
+ clone->n = node->n;
clone->scope = node->scope;
- *node = *clone;
+ replace_ast(node, clone);
/* a succesful replacement needs no futher replacements, I think */
return 0;
}
-static int replace_id(struct ast_node *body, struct ast_node *id,
- struct ast_node *expr)
+static int replace_id(struct ast *body, struct ast *id,
+ struct ast *expr)
{
- struct ast_node *pair[2] = {id, expr};
- return ast_call_on(_replace_id, body, pair);
+ struct ast *pair[2] = {id, expr};
+ return ast_visit(_replace_id, NULL, body, pair);
}
-static int actualize_macro_construct(struct act_state *state,
- struct scope *scope, struct ast_node *n)
+static int actualize_macro_def(struct act_state *state,
+ struct scope *scope, struct ast *n)
{
UNUSED(state);
/* macro bodies, arguments, etc aren't expanded upon until the macro is
* called, so just try to add it to the local scope */
- assert(n && n->node_type == AST_MACRO_CONSTRUCT);
+ assert(n && n->k == AST_MACRO_DEF);
return scope_add_macro(scope, n);
}
-struct ast_node *extract_trait(struct ast_node *type)
-{
- if (!type)
- return 0;
-
- assert(type->node_type == AST_TYPE);
- if (type->_type.kind == AST_TYPE_TRAIT)
- return type;
-
- return extract_trait(type->_type.next);
-}
-
-static void actualize_trait_types(struct ast_node *params,
- struct ast_node *args)
-{
- /** @todo replace trait types with arg types, should probably be merged
- * */
- assert(!args && !params);
-}
-
static int actualize_macro_expand(struct act_state *state,
struct scope *scope,
- struct ast_node *macro_expand)
+ struct ast *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_find_macro(scope, id);
+ assert(macro_expand->k == AST_MACRO_EXPAND);
+ char *id = macro_expand_id(macro_expand);
+ struct ast *macro = file_scope_find_macro(scope, id);
if (!macro) {
semantic_error(scope->fctx, macro_expand, "no such macro");
return -1;
}
- assert(macro->node_type == AST_MACRO_CONSTRUCT);
+ assert(macro->k == AST_MACRO_DEF);
if (ast_flags(macro, AST_FLAG_VARIADIC)) {
semantic_error(scope->fctx, macro,
"variadic macros not yet implemented");
return -1;
}
- struct ast_node *body = clone_ast_node(AST_MACRO_CONSTRUCT(macro).body);
+ struct ast *body = clone_ast(macro_def_body(macro));
if (!body) {
internal_error("failed allocating body for macro expansion");
return -1;
@@ -856,63 +811,79 @@ static int actualize_macro_expand(struct act_state *state,
/** @todo update all macro IDs to the correct scope */
body->scope = macro_expand->scope;
- body->next = macro_expand->next;
+ body->n = macro_expand->n;
- struct ast_node *param = AST_MACRO_CONSTRUCT(macro).params;
- struct ast_node *arg = AST_MACRO_EXPAND(macro_expand).args;
+ struct ast *param = macro_def_params(macro);
+ struct ast *arg = macro_expand_args(macro_expand);
- /* TODO: actual replacements */
while (param && arg) {
/* feels slightly hacky, but essentially replace each individual
* component in the arg list by breaking it out of the list
* temporarily. After the replacement, insert it back into the
* list so the cleanup is easier. */
- struct ast_node *next_arg = arg->next;
- arg->next = NULL;
+ struct ast *next_arg = arg->n;
+ arg->n = NULL;
if (replace_id(body, param, arg)) {
semantic_error(scope->fctx, macro_expand,
"failed replacing params with args");
- arg->next = next_arg;
+ arg->n = next_arg;
return -1;
}
- param = param->next;
- arg = arg->next = next_arg;
+ param = param->n;
+ arg = arg->n = next_arg;
}
+ free(macro_expand_id(macro_expand));
*macro_expand = *body;
/* actualize the new content */
return actualize(state, scope, macro_expand);
}
static int actualize_call(struct act_state *state,
- struct scope *scope, struct ast_node *call)
+ struct scope *scope, struct ast *call)
{
- assert(call && call->node_type == AST_CALL);
+ assert(call && call->k == AST_CALL);
- /* check that arguments exist, make sure they have types etc. */
- /* TODO: procedure callbacks? */
- int ret = actualize(state, scope, AST_CALL(call).args);
- if (ret)
- return ret;
+ if (actualize_list(state, scope, call_args(call)))
+ return -1;
- ret = actualize(state, scope, AST_CALL(call).expr);
- if (ret)
- return ret;
+ if (actualize_list(state, scope, call_expr(call)))
+ return -1;
- semantic_info(scope->fctx, call, "FIXME: skipping type checks for now");
- struct ast_node *expr = AST_CALL(call).expr;
- if (AST_TYPE(expr->type).kind != AST_TYPE_SIGN) {
- char *tstr = type_str(expr->type);
- semantic_info(scope->fctx, call, "not a callable type: %s",
+ struct ast *expr = call_expr(call);
+ if (expr->t->k != TYPE_CALLABLE) {
+ char *tstr = type_str(expr->t);
+ semantic_error(scope->fctx, call, "not a callable type: %s",
tstr);
free(tstr);
return -1;
}
- struct ast_node *sign = expr->type;
- set_type(call, AST_SIGN_TYPE(sign).ret);
+ struct type *callable = expr->t;
+ struct type *ptypes = callable_ptypes(callable);
+ struct ast *arg = call_args(call);
+ foreach_type(p, ptypes) {
+ if (!arg) {
+ semantic_error(scope->fctx, call, "too many arguments");
+ return -1;
+ }
+
+ if (!types_match(p, arg->t)) {
+ type_mismatch(scope, arg, p, arg->t);
+ return -1;
+ }
+
+ arg = arg->n;
+ }
+
+ if (arg) {
+ semantic_error(scope->fctx, arg, "too many arguments");
+ return -1;
+ }
+
+ set_type(call, callable_rtype(callable));
return 0;
}
@@ -923,7 +894,7 @@ static void warn_unused_labels(struct act_state *state, struct scope *scope)
return;
do {
- struct ast_node *label = labels->node;
+ struct ast *label = labels->node;
if (!ast_flags(label, AST_FLAG_ACTUAL))
semantic_warn(scope->fctx, label,
"unused label");
@@ -939,7 +910,7 @@ static int undefined_gotos(struct act_state *state, struct scope *scope)
return ret;
do {
- struct ast_node *got = gotos->node;
+ struct ast *got = gotos->node;
if (!ast_flags(got, AST_FLAG_ACTUAL)) {
semantic_warn(scope->fctx, got,
"undefined label");
@@ -952,39 +923,35 @@ static int undefined_gotos(struct act_state *state, struct scope *scope)
}
static int actualize_proc(struct act_state *state,
- struct scope *scope, struct ast_node *proc)
+ struct scope *scope, struct ast *proc)
{
+ UNUSED(state);
/* actualize_proc is called on trait procs as well, but I believe
* that's fine? */
- assert(proc && proc->node_type == AST_PROC);
- struct ast_node *sign = AST_PROC(proc).sign;
+ assert(proc && proc->k == AST_PROC_DEF);
- /* signature should already be typed etc. */
struct act_state new_state = {0};
- if (actualize(&new_state, proc->scope, sign))
- return -1;
-
- set_type(proc, sign);
+ /* params should already have been actualized, should maybe check */
/* actualize body */
new_state.cur_proc = proc;
- if (actualize(&new_state, proc->scope, AST_PROC(proc).body))
+ if (actualize(&new_state, proc->scope, proc_body(proc)))
return -1;
if (!act_flags(&new_state, ACT_HAS_RETURN)) {
- if (!is_void(AST_SIGN_TYPE(sign).ret)) {
+ if (!is_void(proc_rtype(proc))) {
semantic_error(scope->fctx, proc,
"no return with non-void return type");
return -1;
}
/* add 'implicit' return */
- struct ast_node *body = AST_PROC(proc).body;
- struct ast_node *r = gen_return(NULL, NULL_LOC());
+ struct ast *body = proc_body(proc);
+ struct ast *r = gen_return(NULL, NULL, NULL_LOC());
r->scope = body->scope;
- ast_append(AST_BLOCK(body).body, r);
+ ast_append(block_body(body), r);
}
- else if (ast_block_last(AST_PROC(proc).body)->node_type != AST_RETURN) {
+ else if (ast_block_last(proc_body(proc))->k != AST_RETURN) {
/* TODO: something more sophisticated than this */
semantic_warn(scope->fctx, proc,
"unable to determine explicit return for all branches");
@@ -996,63 +963,41 @@ static int actualize_proc(struct act_state *state,
return -1;
/* if we're main, don't mangle the entry point */
- struct ast_node *id = AST_PROC(proc).id;
- if (strcmp("main", AST_ID(id).id) == 0)
- ast_set_flags(id, AST_FLAG_NOMANGLE);
+ char *id = proc_id(proc);
+ if (strcmp("main", id) == 0)
+ ast_set_flags(proc, AST_FLAG_NOMANGLE);
/* we have successfully actualized the procedure */
return 0;
}
static int actualize_binop(struct act_state *state,
- struct scope *scope, struct ast_node *binop)
+ struct scope *scope, struct ast *binop)
{
- assert(binop && binop->node_type == AST_BINOP);
+ assert(binop && is_binop(binop));
- struct ast_node *left = AST_BINOP(binop).left;
- struct ast_node *right = AST_BINOP(binop).right;
-
- int ret = 0;
- ret |= actualize(state, scope, left);
- ret |= actualize(state, scope, right);
- if (ret)
- return ret;
+ struct ast *left = binop_left(binop);
+ struct ast *right = binop_right(binop);
- if (!left->type) {
- semantic_error(scope->fctx, binop,
- "unable to detect lefthand type");
+ if (actualize(state, scope, left))
return -1;
- }
- if (!right->type) {
- semantic_error(scope->fctx, binop,
- "unable to detect righthand type");
+ if (actualize(state, scope, right))
return -1;
- }
- if (!types_match(left->type, right->type)) {
- char *left_type = type_str(left);
- char *right_type = type_str(right);
- semantic_error(scope->fctx, binop,
- "type mismatch (%s vs %s)", left_type,
- right_type);
- free(left_type);
- free(right_type);
+ if (!types_match(left->t, right->t)) {
+ type_mismatch(scope, binop, left->t, right->t);
return -1;
}
- /* TODO: also check trait types, just because two traits collapse
- * to the same actual type doesn't mean that the two trait types
- * should be allowed to operate on eachother */
-
/* types are the same, so the type of this expression is whichever */
- set_type(binop, left->type);
+ set_type(binop, left->t);
return 0;
}
static int actualize_block(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
struct scope *block_scope = scope;
if (!ast_flags(node, AST_FLAG_UNHYGIENIC)) {
@@ -1066,20 +1011,21 @@ static int actualize_block(struct act_state *state,
}
struct act_stack *defers = state->defer_stack;
- foreach_node(pt, node->_block.body) {
+ foreach_node(pt, block_body(node)) {
if (actualize(state, block_scope, pt))
return -1;
}
- if (node->_block.body == NULL) {
- node->type = void_type();
- node->_block.body = gen_empty();
+ if (block_body(node) == NULL) {
+ node->t = void_type();
+ /* still not a huge fan of directly mucking about with ast slots */
+ block_body(node) = gen_empty(NULL_LOC());
return 0;
}
/* the block type is the last statement in the block's type */
- set_type(node, ast_last_node(node->_block.body)->type);
- if (!node->type) {
+ set_type(node, ast_last(block_body(node))->t);
+ if (!node->t) {
semantic_error(scope->fctx, node,
"unable to detect block type");
return -1;
@@ -1088,8 +1034,8 @@ static int actualize_block(struct act_state *state,
/* TODO: currently defers are sort of duplicated after a return, unsure
* if they should be handled here or somewhere else */
if (state->defer_stack) {
- node->_block.defers = clone_defers(state, defers);
- if (!node->_block.defers) {
+ block_defers(node) = clone_defers(state, defers);
+ if (!block_defers(node)) {
internal_error("failed cloning defers");
return -1;
}
@@ -1101,10 +1047,10 @@ static int actualize_block(struct act_state *state,
}
static int actualize_id(struct act_state *state,
- struct scope *scope, struct ast_node *id)
+ struct scope *scope, struct ast *id)
{
UNUSED(state);
- assert(id && id->node_type == AST_ID);
+ assert(id && id->k == AST_ID);
id->scope = scope;
/** @todo vars and procs kind of override eachother, i.e.
@@ -1119,16 +1065,16 @@ static int actualize_id(struct act_state *state,
* Either add in some syntax to distinguish procedure calls and
* pointer calls or make procs and vars share the same namespace.
* */
- struct ast_node *decl = file_scope_find_var(scope, id);
+ struct ast *decl = file_scope_find_var(scope, id_str(id));
if (decl) {
- set_type(id, decl->type);
+ set_type(id, decl->t);
decl->uses++;
return 0;
}
- decl = file_scope_find_proc(scope, id);
+ decl = file_scope_find_proc(scope, id_str(id));
if (decl) {
- set_type(id, decl->type);
+ set_type(id, decl->t);
decl->uses++;
return 0;
}
@@ -1138,320 +1084,268 @@ static int actualize_id(struct act_state *state,
}
static int actualize_var(struct act_state *state,
- struct scope *scope, struct ast_node *var)
+ struct scope *scope, struct ast *var)
{
- assert(var && var->node_type == AST_VAR);
- struct ast_node *init = AST_VAR(var).init;
- struct ast_node *type = AST_VAR(var).type;
+ assert(var && var->k == AST_VAR_DEF);
+ struct ast *init = var_init(var);
+ struct type *type = var_type(var);
/* one of these must be defined, otherwise the parser fucked up */
assert(type || init);
- if (init && actualize(state, scope, init))
+ if (init && actualize_list(state, scope, init))
return -1;
- if (type && actualize(state, scope, type))
+ if (type && actualize_type_list(state, scope, type))
return -1;
- if (init && init->node_type == AST_INIT) {
- assert(!init->type);
+ if (init && init->k == AST_INIT) {
+ assert(!init->t);
set_type(init, type);
/* TODO: some kind of check_init() */
}
if (init && type) {
/* make sure the asked type and the actualized types match */
- if (!types_match(init->type, type)) {
- char *init_type = type_str(init->type);
- char *req_type = type_str(type);
- semantic_error(scope->fctx, var,
- "type mismatch (%s vs %s)",
- req_type, init_type);
- free(init_type);
- free(req_type);
+ if (!types_match(init->t, type)) {
+ type_mismatch(scope, var, init->t, type);
return -1;
}
}
- /* this is important for lowering */
- AST_VAR(var).id->scope = scope;
var->scope = scope;
if (init)
/* infer */
- set_type(var, init->type);
+ set_type(var, init->t);
if (type)
- /* TODO: should there be some default value? */
+ /* TODO: should there be some default zero value? */
/* declare */
set_type(var, type);
/* an unnamed var is a var in a signature that should not produce a
* warning on not being used (if I ever get around to adding those kinds
* of warnings) */
- if (AST_VAR(var).id && !ast_flags(var, AST_FLAG_MEMBER))
+ if (var_id(var) && !ast_flags(var, AST_FLAG_MEMBER))
return scope_add_var(scope, var);
- /* TODO: we should make sure the type is fully qualified in bodies */
return 0;
}
-#define ENTER_ACT() \
- enum act_flags old_flags = state->flags; \
- struct ast_node *old_trait = state->cur_trait;
-
-#define EXIT_ACT(r) \
- do { \
- state->cur_trait = old_trait; \
- state->flags = old_flags; \
- return r; \
- } while (0);
-
-static enum ast_primitive id_to_primitive(struct ast_node *id)
+static int actualize_tid(struct act_state *state, struct scope *scope, struct type *t)
{
- const char *name = AST_ID(id).id;
- if (strcmp(name, "i27") == 0)
- return AST_I27;
+ UNUSED(state);
- if (strcmp(name, "i9") == 0)
- return AST_I9;
+ /* no id means void */
+ if (!t->id) {
+ replace_type(t, void_type());
+ return 0;
+ }
- if (strcmp(name, "bool") == 0)
- return AST_BOOL;
+ struct src_loc l = t->loc;
- /** @todo some better error reporting should probably be used */
- internal_error( "illegal primitive: %s\n", name);
- return AST_VOID;
-}
+ struct ast *def = file_scope_find_type(scope, t->id);
+ if (!def) {
+ type_error(scope->fctx, t, "no such type");
+ return -1;
+ }
-static int struct_is_primitive(struct ast_node *s)
-{
- struct ast_node *id = AST_STRUCT(s).id;
- const char *name = AST_ID(id).id;
- if (strcmp(name, "i27") == 0)
- return 1;
+ assert(t->n == NULL);
+ assert(def->k != AST_TRAIT_DEF);
- if (strcmp(name, "i9") == 0)
- return 1;
+ if (def->k == AST_ALIAS_DEF) {
+ replace_type(t, clone_type_list(def->t));
+ t->a = def;
+ return 0;
+ }
+ else if (def->k == AST_STRUCT_DEF) {
+ replace_type(t, clone_type_list(def->t));
+ return 0;
+ }
+ else if (def->k == AST_ENUM_DEF) {
+ replace_type(t, clone_type_list(def->t));
+ return 0;
+ }
- if (strcmp(name, "bool") == 0)
- return 1;
+ return -1;
+}
- /* special case of a special case?
- if (strcmp(name, "str"))
- return 1;
- */
+static int actualize_ptr(struct act_state *state, struct scope *scope, struct type *t)
+{
+ assert(ptr_base(t));
+ if (actualize_type(state, scope, ptr_base(t)))
+ return -1;
return 0;
}
-static int actualize_type(struct act_state *state,
- struct scope *scope, struct ast_node *type)
+static int actualize_callable(struct act_state *state, struct scope *scope, struct type *t)
{
- /* TODO: there's gotta be a better way to handle flags. Maybe macros
- * like ENTER_ACTUALIZE and EXIT_ACTUALIZE? */
- /* TODO: get rid of aliases, expand implements, fill out structures,
- * etc. */
- assert(type->node_type == AST_TYPE);
- ENTER_ACT();
+ struct type *ptypes = callable_ptypes(t);
+ struct type *rtype = callable_rtype(t);
- if (actualize(state, scope, AST_TYPE(type).next)) {
- EXIT_ACT(-1);
+ foreach_type(p, ptypes){
+ if (actualize_type(state, scope, p))
+ return -1;
}
- switch (AST_TYPE(type).kind) {
- case AST_TYPE_ID: {
- /* type IDs can really only be aliases to something else, or if
- * 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());
- }
-
- 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);
- }
+ if (!rtype)
+ callable_rtype(t) = void_type();
- if (exists->node_type == AST_TYPE) {
- assert(AST_TYPE(exists).kind == AST_TYPE_PRIMITIVE);
- AST_TYPE(type) = AST_TYPE(exists);
- break;
- }
+ if (actualize_type(state, scope, rtype))
+ return -1;
- /*
- if (actualize(state, exists->scope, exists))
- EXIT_ACT(-1);
- */
+ return 0;
+}
- assert(AST_TYPE(type).next == NULL);
- if (exists->node_type == AST_ALIAS) {
- AST_TYPE(type).aliased = exists;
- AST_TYPE(type) = AST_TYPE(exists);
- }
- else if (exists->node_type == AST_TRAIT) {
- /* this is kind of weird, have to think about it */
- *type = *gen_type(AST_TYPE_TRAIT, exists,
- NULL, exists->loc);
- }
- else if (exists->node_type == AST_STRUCT) {
- if (struct_is_primitive(exists)) {
- *type = *gen_primitive(
- id_to_primitive(AST_STRUCT(exists).id),
- exists,
- exists->loc);
- } else {
- *type = *gen_type(AST_TYPE_STRUCT, exists,
- NULL, exists->loc);
- }
- }
- else if (exists->node_type == AST_ENUM) {
- *type = *gen_type(AST_TYPE_ENUM, exists,
- NULL, exists->loc);
- }
+static int actualize_i27(struct act_state *state, struct scope *scope, struct type *t)
+{
+ /* not much to do */
+ if (t->d)
+ return 0;
- break;
+ struct ast *def = file_scope_find_type(scope, "i27");
+ if (!def) {
+ error("missing definition of type 'i27'");
+ return NULL;
}
- case AST_TYPE_CONSTRUCT:
- /** @todo fully qualified constructs should be added to the
- * actual list for code generation */
- semantic_info(scope->fctx, type,
- "constructs unimplemented, continuing with compilation to see what breaks");
- break;
+ t->d = def;
+ return 0;
+}
- 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;
+static int actualize_i9(struct act_state *state, struct scope *scope, struct type *t)
+{
+ /* not much to do */
+ if (t->d)
+ return 0;
- case AST_TYPE_POINTER:
- assert(AST_PTR_TYPE(type).base);
- if (actualize(state, scope, AST_PTR_TYPE(type).base))
- EXIT_ACT(-1);
- break;
+ struct ast *def = file_scope_find_type(scope, "i9");
+ if (!def) {
+ error("missing definition of type 'i9'");
+ return NULL;
+ }
- case AST_TYPE_SIGN: {
- struct ast_node *params = AST_SIGN_TYPE(type).params;
- struct ast_node *ret = AST_SIGN_TYPE(type).ret;
+ t->d = def;
+ return 0;
+}
- foreach_node(p, params){
- if (actualize(state, scope, p))
- EXIT_ACT(-1);
- }
+static int actualize_bool(struct act_state *state, struct scope *scope, struct type *t)
+{
+ /* not much to do */
+ if (t->d)
+ return 0;
- if (!ret)
- ret = AST_SIGN_TYPE(type).ret = void_type();
+ struct ast *def = file_scope_find_type(scope, "bool");
+ if (!def) {
+ error("missing definition of type 'bool'");
+ return NULL;
+ }
- if (actualize(state, scope, ret))
- EXIT_ACT(-1);
+ t->d = def;
+ return 0;
+}
- break;
- }
+static int actualize_type(struct act_state *state,
+ struct scope *scope,
+ struct type *t)
+{
+ if (!t)
+ return 0;
- case AST_TYPE_TRAIT: {
- assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type,
- "FIXME skipping trait type checks");
- break;
- }
+ t->scope = scope;
- case AST_TYPE_STRUCT: {
- assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type,
- "FIXME skipping struct type checks");
- break;
- }
+ if (actualize_type(state, scope, t->n))
+ return -1;
- case AST_TYPE_PRIMITIVE: {
- assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type,
- "FIXME skipping primitive type checks");
- break;
- }
+ switch (t->k) {
+ case TYPE_I27: return actualize_i27(state, scope, t);
+ case TYPE_I9: return actualize_i9(state, scope, t);
+ case TYPE_BOOL: return actualize_bool(state, scope, t);
+ case TYPE_ID: return actualize_tid(state, scope, t);
+ case TYPE_PTR: return actualize_ptr(state, scope, t);
+ case TYPE_CALLABLE: return actualize_callable(state, scope, t);
+ case TYPE_VOID: return 0; /* void is by default actualized */
default:
- semantic_error(scope->fctx, type, "unimplemented type");
- EXIT_ACT(-1);
+ type_info(scope->fctx, t,
+ "unimplemented type");
+ type_info(scope->fctx, t,
+ "continuing with compilation to see what breaks");
+ return 0;
}
- /* generally speaking */
- EXIT_ACT(0);
+ return 0;
}
-static int actualize_empty(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+static int actualize_type_list(struct act_state *state,
+ struct scope *scope,
+ struct type *l)
{
- UNUSED(state);
- /* TODO: converting to void is common enough that it might be worth
- * creating a function for */
- struct ast_node *void_id = gen_id(strdup("void"), NULL_LOC());
- if (!void_id) {
- internal_error(
- "couldn't allocate type id for empty statement\n");
- return -1;
- }
-
- 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;
+ foreach_type(t, l) {
+ if (actualize_type(state, scope, t))
+ return -1;
}
return 0;
}
-static int integral_type(struct ast_node *type)
+static int actualize_empty(struct act_state *state,
+ struct scope *scope, struct ast *node)
{
- assert(type->node_type == AST_TYPE);
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE)
- return 0;
+ UNUSED(state);
+ UNUSED(scope);
+ node->t = void_type();
+ return 0;
+}
- /* here would be awesome with an enum of our base types */
- enum ast_primitive p = AST_PRIMITIVE_TYPE(type).type;
- switch (p) {
- case AST_I9: return 1;
- case AST_I27: return 1;
- default: return 0;
+static int integral_type(struct type *type)
+{
+ switch (type->k) {
+ case TYPE_I27:
+ case TYPE_I9:
+ case TYPE_BOOL:
+ return true; /* maybe? */
+ default:
}
- return 0;
+ return false;
}
-static int pointer_type(struct ast_node *type)
+static int pointer_type(struct type *type)
{
- assert(type->node_type == AST_TYPE);
- return type->_type.kind == AST_TYPE_POINTER;
+ return type->k == TYPE_PTR;
}
-static int pointer_conversion(struct ast_node *a, struct ast_node *b)
+static int pointer_conversion(struct type *a, struct type *b)
{
- assert(a->node_type == AST_TYPE);
- assert(b->node_type == AST_TYPE);
if (pointer_type(a)) {
- if (AST_TYPE(b).kind != AST_TYPE_PRIMITIVE)
+ if (!is_primitive(b))
return 0;
/* for now */
- return AST_PRIMITIVE_TYPE(b).type == AST_I27;
+ return b->k == TYPE_I27;
}
return 0;
}
-static size_t member_count(struct ast_node *exists)
+static size_t member_count(struct ast *exists)
{
- assert(exists->node_type == AST_STRUCT);
- struct ast_node *body = exists->_struct.body;
- return ast_list_len(body);
+ assert(exists->k == AST_STRUCT_DEF);
+ struct ast *body = struct_body(exists);
+
+ size_t count = 0;
+ foreach_node(n, body) {
+ if (n->k == AST_VAR_DEF)
+ count++;
+ }
+
+ return count;
}
-static struct ast_node *lookup_member_idx(struct ast_node *body,
- struct ast_node *find,
+static struct ast *lookup_member_idx(struct ast *body,
+ char *find,
size_t *idx)
{
/* micro-optimisation, likely way premature but speeds up selection
@@ -1459,27 +1353,26 @@ static struct ast_node *lookup_member_idx(struct ast_node *body,
(void)(find);
assert(idx);
size_t i = *idx;
- struct ast_node *m = body;
+ struct ast *m = body;
while (i != 0 && m) {
- m = m->next;
+ m = m->n;
i--;
}
return m;
}
-static struct ast_node *lookup_member_name(struct ast_node *body,
- struct ast_node *find,
+static struct ast *lookup_member_name(struct ast *body,
+ char *find,
size_t *idx)
{
- assert(find->node_type == AST_ID);
size_t i = 0;
- struct ast_node *m = body;
+ struct ast *m = body;
while (m) {
- assert(m->node_type == AST_VAR);
- if (same_id(find, AST_VAR(m).id))
+ assert(m->k == AST_VAR_DEF);
+ if (same_id(find, var_id(m)))
break;
- m = m->next;
+ m = m->n;
i++;
}
@@ -1489,25 +1382,25 @@ static struct ast_node *lookup_member_name(struct ast_node *body,
return m;
}
-static struct ast_node *lookup_struct_member(struct ast_node *struc,
- struct ast_node *find, size_t *idx)
+static struct ast *lookup_struct_member(struct ast *struc,
+ char *find, size_t *idx)
{
if (find)
- return lookup_member_name(struc->_struct.body, find, idx);
+ return lookup_member_name(struct_body(struc), find, idx);
- return lookup_member_idx(struc->_struct.body, find, idx);
+ return lookup_member_idx(struct_body(struc), find, idx);
}
-static struct ast_node *lookup_enum_member(struct ast_node *enu,
- struct ast_node *find)
+static struct ast *lookup_enum_member(struct ast *enu,
+ char *find)
{
size_t i = 0;
- struct ast_node *m = enu->_enum.body;
+ struct ast *m = enum_body(enu);
while (m) {
- assert(m->node_type == AST_VAL);
- if (same_id(find, AST_VAL(m).id))
+ assert(m->k == AST_VAL);
+ if (same_id(find, val_id(m)))
break;
- m = m->next;
+ m = m->n;
i++;
}
@@ -1515,7 +1408,7 @@ static struct ast_node *lookup_enum_member(struct ast_node *enu,
}
static int init_struct(struct act_state *state, struct scope *scope,
- struct ast_node *exists, struct ast_node *init)
+ struct ast *exists, struct ast *init)
{
size_t i = 0;
size_t mcount = member_count(exists);
@@ -1527,7 +1420,7 @@ static int init_struct(struct act_state *state, struct scope *scope,
return -1;
}
- struct ast_node *args = init->_init.body;
+ struct ast *args = init_body(init);
while (args) {
if (i >= mcount) {
semantic_error(scope->fctx, args,
@@ -1546,15 +1439,15 @@ static int init_struct(struct act_state *state, struct scope *scope,
if ((ret = actualize(state, scope, args)))
break;
- struct ast_node *find = NULL;
+ char *find = NULL;
if (ast_flags(args, AST_FLAG_MEMBER))
- find = args->_var.id;
+ find = var_id(args);
- struct ast_node *member =
+ struct ast *member =
lookup_struct_member(exists, find, &i);
if (!member) {
- char *sstr = type_str(exists->type);
+ char *sstr = type_str(exists->t);
semantic_error(scope->fctx, args,
"no such member in %s",
sstr);
@@ -1563,9 +1456,9 @@ static int init_struct(struct act_state *state, struct scope *scope,
break;
}
- if (!types_match(args->type, member->type)) {
- char *astr = type_str(args->type);
- char *mstr = type_str(member->type);
+ if (!types_match(args->t, member->t)) {
+ char *astr = type_str(args->t);
+ char *mstr = type_str(member->t);
semantic_error(scope->fctx, args,
"%s does not match %s", astr, mstr);
free(astr);
@@ -1575,7 +1468,7 @@ static int init_struct(struct act_state *state, struct scope *scope,
}
initd[i] = 1;
- args = args->next;
+ args = args->n;
i++;
}
@@ -1585,108 +1478,70 @@ static int init_struct(struct act_state *state, struct scope *scope,
static int actualize_struct_init_cast(struct act_state *state,
struct scope *scope,
- struct ast_node *init,
- struct ast_node *actual)
+ struct ast *init,
+ struct type *type)
{
- struct ast_node *def = AST_STRUCT_TYPE(actual).def;
+ struct ast *def = type->d;
return init_struct(state, scope, def, init);
}
static int actualize_init_cast(struct act_state *state,
- struct scope *scope, struct ast_node *init,
- struct ast_node *type)
+ struct scope *scope, struct ast *init,
+ struct type *type)
{
- if (AST_TYPE(type).kind == AST_TYPE_STRUCT)
+ if (type->k == TYPE_STRUCT)
return actualize_struct_init_cast(state, scope, init, type);
- semantic_error(scope->fctx, type,
+ type_error(scope->fctx, type,
"type is not a struct");
return -1;
}
-static int proc_pointer(struct ast_node *type)
-{
- if (type->_type.kind != AST_TYPE_POINTER)
- return 0;
-
- struct ast_node *next = type->_type.next;
- if (next->_type.kind != AST_TYPE_SIGN)
- return 0;
-
- return 1;
-}
-
-static int proc_choice(struct ast_node *expr, struct ast_node *type)
-{
- if (expr->node_type != AST_ID)
- return 0;
-
- if (!proc_pointer(type))
- return 0;
-
- return 1;
-}
-
-/* still slightly unsure about this, but hey ho */
-static int match_proc(struct act_state *state, struct scope *scope,
- struct ast_node *cast)
-{
- (void)(state);
- semantic_error(scope->fctx, cast,
- "procedure signature casts not yet implemented");
- return -1;
-}
-
static int actualize_cast(struct act_state *state,
- struct scope *scope, struct ast_node *cast)
+ struct scope *scope, struct ast *cast)
{
- assert(cast->node_type == AST_CAST);
- struct ast_node *expr = cast->_cast.expr;
- struct ast_node *type = cast->_cast.type;
+ assert(cast->k == AST_CAST);
+ struct ast *expr = cast_expr(cast);
+ struct type *type = cast_type(cast);
- if (actualize(state, scope, type))
+ if (actualize_type(state, scope, type))
return -1;
- if (proc_choice(expr, type)) {
- set_type(cast, type);
- return match_proc(state, scope, cast);
- }
-
if (actualize(state, scope, expr))
return -1;
- if (expr->node_type == AST_INIT) {
+ if (expr->k == AST_INIT) {
set_type(cast, type);
return actualize_init_cast(state, scope, expr, type);
}
- if (types_match(expr->type, type)) {
+ if (types_match(expr->t, type)) {
set_type(cast, type);
return 0;
}
- if (integral_type(expr->type) && integral_type(type)) {
+ if (integral_type(expr->t) && integral_type(type)) {
set_type(cast, type);
return 0;
}
- if (pointer_type(expr->type) && pointer_type(type)) {
+ if (pointer_type(expr->t) && pointer_type(type)) {
set_type(cast, type);
return 0;
}
- if (pointer_conversion(expr->type, type)
- || pointer_conversion(type, expr->type)) {
+ if (pointer_conversion(expr->t, type)
+ || pointer_conversion(type, expr->t)) {
set_type(cast, type);
return 0;
}
/* TODO: arrays? */
- char *left_type = type_str(expr);
+ char *left_type = type_str(expr->t);
char *right_type = type_str(type);
- semantic_error(scope->fctx, cast, "illegal cast (%s vs %s)",
+ semantic_error(scope->fctx, cast, "illegal cast: %s vs %s",
left_type, right_type);
free(left_type);
free(right_type);
@@ -1694,17 +1549,22 @@ static int actualize_cast(struct act_state *state,
}
static int actualize_const(struct act_state *state, struct scope *scope,
- struct ast_node *cons)
+ struct ast *cons)
{
UNUSED(state);
- assert(cons->node_type == AST_CONST);
- if (AST_CONST(cons).kind == AST_CONST_INTEGER)
- cons->type = i27_type(scope);
+ if (cons->k == AST_CONST_INT)
+ cons->t = i27_type(scope);
+
+ else if (cons->k == AST_CONST_CHAR)
+ cons->t = i9_type(scope);
- else if (AST_CONST(cons).kind == AST_CONST_STRING)
- cons->type = str_type(scope);
+ else if (cons->k == AST_CONST_BOOL)
+ cons->t = bool_type(scope);
- if (cons->type)
+ else if (cons->k == AST_CONST_STR)
+ cons->t = str_type(scope);
+
+ if (cons->t)
return 0;
semantic_error(scope->fctx, cons, "unimplemented constant");
@@ -1712,13 +1572,13 @@ static int actualize_const(struct act_state *state, struct scope *scope,
}
static int actualize_alias(struct act_state *state, struct scope *scope,
- struct ast_node *alias)
+ struct ast *alias)
{
/* I shall have to think about things, as currently very deeply nested
* aliases might be a bit cumbersome to work with. Still, this works
* well enough I suppose. */
- assert(alias->node_type == AST_ALIAS);
- if (actualize(state, scope, AST_ALIAS(alias).type)) {
+ assert(alias->k == AST_ALIAS_DEF);
+ if (actualize_type(state, scope, alias_type(alias))) {
/* usually we don't want to output errors upon errors, but this
* is likely a useful message as it might show where a loop is
* occuring */
@@ -1731,9 +1591,9 @@ static int actualize_alias(struct act_state *state, struct scope *scope,
}
static int actualize_defer(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- struct ast_node *expr = node->_defer.expr;
+ struct ast *expr = defer_expr(node);
/* TODO: should the actualization only happen when the defers are
* called? */
if (actualize(state, scope, expr))
@@ -1742,61 +1602,54 @@ static int actualize_defer(struct act_state *state,
if (push_defer(state, expr))
return -1;
- node->type = void_type();
+ node->t = void_type();
return 0;
}
static int actualize_return(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
act_set_flags(state, ACT_HAS_RETURN);
- struct ast_node *expr = node->_return.expr;
+ struct ast *expr = return_expr(node);
if (expr) {
if (actualize(state, scope, expr))
return -1;
- set_type(node, expr->type);
+ set_type(node, expr->t);
}
else {
- node->type = void_type();
+ node->t = void_type();
}
assert(state->cur_proc);
- struct ast_node *cur_proc = state->cur_proc;
- struct ast_node *sign = AST_PROC(cur_proc).sign;
- struct ast_node *ret = AST_SIGN_TYPE(sign).ret;
- if (!types_match(node->type, ret)) {
- char *rt = type_str(ret);
- char *et = type_str(node);
- semantic_error(scope->fctx, node,
- "return type mismatch: %s", et);
-
- semantic_info(scope->fctx, ret,
- "vs %s", rt);
- free(rt);
- free(et);
+ struct ast *cur_proc = state->cur_proc;
+ struct type *rtype = proc_rtype(cur_proc);
+ if (!types_match(node->t, rtype)) {
+ /* hmm, should this be "return type mismatch? */
+ type_mismatch(scope, node, rtype, node->t);
return -1;
}
if (state->defer_stack) {
- AST_RETURN(node).defers = clone_defers(state, NULL);
- if (!node->_return.defers) {
+ return_defers(node) = clone_defers(state, NULL);
+ if (!return_defers(node)) {
internal_error("failed cloning return defers");
return -1;
}
}
+
return 0;
}
/* Still slightly unsure if this works in all cases, but a good start
* nonetheless. */
-static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
+static void actualize_goto_defer(struct ast *got, struct ast *label)
{
- struct ast_node *goto_defers = AST_GOTO(got).defers;
- struct ast_node *label_defers = AST_LABEL(label).defers;
+ struct ast *goto_defers = goto_defers(got);
+ struct ast *label_defers = label_defers(label);
/* since we're dealing with singly linked lists, keep a reference to one
* node before the current goto defer. */
- struct ast_node *prev_defer = NULL;
+ struct ast *prev_defer = NULL;
/* this goto has a defined label */
ast_set_flags(got, AST_FLAG_ACTUAL);
@@ -1808,12 +1661,12 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
/* find first common defer statement */
while (goto_len > label_len) {
prev_defer = goto_defers;
- goto_defers = goto_defers->next;
+ goto_defers = goto_defers->n;
goto_len--;
}
while (label_len > goto_len) {
- label_defers = label_defers->next;
+ label_defers = label_defers->n;
label_len--;
}
@@ -1823,15 +1676,15 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
* unlikely that goto stuff would be a major bottleneck. */
while (!equiv_nodes(goto_defers, label_defers)) {
prev_defer = goto_defers;
- label_defers = label_defers->next;
- goto_defers = goto_defers->next;
+ label_defers = label_defers->n;
+ goto_defers = goto_defers->n;
}
/* only the defers below the common defer should be executed by the goto */
if (goto_defers) {
/* fuck, I actually need the one previous to this */
- assert(prev_defer->next == goto_defers);
- prev_defer->next = NULL;
+ assert(prev_defer->n == goto_defers);
+ prev_defer->n = NULL;
}
/* nothing to do */
@@ -1839,16 +1692,16 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
static int actualize_goto(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_GOTO);
+ assert(node->k == AST_GOTO);
push_goto(state, node);
/* clone all defers as we don't know where the label might be */
- node->_goto.defers = clone_defers(state, NULL);
- node->type = void_type();
+ goto_defers(node) = clone_defers(state, NULL);
+ node->t = void_type();
- struct ast_node *label = find_label(state, node->_goto.label);
+ struct ast *label = find_label(state, goto_label(node));
/* this is a jump backwards, i.e. we can already do it */
if (label)
actualize_goto_defer(node, label);
@@ -1858,24 +1711,24 @@ static int actualize_goto(struct act_state *state, struct scope *scope,
}
static void actualize_goto_defers(struct act_state *state,
- struct ast_node *label)
+ struct ast *label)
{
struct act_stack *prev = state->goto_stack, *cur;
if (prev)
do {
cur = prev->next;
- struct ast_node *got = prev->node;
- if (equiv_nodes(AST_GOTO(got).label, label))
+ struct ast *got = prev->node;
+ if (same_id(goto_label(got), label_id(label)))
actualize_goto_defer(got, label);
} while ((prev = cur));
}
static int actualize_label(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_LABEL);
- struct ast_node *prev = find_label(state, node);
+ assert(node->k == AST_LABEL);
+ struct ast *prev = find_label(state, label_id(node));
if (prev) {
semantic_error(scope->fctx, node, "label redefined");
semantic_info(scope->fctx, prev, "previous definition");
@@ -1884,60 +1737,65 @@ static int actualize_label(struct act_state *state, struct scope *scope,
push_label(state, node);
/* clone all defers */
- node->_label.defers = clone_defers(state, NULL);
- node->type = void_type();
+ label_defers(node) = clone_defers(state, NULL);
+ node->t = void_type();
actualize_goto_defers(state, node);
return 0;
}
static int actualize_unop(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_UNOP);
- struct ast_node *expr = AST_UNOP(node).expr;
+ assert(is_unop(node));
+ struct ast *expr = unop_expr(node);
if (actualize(state, scope, expr))
return -1;
/* generally speaking */
- set_type(node, expr->type);
+ set_type(node, expr->t);
- switch (node->_unop.op) {
+ switch (node->k) {
case AST_DEREF: {
- struct ast_node *type = expr->type;
- if (AST_TYPE(type).kind != AST_TYPE_POINTER) {
- /* TODO: or array */
+ struct type *type = expr->t;
+ if (type->k!= TYPE_PTR) {
+ /** @todo or array? */
+ char *tstr = type_str(type);
semantic_error(scope->fctx, expr,
- "trying to dereference something that's not a pointer");
+ "not a pointer: %s",
+ tstr);
+ free(tstr);
return -1;
}
- set_type(node, AST_PTR_TYPE(type).base);
- assert(node->type);
+ set_type(node, ptr_base(type));
+ assert(node->t);
break;
}
case AST_REF: {
- node->type = gen_type(AST_TYPE_POINTER, NULL, NULL,
- NULL_LOC());
- set_type(node->AST_TYPE(type).next, expr->type);
+ /** @todo array pointer decay? */
+ node->t = tgen_ptr(clone_type(expr->t), node->loc);
break;
}
case AST_LNOT: {
- if (AST_TYPE(expr->type).kind != AST_TYPE_PRIMITIVE) {
+ if (is_primitive(expr->t)) {
+ char *tstr = type_str(expr->t);
semantic_error(scope->fctx, node,
- "'!' only implemented for primitive types");
+ "'!' only implemented for primitive types: %s",
+ tstr);
+ free(tstr);
return -1;
}
- if (AST_PRIMITIVE_TYPE(expr->type).type == AST_VOID) {
+ if (expr->t->k == TYPE_VOID) {
semantic_error(scope->fctx, node,
"'!' not implemented for void");
return -1;
}
- node->type = bool_type(scope);
+ node->t = bool_type(scope);
break;
}
@@ -1950,79 +1808,90 @@ static int actualize_unop(struct act_state *state,
}
static int actualize_as(struct act_state *state,
- struct scope *scope, struct ast_node *as)
+ struct scope *scope, struct ast *as)
{
- assert(as->node_type == AST_AS);
- struct ast_node *type = AST_AS(as).type;
- if (actualize(state, scope, type))
+ assert(as->k == AST_AS);
+ struct type *type = as->t;
+ if (actualize_type(state, scope, type))
return -1;
set_type(as, type);
return 0;
}
-static int _replace_type_id(struct ast_node *node, void *data)
-{
- if (!node)
- return 0;
+struct replace_data {
+ char *id;
+ struct type *replacement;
+};
- struct ast_node **pair = data;
- struct ast_node *id = pair[0];
- struct ast_node *replacement = pair[1];
+static int _replace_type_id(struct type *type, void *data)
+{
+ struct replace_data *pair = data;
+ struct type *replacement = pair->replacement;
+ char *id = pair->id;
- if (node->node_type != AST_TYPE)
- goto next;
+ switch (type->k) {
+ case TYPE_ID: {
+ replace_type(type, clone_type(replacement));
+ break;
+ }
- switch (AST_TYPE(node).kind) {
- case AST_TYPE_ID: *node = *clone_ast_node(replacement); break;
- case AST_TYPE_TRAIT: {
- struct ast_node *def = AST_TRAIT_TYPE(node).def;
+ case TYPE_TRAIT: {
+ struct ast *def = type->d;
assert(def);
- struct ast_node *name = AST_TRAIT(def).id;
+
+ char *name = trait_id(def);
if (same_id(id, name))
- *node = *clone_ast_node(replacement);
+ replace_type(type, clone_type(replacement));
break;
}
- case AST_TYPE_STRUCT: {
- struct ast_node *def = AST_STRUCT_TYPE(node).def;
+ case TYPE_STRUCT: {
+ struct ast *def = type->d;
assert(def);
- struct ast_node *name = AST_STRUCT(def).id;
+ char *name = struct_id(def);
if (same_id(id, name))
- *node = *clone_ast_node(replacement);
+ replace_type(type, clone_type(replacement));
break;
}
+
default:
}
-next:
- return ast_call_on(_replace_type_id, node, data);
+ return 0;
}
-static int replace_type_id(struct ast_node *nodes, struct ast_node *id,
- struct ast_node *replacement)
+static int _replace_ast_type_id(struct ast *node, void *data)
{
- assert(replacement->node_type == AST_TYPE);
- struct ast_node *pair[2] = {id, replacement};
- return ast_call_on(_replace_type_id, nodes, pair);
+ if (!node)
+ return 0;
+
+ return type_visit_list(_replace_type_id, NULL, node->t, data);
+}
+
+static int replace_type_id(struct ast *nodes, char *id,
+ struct type *replacement)
+{
+ struct replace_data pair = {id, replacement};
+ return ast_visit(_replace_ast_type_id, NULL, nodes, &pair);
}
/* lots of overlap with actualize_struct, kind of ugly... */
static int actualize_trait(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_TRAIT);
- foreach_node(n, AST_TRAIT(node).body) {
+ assert(node->k == AST_TRAIT_DEF);
+ foreach_node(n, trait_body(node)) {
/* there's really only prodcedure body actualization left I
* guess, as type stuff was taken care of in the analysis phase
* */
- if (n->node_type != AST_PROC)
+ if (n->k != AST_PROC_DEF)
continue;
/* don't actualize prototypes, duh */
- if (!AST_PROC(n).body)
+ if (!proc_body(n))
continue;
if (actualize(state, node->scope, n))
@@ -2033,18 +1902,18 @@ static int actualize_trait(struct act_state *state, struct scope *scope,
}
static int actualize_struct(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_STRUCT);
- foreach_node(n, AST_STRUCT(node).body) {
+ assert(node->k == AST_STRUCT_DEF);
+ foreach_node(n, struct_body(node)) {
/* there's really only prodcedure body actualization left I
* guess, as type stuff was taken care of in the analysis phase
* */
- if (n->node_type != AST_PROC)
+ if (n->k != AST_PROC_DEF)
continue;
/* don't actualize prototypes, duh */
- if (!AST_PROC(n).body)
+ if (!proc_body(n))
continue;
if (actualize(state, node->scope, n))
@@ -2057,23 +1926,23 @@ static int actualize_struct(struct act_state *state,
/* could maybe be renamed, but essentially dot in copper works as either
* -> or . in C, so allow structures or traits and single level pointers to
* structures or traits. */
-static int has_members(struct ast_node *type)
+static int has_members(struct type *type)
{
/* most likely */
- if (AST_TYPE(type).kind == AST_TYPE_STRUCT)
+ if (type->k == TYPE_STRUCT)
return 1;
- if (AST_TYPE(type).kind == AST_TYPE_TRAIT)
+ if (type->k == TYPE_TRAIT)
return 1;
- if (AST_TYPE(type).kind == AST_TYPE_CONSTRUCT)
+ if (type->k == TYPE_CONSTRUCT)
return 1;
return 0;
}
static int actualize_dot(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
/* TODO: handle enums as well, idea is something like
* enum whatever {A_FLAG}
@@ -2083,19 +1952,18 @@ static int actualize_dot(struct act_state *state,
* possibly also if the expr is of type whatever then .A_FLAG just gets
* the corresponding constant?
**/
- assert(node->node_type == AST_DOT);
- struct ast_node *expr = AST_DOT(node).expr;
+ assert(node->k == AST_DOT);
+ struct ast *expr = dot_expr(node);
if (actualize(state, scope, expr))
return -1;
- struct ast_node *id = AST_DOT(node).id;
- struct ast_node *type = expr->type;
+ char *id = dot_id(node);
+ struct type *type = expr->t;
- struct ast_node *def = NULL;
- switch (AST_TYPE(type).kind) {
- case AST_TYPE_PRIMITIVE: def = AST_PRIMITIVE_TYPE(type).def; break;
- case AST_TYPE_TRAIT: def = AST_TRAIT_TYPE(type).def; break;
- case AST_TYPE_STRUCT: def = AST_STRUCT_TYPE(type).def; break;
+ struct ast *def = NULL;
+ switch (type->k) {
+ case TYPE_TRAIT:
+ case TYPE_STRUCT: def = type->d; break;
default: {
char *tstr = type_str(type);
semantic_error(scope->fctx, node,
@@ -2106,17 +1974,17 @@ static int actualize_dot(struct act_state *state,
}
}
- struct ast_node *exists = scope_find_var(def->scope, id);
+ struct ast *exists = scope_find_var(def->scope, id);
if (exists) {
- assert(exists->type);
- set_type(node, exists->type);
+ assert(exists->t);
+ set_type(node, exists->t);
return 0;
}
exists = scope_find_proc(def->scope, id);
if (exists) {
- assert(exists->type);
- set_type(node, exists->type);
+ assert(exists->t);
+ set_type(node, exists->t);
return 0;
}
@@ -2126,42 +1994,33 @@ static int actualize_dot(struct act_state *state,
}
static int actualize_init(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_INIT);
+ assert(node->k == AST_INIT);
/* for now just do the types, the named stuff will be checked later */
/* TODO: how to make sure all members are initialized? */
- int ret = 0;
- enum act_flags old_flags = state->flags;
- ret = actualize(state, scope, node->_init.body);
- state->flags = old_flags;
- return ret;
+ return actualize_list(state, scope, init_body(node));
}
static int actualize_assign(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_ASSIGN);
- struct ast_node *to = node->_assign.to;
+ assert(node->k == AST_ASSIGN);
+ struct ast *to = assign_to(node);
if (actualize(state, scope, to))
return -1;
- struct ast_node *from = node->_assign.from;
- if (actualize(state, scope, from))
+ struct ast *from = assign_from(node);
+ if (actualize_list(state, scope, from))
return -1;
- if (from->node_type == AST_INIT) {
- set_type(node, to->type);
- return actualize_init_cast(state, scope, from, to->type);
+ if (from->k == AST_INIT) {
+ set_type(node, to->t);
+ return actualize_init_cast(state, scope, from, to->t);
}
- if (!types_match(to->type, from->type)) {
- char *tostr = type_str(to->type);
- char *fromstr = type_str(from->type);
- semantic_error(scope->fctx, node, "type mismatch (%s vs %s)",
- tostr, fromstr);
- free(tostr);
- free(fromstr);
+ if (!types_match(to->t, from->t)) {
+ type_mismatch(scope, node, to->t, from->t);
return -1;
}
@@ -2172,84 +2031,77 @@ static int actualize_assign(struct act_state *state, struct scope *scope,
return -1;
}
- set_type(node, to->type);
+ set_type(node, to->t);
return 0;
}
static int actualize_fetch(struct act_state *state, struct scope *scope,
- struct ast_node *fetch)
+ struct ast *fetch)
{
- assert(fetch->node_type == AST_FETCH);
- struct ast_node *type = fetch->_fetch.type;
- if (actualize(state, scope, type))
+ assert(fetch->k == AST_FETCH);
+ struct type *type = fetch_type(fetch);
+ if (actualize_type(state, scope, type))
return -1;
- if (type->_type.kind != AST_TYPE_ENUM) {
- semantic_error(scope->fctx, type, "type is not an enum");
+ if (type->k != TYPE_ENUM) {
+ type_error(scope->fctx, type, "type is not an enum");
return -1;
}
- struct ast_node *id = fetch->_fetch.id;
- struct ast_node *def =
- file_scope_find_type(scope, AST_ID_TYPE(type).id);
+ char *id = fetch_id(fetch);
+ struct ast *def = type->d;
assert(def);
- struct ast_node *member = lookup_enum_member(def, id);
+ struct ast *member = lookup_enum_member(def, id);
if (!member) {
char *estr = type_str(type);
- semantic_error(scope->fctx, id, "no such member in enum %s");
+ semantic_error(scope->fctx, fetch, "no such member in enum %s");
free(estr);
return -1;
}
- set_type(fetch, def->type);
+ set_type(fetch, def->t);
return 0;
}
static int actualize_enum(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_ENUM);
- struct ast_node *type = node->_enum.type;
+ assert(node->k == AST_ENUM_DEF);
+ struct type *type = enum_type(node);
struct scope *enum_scope = node->scope;
/* TODO: here we could save space by choosing the smallest type that
* fits */
if (!type) {
type = i27_type(scope);
- node->_enum.type = type;
- } else if (actualize(state, enum_scope, type))
+ node->t = type;
+ } else if (actualize_type(state, enum_scope, type))
return -1;
long long counter = 0;
- node->type = type;
- struct ast_node *members = node->_enum.body;
+ node->t = type;
+ struct ast *members = enum_body(node);
while (members) {
set_type(members, type);
- if (members->_val.val) {
- struct ast_node *val = members->_val.val;
+ if (val_val(members)) {
+ struct ast *val = val_val(members);
if (actualize(state, enum_scope, val))
return -1;
- if (val->node_type != AST_CONST) {
+ if (val->k != AST_CONST_INT) {
semantic_error(scope->fctx, members,
"unable to process nonconstant expression");
return -1;
}
- if (val->_const.kind != AST_CONST_INTEGER) {
- semantic_error(scope->fctx, members,
- "not expandable to an integer constant");
- return -1;
- }
-
- counter = val->_const.integer;
+ counter = int_val(val);
}
else {
- members->_val.val = gen_int(counter, NULL_LOC());
+ val_val(members) = gen_const_int(counter, NULL_LOC());
}
- members = members->next;
+ members = members->n;
counter++;
}
@@ -2258,21 +2110,21 @@ static int actualize_enum(struct act_state *state, struct scope *scope,
}
static int actualize_if(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_IF);
- if (actualize(state, scope, AST_IF(node).cond))
+ assert(node->k == AST_IF);
+ if (actualize(state, scope, if_cond(node)))
return -1;
- if (actualize(state, scope, AST_IF(node).body))
+ if (actualize(state, scope, if_body(node)))
return -1;
- if (actualize(state, scope, AST_IF(node).els))
+ if (actualize(state, scope, if_else(node)))
return -1;
if (ast_flags(node, AST_FLAG_DOEXPR)) {
- struct ast_node *tt = ast_last_node(AST_IF(node).body)->type;
- struct ast_node *ft = ast_last_node(AST_IF(node).els)->type;
+ struct type *tt = ast_last(if_body(node))->t;
+ struct type *ft = ast_last(if_else(node))->t;
if (!types_match(tt, ft)) {
semantic_error(scope->fctx, node,
"mismatched if/else body values");
@@ -2283,143 +2135,124 @@ static int actualize_if(struct act_state *state, struct scope *scope,
return 0;
}
- node->type = void_type();
+ node->t = void_type();
return 0;
}
static int actualize_for(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_FOR);
- if (actualize(state, scope, AST_FOR(node).pre))
+ assert(node->k == AST_FOR);
+ if (actualize_list(state, scope, for_pre(node)))
return -1;
- if (actualize(state, scope, AST_FOR(node).post))
+ if (actualize_list(state, scope, for_post(node)))
return -1;
- if (actualize(state, scope, AST_FOR(node).cond))
+ if (actualize_list(state, scope, for_cond(node)))
return -1;
- if (actualize(state, scope, AST_FOR(node).body))
+ if (actualize_list(state, scope, for_body(node)))
return -1;
- node->type = void_type();
+ node->t = void_type();
+ return 0;
+}
+
+static int actualize_comparison(struct act_state *state, struct scope *scope, struct ast *node)
+{
+ assert(is_comparison(node));
+ struct ast *left = comparison_left(node);
+ struct ast *right = comparison_right(node);
+
+ if (actualize(state, scope, left))
+ return -1;
+
+ if (actualize(state, scope, right))
+ return -1;
+
+ if (!is_primitive(left->t)) {
+ type_error(scope->fctx, left->t, "primitive type required");
+ return -1;
+ }
+
+ if (!is_primitive(right->t)) {
+ type_error(scope->fctx, right->t, "primitive type required");
+ return -1;
+ }
+
+ if (!types_match(left->t, right->t)) {
+ type_mismatch(scope, node, left->t, right->t);
+ return -1;
+ }
+
+ set_type(node, bool_type(scope));
return 0;
}
static int actualize(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- int ret = 0;
if (!node)
- return ret;
+ return 0;
if (!node->scope)
node->scope = scope;
- /* this node was already actualized, presumed to be fine */
- if (ast_flags(node, AST_FLAG_ACTUAL)) {
- return 0;
- }
-
- /* actualization started */
- ast_set_flags(node, AST_FLAG_INIT);
+ if (is_unop(node))
+ return actualize_unop(state, scope, node);
- /* actualization done for this node (optimistic) */
- ast_set_flags(node, AST_FLAG_ACTUAL);
+ if (is_binop(node))
+ return actualize_binop(state, scope, node);
- switch (node->node_type) {
- case AST_PROC:
- ret |= actualize_proc(state, scope, node);
- break;
+ if (is_comparison(node))
+ return actualize_comparison(state, scope, node);
- 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_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;
- case AST_ID: ret |= actualize_id(state, scope, node); break;
- case AST_VAR: ret |= actualize_var(state, scope, node); break;
- case AST_TYPE: ret |= actualize_type(state, scope, node); break;
- case AST_EMPTY: ret |= actualize_empty(state, scope, node); break;
- case AST_CAST: ret |= actualize_cast(state, scope, node); break;
- case AST_CONST: ret |= actualize_const(state, scope, node); break;
- case AST_DEFER: ret |= actualize_defer(state, scope, node); break;
- case AST_RETURN: ret |= actualize_return(state, scope, node); break;
- case AST_GOTO: ret |= actualize_goto(state, scope, node); break;
- case AST_LABEL: ret |= actualize_label(state, scope, node); break;
- case AST_UNOP: ret |= actualize_unop(state, scope, node); break;
- case AST_AS: ret |= actualize_as(state, scope, node); break;
- case AST_STRUCT: ret |= actualize_struct(state, scope, node); break;
- case AST_DOT: ret |= actualize_dot(state, scope, node); break;
- case AST_INIT: ret |= actualize_init(state, scope, node); break;
- case AST_ASSIGN: ret |= actualize_assign(state, scope, node); break;
- case AST_FETCH: ret |= actualize_fetch(state, scope, node); break;
- case AST_ENUM: ret |= actualize_enum(state, scope, node); break;
- case AST_IF: ret |= actualize_if(state, scope, node); break;
- case AST_FOR: ret |= actualize_for(state, scope, node); break;
+ if (is_const(node))
+ return actualize_const(state, scope, node);
+ switch (node->k) {
+ case AST_PROC_DEF: return actualize_proc(state, scope, node);
+ case AST_TRAIT_DEF: return actualize_trait(state, scope, node);
+ case AST_ALIAS_DEF: return actualize_alias(state, scope, node);
+ case AST_ENUM_DEF: return actualize_enum(state, scope, node);
+ case AST_MACRO_DEF: return actualize_macro_def(state, scope, node);
+ case AST_STRUCT_DEF: return actualize_struct(state, scope, node);
+ case AST_VAR_DEF: return actualize_var(state, scope, node);
+ case AST_CALL: return actualize_call(state, scope, node);
+ case AST_BLOCK: return actualize_block(state, scope, node);
+ case AST_ID: return actualize_id(state, scope, node);
+ case AST_EMPTY: return actualize_empty(state, scope, node);
+ case AST_CAST: return actualize_cast(state, scope, node);
+ case AST_DEFER: return actualize_defer(state, scope, node);
+ case AST_RETURN: return actualize_return(state, scope, node);
+ case AST_GOTO: return actualize_goto(state, scope, node);
+ case AST_LABEL: return actualize_label(state, scope, node);
+ case AST_AS: return actualize_as(state, scope, node);
+ case AST_DOT: return actualize_dot(state, scope, node);
+ case AST_INIT: return actualize_init(state, scope, node);
+ case AST_ASSIGN: return actualize_assign(state, scope, node);
+ case AST_FETCH: return actualize_fetch(state, scope, node);
+ case AST_IF: return actualize_if(state, scope, node);
+ case AST_FOR: return actualize_for(state, scope, node);
+ case AST_MACRO_EXPAND: return actualize_macro_expand(state, scope, node);
default:
/* more like internal_error, maybe? */
semantic_error(scope->fctx, node,
"unimplemented actualization");
- break;
- }
- return ret;
-}
-
-int actualize_main(struct scope *root)
-{
- struct ast_node *main_id = gen_id(strdup("main"), NULL_LOC());
-
- struct act_state state = {0};
-
- /* skip checking signature for now */
- struct ast_node *main = file_scope_find_proc(root, main_id);
- if (!main) {
- /* libraries are not really compilable... */
- error("no main");
return -1;
}
- int ret = actualize(&state, root, main);
- destroy_act_state(&state);
- return ret;
-}
-
-void replace_type(struct ast_node *type, struct ast_node *from,
- struct ast_node *to)
-{
- if (!type)
- return;
-
- assert(type->node_type == AST_TYPE);
- assert(from->node_type == AST_TYPE);
- assert(to->node_type == AST_TYPE);
-
- if (types_match(type, from)) {
- assert(type->_type.next == NULL);
- struct ast_node *clone = clone_ast_node(to);
- *type = *clone;
- return;
- }
- replace_type(type->_type.next, from, to);
+ return 0;
}
-void replace_param_types(struct ast_node *param, struct ast_node *param_type,
- struct ast_node *arg_type)
+static int actualize_list(struct act_state *state, struct scope *scope,
+ struct ast *l)
{
- if (arg_type->_type.kind == AST_TYPE_TRAIT) {
- replace_param_types(param, param_type, arg_type);
- return;
+ foreach_node(n, l) {
+ if (actualize(state, scope, n))
+ return -1;
}
- while (param) {
- replace_type(param->type, param_type, arg_type);
- param = param->next;
- }
+ return 0;
}
diff --git a/src/ast.c b/src/ast.c
index e77714c..18a98bc 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -15,585 +15,162 @@
#include <math.h>
#include <ek/ast.h>
+#include <ek/vec.h>
#include <ek/scope.h>
-static struct {
- size_t n;
- size_t s;
- struct ast_node **v;
-} ast_nodes = {0};
+static struct vec nodes = {0};
+static struct vec types = {0};
-static void destroy_ast_node(struct ast_node *node)
+static void destroy_ast_node(struct ast *n)
{
- if (!node)
+ if (!n)
return;
- 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;
- default:
- }
-
- free(node);
-}
-
-void destroy_ast_nodes()
-{
- for (size_t i = 0; i < ast_nodes.n; ++i)
- destroy_ast_node(ast_nodes.v[i]);
-
- free(ast_nodes.v);
-}
-
-/* eventually we might want to pass in a context or something */
-static struct ast_node *create_ast_node()
-{
- if (ast_nodes.s == 0) {
- ast_nodes.s = 1;
- ast_nodes.n = 0;
- ast_nodes.v = calloc(1, sizeof(struct 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 *));
- }
-
- struct ast_node *n = calloc(1, sizeof(struct ast_node));
- ast_nodes.v[ast_nodes.n++] = n;
- return n;
-}
-
-/** @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 DESTROY_LIST(x) \
- { \
- struct ast_node *prev = x, *cur; \
- if (prev) \
- do { \
- cur = prev->next; \
- destroy_ast_node(prev); \
- } while ((prev = cur)); \
- }
-
-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;
- AST_ARR_ACCESS(n).base = base;
- AST_ARR_ACCESS(n).idx = idx;
- n->loc = loc;
- return n;
-}
-
-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;
- AST_MACRO_EXPAND(n).id = id;
- AST_MACRO_EXPAND(n).args = args;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_type_expand(struct ast_node *id,
- struct ast_node *args,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "type_expand");
- n->node_type = AST_TYPE_EXPAND;
- AST_TYPE_EXPAND(n).id = id;
- AST_TYPE_EXPAND(n).args = args;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_binop(enum ast_binops op,
- struct ast_node *left,
- struct ast_node *right,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "binop");
- n->node_type = AST_BINOP;
- AST_BINOP(n).op = op;
- AST_BINOP(n).left = left;
- AST_BINOP(n).right = right;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_unop(enum ast_unops op, struct ast_node *expr,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "unop");
- n->node_type = AST_UNOP;
- AST_UNOP(n).op = op;
- AST_UNOP(n).expr = expr;
- n->loc = loc;
- return n;
-}
-
-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;
- AST_CALL(n).expr = expr;
- AST_CALL(n).args = args;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_id(const char *id, struct src_loc loc)
-{
- ALLOC_NODE(n, "id");
- n->node_type = AST_ID;
- AST_ID(n).id = id;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_assign(struct ast_node *to, struct ast_node *from,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "assign");
- n->node_type = AST_ASSIGN;
- AST_ASSIGN(n).to = to;
- AST_ASSIGN(n).from = from;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_init(struct ast_node *body, struct src_loc loc)
-{
- ALLOC_NODE(n, "struct init");
- n->node_type = AST_INIT;
- AST_INIT(n).body = body;
- n->loc = loc;
- return n;
-}
+ if (n->s)
+ free(n->s);
-struct ast_node *gen_int(long long integer, struct src_loc loc)
-{
- ALLOC_NODE(n, "int");
- n->node_type = AST_CONST;
- AST_CONST(n).kind = AST_CONST_INTEGER;
- AST_CONST(n).integer = integer;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_string(const char *str, struct src_loc loc)
-{
- ALLOC_NODE(n, "string");
- n->node_type = AST_CONST;
- AST_CONST(n).kind = AST_CONST_STRING;
- AST_CONST(n).str = str;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_while(struct ast_node *cond, struct ast_node *body,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "while");
- n->node_type = AST_WHILE;
- AST_WHILE(n).cond = cond;
- AST_WHILE(n).body = body;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_for(struct ast_node *pre, struct ast_node *cond,
- struct ast_node *post, struct ast_node *body,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "for");
- n->node_type = AST_FOR;
- AST_FOR(n).pre = pre;
- AST_FOR(n).cond = cond;
- AST_FOR(n).post = post;
- AST_FOR(n).body = body;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_return(struct ast_node *expr, struct src_loc loc)
-{
- ALLOC_NODE(n, "return");
- n->node_type = AST_RETURN;
- AST_RETURN(n).expr = expr;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_goto(struct ast_node *label, struct src_loc loc)
-{
- ALLOC_NODE(n, "goto");
- n->node_type = AST_GOTO;
- AST_GOTO(n).label = label;
- n->loc = loc;
- return n;
-}
-
-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;
- AST_DOT(n).expr = expr;
- AST_DOT(n).id = id;
- n->loc = loc;
- return n;
+ free(n);
}
-struct ast_node *gen_label(struct ast_node *id, struct src_loc loc)
+static void destroy_type(struct type *n)
{
- ALLOC_NODE(n, "label");
- n->node_type = AST_LABEL;
- AST_LABEL(n).id = id;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_ctrl(enum ast_ctrl_kind kind, struct src_loc loc)
-{
- ALLOC_NODE(n, "ctrl");
- n->node_type = AST_CTRL;
- AST_CTRL(n).kind = kind;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_fetch(struct ast_node *id, struct ast_node *type,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "fetch");
- n->node_type = AST_FETCH;
- AST_FETCH(n).id = id;
- AST_FETCH(n).type = type;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_macro_construct(struct ast_node *id,
- struct ast_node *params,
- struct ast_node *body,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "macro_construct");
- n->node_type = AST_MACRO_CONSTRUCT;
- AST_MACRO_CONSTRUCT(n).id = id;
- AST_MACRO_CONSTRUCT(n).params = params;
- AST_MACRO_CONSTRUCT(n).body = body;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_if(struct ast_node *cond, struct ast_node *body,
- struct ast_node *els, struct src_loc loc)
-{
- ALLOC_NODE(n, "if");
- n->node_type = AST_IF;
- AST_IF(n).cond = cond;
- AST_IF(n).body = body;
- AST_IF(n).els = els;
- n->loc = loc;
- return n;
-}
+ if (!n)
+ return;
-struct ast_node *gen_switch(struct ast_node *cond, struct ast_node *cases,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "switch");
- n->node_type = AST_SWITCH;
- AST_SWITCH(n).cond = cond;
- AST_SWITCH(n).cases = cases;
- n->loc = loc;
- return n;
-}
+ if (n->id)
+ free(n->id);
-struct ast_node *gen_case(struct ast_node *cond, struct ast_node *body,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "case");
- /* TODO: a macro to map proc name to node type would make sure I don't
- * make any dumb mixups... */
- n->node_type = AST_CASE;
- AST_CASE(n).cond = cond;
- AST_CASE(n).body = body;
- /* TODO: where should I check the fallthrough flag? In the
- * actualization stage, I guess */
- n->loc = loc;
- return n;
+ free(n);
}
-struct ast_node *gen_primitive(enum ast_primitive type, struct ast_node *def,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "primitive");
- n->node_type = AST_TYPE;
- AST_TYPE(n).kind = AST_TYPE_PRIMITIVE;
- AST_PRIMITIVE_TYPE(n).type = type;
- AST_PRIMITIVE_TYPE(n).def = def;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_type(enum ast_type_kind kind,
- struct ast_node *t0,
- struct ast_node *t1,
- struct src_loc loc)
+void destroy_ast_nodes()
{
- 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;
- break;
-
- case AST_TYPE_ID:
- 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_POINTER:
- AST_PTR_TYPE(n).base = t0;
- break;
-
- case AST_TYPE_STRUCT:
- AST_STRUCT_TYPE(n).def = t0;
- break;
-
- case AST_TYPE_ENUM:
- AST_ENUM_TYPE(n).def = t0;
- break;
-
- case AST_TYPE_SIGN:
- AST_SIGN_TYPE(n).params = t0;
- AST_SIGN_TYPE(n).ret = t1;
- break;
-
- default: abort();
+ foreach_vec(ni, nodes) {
+ struct ast *n = vect_at(struct ast *, nodes, ni);
+ destroy_ast_node(n);
}
- return n;
-}
-
-struct ast_node *gen_block(struct ast_node *body, struct src_loc loc)
-{
- ALLOC_NODE(n, "block");
- n->node_type = AST_BLOCK;
- AST_BLOCK(n).body = body;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_sizeof(struct ast_node *expr, struct src_loc loc)
-{
- ALLOC_NODE(n, "sizeof");
- n->node_type = AST_SIZEOF;
- AST_SIZEOF(n).expr = expr;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_as(struct ast_node *type, struct src_loc loc)
-{
- ALLOC_NODE(n, "as");
- n->node_type = AST_AS;
- AST_AS(n).type = type;
- n->loc = loc;
- return n;
-}
-
-struct ast_node *gen_defer(struct ast_node *expr, struct src_loc loc)
-{
- ALLOC_NODE(n, "defer");
- n->node_type = AST_DEFER;
- AST_DEFER(n).expr = expr;
- n->loc = loc;
- return n;
+ vec_destroy(&nodes);
}
-void destroy_defer(struct ast_node *defer)
+void destroy_types()
{
- assert(defer->node_type == AST_DEFER);
- destroy_ast_node(AST_DEFER(defer).expr);
- free(defer);
-}
+ foreach_vec(ti, types) {
+ struct type *t = vect_at(struct type *, types, ti);
+ destroy_type(t);
+ }
-struct ast_node *gen_var(struct ast_node *id, struct ast_node *type,
- struct ast_node *init, struct src_loc loc)
-{
- ALLOC_NODE(n, "var");
- n->node_type = AST_VAR;
- AST_VAR(n).id = id;
- AST_VAR(n).type = type;
- AST_VAR(n).init = init;
- n->loc = loc;
- return n;
+ vec_destroy(&types);
}
-struct ast_node *gen_proc(struct ast_node *id, struct ast_node *sign,
- struct ast_node *body, struct src_loc loc)
+void destroy_allocs()
{
- ALLOC_NODE(n, "proc");
- n->node_type = AST_PROC;
- AST_PROC(n).id = id;
- AST_PROC(n).sign = sign;
- AST_PROC(n).body = body;
- n->loc = loc;
- return n;
+ destroy_ast_nodes();
+ destroy_types();
}
-struct ast_node *gen_struct(struct ast_node *id,
- struct ast_node *generics, struct ast_node *body,
- struct src_loc loc)
+static struct ast *create_empty_ast()
{
- ALLOC_NODE(n, "struct");
- n->node_type = AST_STRUCT;
- AST_STRUCT(n).id = id;
- AST_STRUCT(n).generics = generics;
- AST_STRUCT(n).body = body;
- n->loc = loc;
- return n;
-}
+ if (vec_uninit(nodes)) {
+ nodes = vec_create(sizeof(struct ast *));
+ }
-struct ast_node *gen_enum(struct ast_node *id, struct ast_node *type,
- struct ast_node *body, struct src_loc loc)
-{
- ALLOC_NODE(n, "enum");
- n->node_type = AST_ENUM;
- AST_ENUM(n).id = id;
- AST_ENUM(n).type = type;
- AST_ENUM(n).body = body;
- n->loc = loc;
+ struct ast *n = calloc(1, sizeof(struct ast));
+ /* just to be safe */
+ n->k = AST_EMPTY;
+ vect_append(struct ast *, nodes, &n);
return n;
}
-struct ast_node *gen_cast(struct ast_node *expr, struct ast_node *type,
- struct src_loc loc)
+static struct type *create_empty_type()
{
- ALLOC_NODE(n, "cast");
- n->node_type = AST_CAST;
- AST_CAST(n).expr = expr;
- AST_CAST(n).type = type;
- n->loc = loc;
- return n;
-}
+ if (vec_uninit(types)) {
+ types = vec_create(sizeof(struct type *));
+ }
-struct ast_node *gen_val(struct ast_node *id, struct ast_node *val,
- struct src_loc loc)
-{
- ALLOC_NODE(n, "val");
- n->node_type = AST_VAL;
- AST_VAL(n).id = id;
- AST_VAL(n).val = val;
- n->loc = loc;
+ struct type *n = calloc(1, sizeof(struct type));
+ /* just to be safe */
+ n->k = TYPE_VOID;
+ vect_append(struct ast *, types, &n);
return n;
}
-struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type,
- struct src_loc loc)
+struct ast *gen_ast(enum ast_kind kind,
+ struct ast *a0,
+ struct ast *a1,
+ struct ast *a2,
+ struct ast *a3,
+ struct type *t2,
+ char *s,
+ long long v,
+ struct src_loc loc)
{
- ALLOC_NODE(n, "alias");
- n->node_type = AST_ALIAS;
- AST_ALIAS(n).id = id;
- AST_ALIAS(n).type = type;
+ struct ast *n = create_empty_ast();
+ n->k = kind;
+ n->a0 = a0;
+ n->a1 = a1;
+ n->a2 = a2;
+ n->a3 = a3;
+ n->t2 = t2;
+ n->s = s;
+ n->v = v;
n->loc = loc;
return n;
}
-struct ast_node *gen_trait(struct ast_node *id,
- struct ast_node *params,
- struct ast_node *raw_body,
- struct ast_node *body,
- struct src_loc loc)
+struct type *tgen_type(enum type_kind kind,
+ struct type *t0,
+ struct type *t1,
+ struct ast *d,
+ struct ast *a,
+ char *id,
+ struct src_loc loc)
{
- ALLOC_NODE(n, "trait");
- n->node_type = AST_TRAIT;
- AST_TRAIT(n).id = id;
- AST_TRAIT(n).params = params;
- AST_TRAIT(n).body = body;
- AST_TRAIT(n).raw_body = raw_body;
+ struct type *n = create_empty_type();
+ n->k = kind;
+ n->t0 = t0;
+ n->t1 = t1;
+ n->d = d;
+ n->a = a;
+ n->id = id;
n->loc = loc;
return n;
}
-struct ast_node *gen_import(const char *file, struct src_loc loc)
+void ast_set_flags(struct ast *node, enum ast_flags flags)
{
- ALLOC_NODE(n, "import");
- n->node_type = AST_IMPORT;
- AST_IMPORT(n).file = file;
- n->loc = loc;
- return n;
+ node->f |= flags;
}
-struct ast_node *gen_embed(const char *file, struct src_loc loc)
+void ast_clear_flags(struct ast *node, enum ast_flags flags)
{
- ALLOC_NODE(n, "embed");
- n->node_type = AST_EMBED;
- AST_EMBED(n).file = file;
- n->loc = loc;
- return n;
+ node->f &= ~(flags);
}
-struct ast_node *gen_empty()
+unsigned ast_flags(struct ast *node, enum ast_flags flags)
{
- ALLOC_NODE(n, "empty");
- n->node_type = AST_EMPTY;
- /* TODO: location? */
- return n;
+ return node->f & flags;
}
-void ast_set_flags(struct ast_node *node, enum ast_flag flags)
+void ast_append(struct ast *list, struct ast *elem)
{
- node->flags |= flags;
-}
+ struct ast *cur = list;
+ while (cur->n)
+ cur = cur->n;
-void ast_clear_flags(struct ast_node *node, enum ast_flag flags)
-{
- node->flags &= ~(flags);
+ cur->n = elem;
}
-void ast_append(struct ast_node *list, struct ast_node *elem)
+void type_append(struct type *list, struct type *elem)
{
- struct ast_node *cur = list;
- while (cur->next)
- cur = cur->next;
+ struct type *cur = list;
+ while (cur->n)
+ cur = cur->n;
- cur->next = elem;
+ cur->n = elem;
}
-
-static const char *binop_symbol(int op)
+static const char *binop_symbol(enum ast_kind op)
{
switch (op) {
case AST_ADD: return "+";
@@ -618,18 +195,20 @@ static const char *binop_symbol(int op)
case AST_GE: return ">=";
case AST_NE: return "!=";
case AST_EQ: return "==";
+ default:
}
return "UNKNOWN";
}
-static const char *unop_symbol(int op)
+static const char *unop_symbol(enum ast_kind op)
{
switch (op) {
case AST_NEG: return "-";
case AST_LNOT: return "!";
case AST_REF: return "&";
case AST_DEREF: return "*";
+ default:
}
return "UNKNOWN";
@@ -641,19 +220,19 @@ static void dump(int depth, const char *fmt, ...)
va_start(args, fmt);
printf("//");
for (int i = 0; i < depth; ++i)
- putchar('\t');
+ printf(" ");
vprintf(fmt, args);
va_end(args);
}
-static void dump_flags(struct ast_node *node)
+static void dump_flags(struct ast *node)
{
if (node->scope)
printf(" %zu:", node->scope->number);
- enum ast_flag flags = node->flags;
+ enum ast_flags flags = node->f;
if (flags & AST_FLAG_MUTABLE)
printf(" MUT");
@@ -679,1252 +258,462 @@ static void dump_flags(struct ast_node *node)
printf(" FALLTHROUGH");
}
-const char *primitive_str(enum ast_primitive type)
+const char *primitive_str(struct type *type)
{
- switch (type) {
- case AST_VOID: return "void";
- case AST_I9: return "i9";
- case AST_I27: return "i27";
- case AST_BOOL: return "bool";
+ switch (type->k) {
+ case TYPE_VOID: return "void";
+ case TYPE_I9: return "i9";
+ case TYPE_I27: return "i27";
+ case TYPE_BOOL: return "bool";
default: return "unimp";
}
return "unimp";
}
-static void __dump_ast(int depth, struct ast_node *node)
+void ast_dump(int depth, struct ast *n)
{
- switch (node->node_type) {
- case AST_FETCH:
- dump(depth, "{FETCH:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_FETCH(node).id);
- dump_ast(depth + 1, AST_FETCH(node).type);
-
- dump(depth, "}\n");
- break;
-
- case AST_ASSIGN:
- dump(depth, "{ASSIGN:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_ASSIGN(node).to);
- dump_ast(depth + 1, AST_ASSIGN(node).from);
-
- dump(depth, "}\n");
- break;
-
- case AST_INIT:
- dump(depth, "{INIT:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_INIT(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_SIZEOF:
- dump(depth, "{SIZEOF:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_SIZEOF(node).expr);
-
- dump(depth, "}\n");
- break;
-
- case AST_DOT:
- dump(depth, "{DOT:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_DOT(node).expr);
- dump_ast(depth + 1, AST_DOT(node).id);
-
- dump(depth, "}\n");
- break;
-
- case AST_GOTO:
- dump(depth, "{GOTO:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_GOTO(node).defers);
- dump_ast(depth + 1, AST_GOTO(node).label);
-
- dump(depth, "}\n");
- break;
-
- case AST_LABEL:
- dump(depth, "{LABEL:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_LABEL(node).id);
-
- dump(depth, "}\n");
- break;
-
- case AST_BINOP:
- dump(depth, "{BINOP:");
- dump_flags(node);
- printf(" %s\n", binop_symbol(AST_BINOP(node).op));
-
- dump_ast(depth + 1, AST_BINOP(node).left);
- dump_ast(depth + 1, AST_BINOP(node).right);
-
- dump(depth, "}\n");
- break;
-
- case AST_UNOP:
- dump(depth, "{UNOP:");
- dump_flags(node);
- printf(" %s\n", unop_symbol(AST_UNOP(node).op));
-
- dump_ast(depth + 1, AST_UNOP(node).expr);
-
- dump(depth, "}\n");
- break;
-
- case AST_CALL:
- dump(depth, "{CALL:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_CALL(node).expr);
- dump_ast(depth + 1, AST_CALL(node).args);
-
- dump(depth, "}\n");
- break;
-
- case AST_DEFER:
- dump(depth, "{DEFER:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_DEFER(node).expr);
-
- dump(depth, "}\n");
- break;
-
- case AST_CAST:
- dump(depth, "{CAST:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_CAST(node).expr);
- dump_ast(depth + 1, AST_CAST(node).type);
-
- dump(depth, "}\n");
- break;
-
- case AST_MACRO_CONSTRUCT:
- dump(depth, "{MACRO_CONSTRUCT:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_MACRO_CONSTRUCT(node).id);
- dump_ast(depth + 1, AST_MACRO_CONSTRUCT(node).params);
- dump_ast(depth + 1, AST_MACRO_CONSTRUCT(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_MACRO_EXPAND:
- dump(depth, "{MACRO_EXPAND:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_MACRO_EXPAND(node).id);
- dump_ast(depth + 1, AST_MACRO_EXPAND(node).args);
-
- dump(depth, "}\n");
- break;
-
- case AST_PROC:
- dump(depth, "{PROC:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_PROC(node).id);
- dump_ast(depth + 1, AST_PROC(node).sign);
- dump_ast(depth + 1, AST_PROC(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_VAR:
- dump(depth, "{VAR:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_VAR(node).id);
- dump_ast(depth + 1, AST_VAR(node).type);
- dump_ast(depth + 1, AST_VAR(node).init);
-
- dump(depth, "}\n");
- break;
-
- case AST_ID:
- dump(depth, "{ID:");
- dump_flags(node);
- printf(" %s}\n", AST_ID(node).id);
- break;
-
- case AST_AS:
- dump(depth, "{AS:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_AS(node).type);
- dump(depth, "}\n");
- break;
-
- case AST_BLOCK:
- dump(depth, "{BLOCK:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_BLOCK(node).body);
- dump_ast(depth + 1, AST_BLOCK(node).defers);
-
- dump(depth, "}\n");
- break;
-
- case AST_RETURN:
- dump(depth, "{RETURN:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_RETURN(node).defers);
- dump_ast(depth + 1, AST_RETURN(node).expr);
-
- dump(depth, "}\n");
- break;
-
- case AST_TYPE:
- dump(depth, "{TYPE:");
- dump_flags(node);
-
- switch (node->_type.kind) {
- case AST_TYPE_PRIMITIVE:
- printf(" PRIMITIVE %s\n",
- primitive_str(AST_PRIMITIVE_TYPE(node).type));
- break;
-
- case AST_TYPE_TRAIT: {
- printf(" TRAIT\n");
- struct ast_node *def = AST_TRAIT_TYPE(node).def;
- /* this should be enough, avoid print loops */
- dump_ast(depth + 1, AST_TRAIT(def).id);
- break;
- }
-
- case AST_TYPE_CONSTRUCT: {
- printf(" CONSTRUCT\n");
- dump_ast(depth + 1, AST_CONSTRUCT_TYPE(node).id);
- dump_ast(depth + 1, AST_CONSTRUCT_TYPE(node).args);
- break;
- }
-
- case AST_TYPE_ID:
- printf(" ID\n");
- dump_ast(depth + 1, AST_ID_TYPE(node).id);
- break;
-
- case AST_TYPE_ARR:
- printf(" ARR\n");
- dump_ast(depth + 1, AST_ARR_TYPE(node).size);
- dump_ast(depth + 1, AST_ARR_TYPE(node).base);
- break;
-
- case AST_TYPE_POINTER:
- printf(" PTR\n");
- dump_ast(depth + 1, AST_PTR_TYPE(node).base);
- break;
-
- case AST_TYPE_STRUCT: {
- printf(" STRUCT\n");
- struct ast_node *def = AST_STRUCT_TYPE(node).def;
- /* oh yeah, struc is at least right now just an ID that
- * we can use to fetch the actual struct with. */
- dump_ast(depth + 1, AST_STRUCT(def).id);
- break;
- }
-
- case AST_TYPE_ENUM: {
- printf(" ENUM\n");
- struct ast_node *def = AST_ENUM_TYPE(node).def;
- dump_ast(depth + 1, AST_ENUM(def).id);
- break;
- }
-
- case AST_TYPE_SIGN:
- printf(" SIGN\n");
- dump_ast(depth + 1, AST_SIGN_TYPE(node).params);
- dump_ast(depth + 1, AST_SIGN_TYPE(node).ret);
- break;
- }
-
- dump_ast(depth + 1, AST_TYPE(node).next);
-
- dump(depth, "}\n");
- break;
-
- case AST_EMPTY:
- dump(depth, "{EMPTY:");
- dump_flags(node);
- printf("}\n");
- break;
-
- case AST_FOR:
- dump(depth, "{FOR:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_FOR(node).pre);
- dump_ast(depth + 1, AST_FOR(node).cond);
- dump_ast(depth + 1, AST_FOR(node).post);
- dump_ast(depth + 1, AST_FOR(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_WHILE:
- dump(depth, "{WHILE:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_WHILE(node).cond);
- dump_ast(depth + 1, AST_WHILE(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_CTRL:
- dump(depth, "{CTRL:");
- dump_flags(node);
- switch(AST_CTRL(node).kind) {
- case AST_CTRL_BREAK: printf(" BREAK"); break;
- case AST_CTRL_CONTINUE: printf(" CONTINUE"); break;
- }
- printf("}\n");
- break;
-
- case AST_IF:
- dump(depth, "{IF:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_IF(node).cond);
- dump_ast(depth + 1, AST_IF(node).body);
- dump_ast(depth + 1, AST_IF(node).els);
-
- dump(depth, "}\n");
- break;
-
- case AST_IMPORT:
- dump(depth, "{IMPORT:");
- dump_flags(node);
- printf(" %s}\n", AST_IMPORT(node).file);
- break;
-
- case AST_EMBED:
- dump(depth, "{EMBED:");
- dump_flags(node);
- printf(" %s}\n", AST_EMBED(node).file);
- break;
-
- case AST_ENUM:
- dump(depth, "{ENUM:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_ENUM(node).id);
- dump_ast(depth + 1, AST_ENUM(node).type);
- dump_ast(depth + 1, AST_ENUM(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_STRUCT:
- dump(depth, "{STRUCT:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_STRUCT(node).id);
- dump_ast(depth + 1, AST_STRUCT(node).generics);
- dump_ast(depth + 1, AST_STRUCT(node).body);
-
- dump(depth, "}\n");
- break;
-
- case AST_VAL:
- dump(depth, "{VAL:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_VAL(node).id);
- dump_ast(depth + 1, AST_VAL(node).val);
-
- dump(depth, "}\n");
- break;
-
- case AST_SWITCH:
- dump(depth, "{SWITCH:");
- dump_flags(node);
- putchar('\n');
-
- dump_ast(depth + 1, AST_SWITCH(node).cond);
- dump_ast(depth + 1, AST_SWITCH(node).cases);
-
- dump(depth, "}\n");
- break;
+ if (!n) {
+ dump(depth, "{NULL}\n");
+ return;
+ }
- case AST_CASE:
- dump(depth, "{CASE:");
- dump_flags(node);
- putchar('\n');
+#define DUMP(x) case x: dump(depth, #x); break;
+ switch (n->k) {
+ DUMP(AST_FETCH);
+ DUMP(AST_INIT);
+ DUMP(AST_ASSIGN);
+ DUMP(AST_CALL);
+ DUMP(AST_ARR);
+ DUMP(AST_SIZEOF);
+ DUMP(AST_CAST);
+ DUMP(AST_DEFER);
+ DUMP(AST_MACRO_DEF);
+ DUMP(AST_MACRO_EXPAND);
+ DUMP(AST_TYPE_EXPAND);
+ DUMP(AST_PROC_DEF);
+ DUMP(AST_GOTO);
+ DUMP(AST_LABEL);
+ DUMP(AST_VAR_DEF);
+ DUMP(AST_FOR);
+ DUMP(AST_EMBED);
+ DUMP(AST_DOT);
+ DUMP(AST_WHILE);
+ DUMP(AST_DO_WHILE);
+ DUMP(AST_BREAK);
+ DUMP(AST_CONTINUE);
+ DUMP(AST_RETURN);
+ DUMP(AST_ALIAS_DEF);
+ DUMP(AST_TRAIT_DEF);
+ DUMP(AST_STRUCT_DEF);
+ DUMP(AST_IF);
+ DUMP(AST_BLOCK);
+ DUMP(AST_IMPORT);
+ DUMP(AST_ENUM_DEF);
+ DUMP(AST_VAL);
+ DUMP(AST_SWITCH);
+ DUMP(AST_CASE);
+ DUMP(AST_ID);
+ DUMP(AST_AS);
+ DUMP(AST_EMPTY);
+ DUMP(AST_ADD);
+ DUMP(AST_SUB);
+ DUMP(AST_MUL);
+ DUMP(AST_DIV);
+ DUMP(AST_REM);
+ DUMP(AST_LAND);
+ DUMP(AST_LOR);
+ DUMP(AST_LSHIFT);
+ DUMP(AST_RSHIFT);
+ DUMP(AST_ASSIGN_ADD);
+ DUMP(AST_ASSIGN_SUB);
+ DUMP(AST_ASSIGN_MUL);
+ DUMP(AST_ASSIGN_DIV);
+ DUMP(AST_ASSIGN_REM);
+ DUMP(AST_ASSIGN_LSHIFT);
+ DUMP(AST_ASSIGN_RSHIFT);
+ DUMP(AST_LT);
+ DUMP(AST_GT);
+ DUMP(AST_LE);
+ DUMP(AST_GE);
+ DUMP(AST_NE);
+ DUMP(AST_EQ);
+ DUMP(AST_NEG);
+ DUMP(AST_LNOT);
+ DUMP(AST_NOT);
+ DUMP(AST_REF);
+ DUMP(AST_DEREF);
+ DUMP(AST_CONST_INT);
+ DUMP(AST_CONST_CHAR);
+ DUMP(AST_CONST_BOOL);
+ DUMP(AST_CONST_STR);
+ }
+#undef DUMP
- dump_ast(depth + 1, AST_CASE(node).cond);
- dump_ast(depth + 1, AST_CASE(node).body);
+ depth++;
- dump(depth, "}\n");
- break;
+ if (n->t)
+ type_dump_list(n->t);
- case AST_CONST:
- dump(depth, "{CONST:");
- dump_flags(node);
- switch (node->_const.kind) {
- case AST_CONST_INTEGER:
- printf(" %lli", AST_CONST(node).integer);
- break;
- case AST_CONST_STRING:
- printf(" \"%s\"", AST_CONST(node).str);
- break;
- }
- printf("}\n");
- break;
+ printf("\n");
- case AST_ALIAS:
- dump(depth, "{ALIAS:");
- dump_flags(node);
- putchar('\n');
+ if (n->s)
+ dump(depth, "%s\n", n->s);
- dump_ast(depth + 1, AST_ALIAS(node).id);
- dump_ast(depth + 1, AST_ALIAS(node).type);
+ if (n->k == AST_CONST_INT)
+ dump(depth, "%lli\n", n->v);
- dump(depth, "}\n");
- break;
+ if (n->a0)
+ ast_dump_list(depth, n->a0);
- case AST_TRAIT:
- dump(depth, "{TRAIT:");
- dump_flags(node);
- putchar('\n');
+ if (n->a1)
+ ast_dump_list(depth, n->a1);
- dump_ast(depth + 1, AST_TRAIT(node).id);
- dump_ast(depth + 1, AST_TRAIT(node).body);
+ if (n->a2)
+ ast_dump_list(depth, n->a2);
- dump(depth, "}\n");
- break;
+ if (n->a3)
+ ast_dump_list(depth, n->a3);
- default:
- dump(depth, "{UNIMP}\n");
+ if (n->t2) {
+ type_dump_list(n->t2); printf("\n");
}
}
-void dump_ast_node(int depth, struct ast_node *n)
+void ast_dump_list(int depth, struct ast *root)
{
- if (!n) {
+ if (!root) {
dump(depth, "{NULL}\n");
return;
}
- __dump_ast(depth, n);
+ foreach_node(n, root) {
+ ast_dump(depth, n);
+ }
}
-void dump_ast(int depth, struct ast_node *root)
+void type_dump(struct type *n)
{
- if (!root) {
- dump(depth, "{NULL}\n");
+ if (!n) {
+ printf(" {NULL}");
return;
}
- struct ast_node *n = root;
- do {
- dump_ast_node(depth, n);
- } while ((n = n->next));
+ printf(" ");
+
+#define DUMP(x) case x: printf(#x); break;
+ switch (n->k) {
+ DUMP(TYPE_VOID);
+ DUMP(TYPE_BOOL);
+ DUMP(TYPE_I9);
+ DUMP(TYPE_I27);
+ DUMP(TYPE_STR);
+ DUMP(TYPE_PTR);
+ DUMP(TYPE_ID);
+ DUMP(TYPE_CONSTRUCT);
+ DUMP(TYPE_STRUCT);
+ DUMP(TYPE_ENUM);
+ DUMP(TYPE_CALLABLE);
+ DUMP(TYPE_TRAIT);
+ }
}
-struct ast_node *clone_ast_node(struct ast_node *node)
+void type_dump_list(struct type *root)
{
- if (!node)
- return NULL;
-
- assert(node->node_type);
- struct ast_node *new = NULL;
- 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_EXPAND:
- new = gen_type_expand(
- clone_ast_node(AST_TYPE_EXPAND(node).id),
- clone_ast_node(AST_TYPE_EXPAND(node).args),
- node->loc);
- break;
-
- case AST_FETCH:
- new = gen_fetch(clone_ast_node(AST_FETCH(node).id),
- clone_ast_node(AST_FETCH(node).type),
- node->loc);
- break;
-
- case AST_ASSIGN:
- new = gen_assign(clone_ast_node(AST_ASSIGN(node).to),
- clone_ast_node(AST_ASSIGN(node).from),
- node->loc);
- break;
-
- case AST_INIT: new = gen_init(clone_ast_node(AST_INIT(node).body),
- node->loc);
- break;
-
- case AST_SIZEOF: new = gen_sizeof(clone_ast_node(AST_SIZEOF(node).expr),
- node->loc);
- break;
-
- 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(AST_AS(node).type), node->loc);
- break;
-
- case AST_GOTO: new = gen_goto(clone_ast_node(AST_GOTO(node).label),
- node->loc);
- break;
-
- case AST_LABEL: new = gen_label(clone_ast_node(AST_LABEL(node).id),
- node->loc);
- break;
-
- case AST_BINOP: new = gen_binop(AST_BINOP(node).op,
- clone_ast_node(AST_BINOP(node).left),
- clone_ast_node(AST_BINOP(node).right),
- node->loc);
- break;
-
- case AST_UNOP: new = gen_unop(AST_UNOP(node).op,
- clone_ast_node(AST_UNOP(node).expr),
- node->loc);
- break;
-
- 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(AST_DEFER(node).expr),
- node->loc);
- 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),
- node->loc);
- 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;
-
- case AST_CAST: new = gen_cast(clone_ast_node(AST_CAST(node).expr),
- clone_ast_node(AST_CAST(node).type),
- node->loc);
- break;
-
- case AST_PROC: new = gen_proc(clone_ast_node(AST_PROC(node).id),
- clone_ast_node(AST_PROC(node).sign),
- clone_ast_node(AST_PROC(node).body),
- node->loc);
- break;
-
- 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(AST_FOR(node).pre),
- clone_ast_node(AST_FOR(node).cond),
- clone_ast_node(AST_FOR(node).post),
- clone_ast_node(AST_FOR(node).body),
- node->loc);
- break;
-
- case AST_WHILE: new = gen_while(clone_ast_node(AST_WHILE(node).cond),
- clone_ast_node(AST_WHILE(node).body),
- node->loc);
- break;
-
- case AST_CTRL: new = gen_ctrl(AST_CTRL(node).kind, node->loc);
- break;
-
- case AST_RETURN: new = gen_return(clone_ast_node(AST_RETURN(node).expr),
- node->loc);
- break;
-
- case AST_TYPE:
- switch (node->_type.kind) {
- case AST_TYPE_PRIMITIVE:
- new = gen_primitive(AST_PRIMITIVE_TYPE(node).type,
- AST_PRIMITIVE_TYPE(node).def,
- node->loc);
- break;
-
- case AST_TYPE_TRAIT:
- new = gen_type(AST_TYPE_TRAIT,
- AST_TRAIT_TYPE(node).def,
- NULL,
- node->loc);
- break;
-
- case AST_TYPE_CONSTRUCT:
- new = gen_type(AST_TYPE_CONSTRUCT,
- clone_ast_node(AST_CONSTRUCT_TYPE(
- node).id),
- clone_ast_node(AST_CONSTRUCT_TYPE(
- node).args),
- node->loc);
- break;
-
- case AST_TYPE_ID:
- new = gen_type(AST_TYPE_ID,
- clone_ast_node(AST_ID_TYPE(node).id),
- 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),
- node->loc);
- break;
-
- case AST_TYPE_POINTER:
- new = gen_type(AST_TYPE_POINTER,
- clone_ast_node(AST_PTR_TYPE(node).base),
- NULL,
- node->loc);
- break;
-
- case AST_TYPE_STRUCT:
- new = gen_type(AST_TYPE_STRUCT,
- AST_STRUCT_TYPE(node).def,
- NULL, node->loc);
- break;
-
- case AST_TYPE_ENUM:
- new = gen_type(AST_TYPE_ENUM,
- AST_ENUM_TYPE(node).def,
- 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),
- node->loc);
- break;
-
- }
-
- assert(new);
- AST_TYPE(new).next = clone_ast_node(AST_TYPE(node).next);
- break;
-
- case AST_BLOCK:
- /* TODO: should defers also be cloned? Probably? */
- new = gen_block(clone_ast_node(AST_BLOCK(node).body),
- node->loc);
- break;
-
- case AST_IMPORT:
- new = gen_import(strdup(AST_IMPORT(node).file), node->loc);
- break;
-
- case AST_EMBED:
- new = gen_embed(strdup(AST_EMBED(node).file), node->loc);
- break;
-
- case AST_ENUM:
- new = gen_enum(clone_ast_node(AST_ENUM(node).id),
- clone_ast_node(AST_ENUM(node).type),
- clone_ast_node(AST_ENUM(node).body),
- node->loc);
- break;
-
- case AST_STRUCT:
- new = gen_struct(clone_ast_node(AST_STRUCT(node).id),
- clone_ast_node(AST_STRUCT(node).generics),
- clone_ast_node(AST_STRUCT(node).body),
- node->loc);
- break;
-
- case AST_VAL:
- new = gen_val(clone_ast_node(AST_VAL(node).id),
- clone_ast_node(AST_VAL(node).val),
- node->loc);
- break;
-
- case AST_SWITCH:
- new = gen_switch(clone_ast_node(AST_SWITCH(node).cond),
- clone_ast_node(AST_SWITCH(node).cases),
- node->loc);
- break;
+ if (!root)
+ return;
- case AST_CASE:
- new = gen_case(clone_ast_node(AST_CASE(node).cond),
- clone_ast_node(AST_CASE(node).body),
- node->loc);
- break;
+ foreach_type(t, root) {
+ type_dump(t);
+ }
+}
- case AST_CONST:
- switch (node->_const.kind) {
- case AST_CONST_INTEGER:
- new = gen_int(AST_CONST(node).integer, node->loc);
- break;
+struct ast *clone_ast(struct ast *n)
+{
+ if (!n)
+ return NULL;
- case AST_CONST_STRING:
- new = gen_string(strdup(AST_CONST(node).str),
- node->loc);
- break;
- }
- break;
+ assert(n->k);
+ struct ast *new = create_empty_ast();
+ new->scope = n->scope;
+ new->uses = n->uses;
+ new->loc = n->loc;
+ new->k = n->k;
+ new->v = n->v;
+ new->f = n->f;
- case AST_ID:
- new = gen_id(strdup(AST_ID(node).id), node->loc);
- break;
+ if (n->t)
+ new->t = clone_type_list(n->t);
- case AST_EMPTY:
- new = gen_empty();
- break;
+ if (n->s)
+ new->s = strdup(n->s);
- case AST_ALIAS:
- new = gen_alias(clone_ast_node(AST_ALIAS(node).id),
- clone_ast_node(AST_ALIAS(node).type),
- node->loc);
- break;
+ if (n->a0)
+ new->a0 = clone_ast_list(n->a0);
- case AST_TRAIT:
- new = gen_trait(clone_ast_node(AST_TRAIT(node).id),
- clone_ast_node(AST_TRAIT(node).params),
- clone_ast_node(AST_TRAIT(node).raw_body),
- clone_ast_node(AST_TRAIT(node).body),
- node->loc);
- break;
+ if (n->a1)
+ new->a1 = clone_ast_list(n->a1);
- case AST_IF:
- new = gen_if(clone_ast_node(AST_IF(node).cond),
- clone_ast_node(AST_IF(node).body),
- clone_ast_node(AST_IF(node).els),
- node->loc);
- break;
- }
+ if (n->a2)
+ new->a2 = clone_ast_list(n->a2);
- /* if we run out of memory, this assert is likely a bit dumb... */
- assert(new);
- new->scope = node->scope;
- new->flags = node->flags;
- new->uses = node->uses;
- new->loc = node->loc;
- new->next = clone_ast_node(node->next);
+ if (n->a3)
+ new->a3 = clone_ast_list(n->a3);
- if (node->type != node)
- node->type = clone_ast_node(node->type);
- else
- node->type = node;
+ if (n->t2)
+ new->t2 = clone_type_list(n->t2);
return new;
}
-unsigned ast_flags(struct ast_node *node, enum ast_flag flags)
-{
- return node->flags & flags;
-}
-
-static int call_on_assign(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- int ret = 0;
- ret |= call(AST_ASSIGN(node).to, data);
- ret |= call(AST_ASSIGN(node).from, data);
- return ret;
-}
-
-static int call_on_init(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_INIT(node).body, data);
-}
-
-static int call_on_sizeof(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
+struct type *clone_type(struct type *n)
{
- return call(AST_SIZEOF(node).expr, data);
-}
+ if (!n)
+ return NULL;
-static int call_on_dot(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(AST_DOT(node).expr, data);
- ret |= call(AST_DOT(node).id, data);
- return ret;
-}
+ assert(n->k);
+ struct type *new = create_empty_type();
+ new->scope = n->scope;
+ new->loc = n->loc;
+ new->k = n->k;
+ new->a = n->a;
+ new->d = n->d;
-static int call_on_as(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_AS(node).type, data);
-}
+ if (n->id)
+ new->id = strdup(n->id);
-static int call_on_cast(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(AST_CAST(node).expr, data);
- ret |= call(AST_CAST(node).type, data);
- return ret;
-}
+ if (n->t0)
+ new->t0 = clone_type_list(n->t0);
-static int call_on_defer(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_DEFER(node).expr, data);
-}
+ if (n->t1)
+ new->t1 = clone_type_list(n->t1);
-static int call_on_var(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(AST_VAR(node).id, data);
- ret |= call(AST_VAR(node).type, data);
- ret |= call(AST_VAR(node).init, data);
- return ret;
-}
-
-static int call_on_for(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_for.pre, data);
- ret |= call(node->_for.cond, data);
- ret |= call(node->_for.post, data);
- ret |= call(node->_for.body, data);
- return ret;
+ return new;
}
-static int call_on_while(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
+struct ast *clone_ast_list(struct ast *root)
{
- int ret = 0;
- ret |= call(node->_while.cond, data);
- ret |= call(node->_while.body, data);
- return ret;
-}
+ struct ast *n = root, *new_root = NULL, *prev = NULL;
+ while (n) {
+ struct ast *new = clone_ast(n);
-static int call_on_return(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- return call(node->_return.expr, data);
-}
+ if (prev) prev->n = new;
+ else new_root = new;
-static int call_on_alias(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_alias.id, data);
- ret |= call(node->_alias.type, data);
- return ret;
-}
+ prev = new;
+ n = n->n;
+ }
-static int call_on_trait(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_trait.id, data);
- ret |= call(node->_trait.body, data);
- return ret;
+ return new_root;
}
-static int call_on_if(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
+struct type *clone_type_list(struct type *root)
{
- int ret = 0;
- ret |= call(node->_if.cond, data);
- ret |= call(node->_if.body, data);
- ret |= call(node->_if.els, data);
- return ret;
-}
+ struct type *n = root, *new_root = NULL, *prev = NULL;
+ while (n) {
+ struct type *new = clone_type(n);
-static int call_on_enum(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_enum.id, data);
- ret |= call(node->_enum.type, data);
- ret |= call(node->_enum.body, data);
- return ret;
-}
+ if (prev) prev->n = new;
+ else new_root = new;
-static int call_on_struct(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- int ret = 0;
- ret |= call(node->_struct.id, data);
- ret |= call(node->_struct.generics, data);
- ret |= call(node->_struct.body, data);
- return ret;
-}
+ prev = new;
+ n = n->n;
+ }
-static int call_on_val(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_val.id, data);
- ret |= call(node->_val.val, data);
- return ret;
+ return new_root;
}
-static int call_on_switch(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
+int type_visit(type_callback_t before, type_callback_t after, struct type *n, void *d)
{
int ret = 0;
- ret |= call(node->_switch.cond, data);
- ret |= call(node->_switch.cases, data);
- return ret;
-}
+ if (!n)
+ return ret;
-static int call_on_case(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_case.cond, data);
- ret |= call(node->_case.body, data);
- return ret;
-}
+ if (before && (ret = before(n, d)))
+ return ret;
-static int call_on_type_id(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- return call(AST_ID_TYPE(node).id, data);
-}
+ if (n->t0 && (ret = type_visit_list(before, after, n->t0, d)))
+ return ret;
-static int call_on_type_arr(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- return call(AST_ARR_TYPE(node).size, data);
-}
+ if (n->t1 && (ret = type_visit_list(before, after, n->t1, d)))
+ return ret;
-static int call_on_type_sign(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- int ret = 0;
- ret |= call(AST_SIGN_TYPE(node).params, data);
- ret |= call(AST_SIGN_TYPE(node).ret, data);
- return ret;
-}
+ if (after && (ret = after(n, d)))
+ return ret;
-static int call_on_type_construct(int (*call)(struct ast_node *, void *),
- struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(AST_CONSTRUCT_TYPE(node).id, data);
- ret |= call(AST_CONSTRUCT_TYPE(node).args, data);
return ret;
}
-static int call_on_type_pointer(int (*call)(struct ast_node *, void *),
- struct ast_node *node, void *data)
-{
- return call(AST_PTR_TYPE(node).base, data);
-}
-
-static int call_on_type(int (*call)(struct ast_node *, void *),
- struct ast_node *node, void *data)
+int ast_visit(ast_callback_t before, ast_callback_t after, struct ast *n, void *d)
{
int ret = 0;
- switch (AST_TYPE(node).kind) {
- case AST_TYPE_ENUM: break;
- case AST_TYPE_TRAIT: 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_STRUCT: break;
- case AST_TYPE_SIGN: ret = call_on_type_sign(call, node, data); break;
- case AST_TYPE_CONSTRUCT: ret = call_on_type_construct(call, node, data);
- break;
- case AST_TYPE_POINTER: ret = call_on_type_pointer(call, node, data);
- break;
- case AST_TYPE_PRIMITIVE: break;
- }
-
- return ret;
-}
-
-static int call_on_goto(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_GOTO(node).label, data);
-}
-
-static int call_on_label(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_LABEL(node).id, data);
-}
+ if (!n)
+ return ret;
-static int call_on_binop(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(AST_BINOP(node).left, data);
- ret |= call(AST_BINOP(node).right, data);
- return ret;
-}
+ if (before && (ret = before(n, d)))
+ return ret;
-static int call_on_unop(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(AST_UNOP(node).expr, data);
-}
+ if (n->a0 && (ret = ast_visit_list(before, after, n->a0, d)))
+ return ret;
-static int call_on_call(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(AST_CALL(node).expr, data);
- ret |= call(AST_CALL(node).args, data);
- return ret;
-}
+ if (n->a1 && (ret = ast_visit_list(before, after, n->a1, d)))
+ return ret;
-static int call_on_macro_construct(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
-{
- int ret = 0;
- ret |= call(AST_MACRO_CONSTRUCT(node).id, data);
- ret |= call(AST_MACRO_CONSTRUCT(node).params, data);
- ret |= call(AST_MACRO_CONSTRUCT(node).body, data);
- return ret;
-}
+ if (n->a2 && (ret = ast_visit_list(before, after, n->a2, d)))
+ return ret;
-static int call_on_proc(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_proc.id, data);
- ret |= call(node->_proc.sign, data);
- ret |= call(node->_proc.body, data);
- return ret;
-}
+ if (n->a3 && (ret = ast_visit_list(before, after, n->a3, d)))
+ return ret;
-static int call_on_block(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- return call(node->_block.body, data);
-}
+ if (after && (ret = after(n, d)))
+ return ret;
-static int call_on_fetch(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
-{
- int ret = 0;
- ret |= call(node->_fetch.id, data);
- ret |= call(node->_fetch.type, data);
return ret;
}
-static int call_on_macro_expand(int (*call)(struct ast_node *,
- void *), struct ast_node *node,
- void *data)
+int ast_visit_list(ast_callback_t before, ast_callback_t after, struct ast *l, void *d)
{
int ret = 0;
- ret |= call(node->_macro_expand.id, data);
- ret |= call(node->_macro_expand.args, data);
- return ret;
-}
+ foreach_node(n, l) {
+ if ((ret = ast_visit(before, after, n, d)))
+ return ret;
+ }
-static int call_on_type_expand(int (*call)(struct ast_node *,
- void *),
- struct ast_node *type_expand, void *data)
-{
- int ret = 0;
- ret |= call(AST_TYPE_EXPAND(type_expand).id, data);
- ret |= call(AST_TYPE_EXPAND(type_expand).args, data);
return ret;
}
-/* I guess this works, but it's not exactly optimal as the caller sort of has to
- * know when to continue to call on, and when it would cause an infinite loop.
- * I.e. a call on an ID that is forwarded results in an infinite loop.
- *
- * Maybe add in something like ast_continue_call_on() that can check for the
- * user if there's any point in continuing?
- */
-int ast_call_on(int (*call)(struct ast_node *,
- void *), struct ast_node *node, void *data)
+int type_visit_list(type_callback_t before, type_callback_t after, struct type *l, void *d)
{
int ret = 0;
- if (!node)
- return ret;
-
- switch (node->node_type) {
- case AST_ARR_ACCESS:
- 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;
- case AST_SIZEOF: ret = call_on_sizeof(call, node, data); break;
- case AST_DOT: ret = call_on_dot(call, node, data); break;
- case AST_AS: ret = call_on_as(call, node, data); break;
- case AST_CAST: ret = call_on_cast(call, node, data); break;
- case AST_DEFER: ret = call_on_defer(call, node, data); break;
- case AST_VAR: ret = call_on_var(call, node, data); break;
- case AST_FOR: ret = call_on_for(call, node, data); break;
- case AST_WHILE: ret = call_on_while(call, node, data); break;
- case AST_RETURN: ret = call_on_return(call, node, data); break;
- case AST_ALIAS: ret = call_on_alias(call, node, data); break;
- case AST_TRAIT: ret = call_on_trait(call, node, data); break;
- case AST_IF: ret = call_on_if(call, node, data); break;
- case AST_ENUM: ret = call_on_enum(call, node, data); break;
- case AST_STRUCT: ret = call_on_struct(call, node, data); break;
- case AST_VAL: ret = call_on_val(call, node, data); break;
- case AST_SWITCH: ret = call_on_switch(call, node, data); break;
- case AST_CASE: ret = call_on_case(call, node, data); break;
- case AST_TYPE: ret = call_on_type(call, node, data); break;
- case AST_GOTO: ret = call_on_goto(call, node, data); break;
- case AST_LABEL: ret = call_on_label(call, node, data); break;
- 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_PROC: ret = call_on_proc(call, node, data); break;
- case AST_BLOCK: ret = call_on_block(call, node, data); break;
- case AST_EMBED: break;
- case AST_CTRL: break;
- case AST_IMPORT: break;
- case AST_CONST: break;
- case AST_ID: break;
- case AST_EMPTY: break;
+ foreach_type(n, l) {
+ if ((ret = type_visit(before, after, n, d)))
+ return ret;
}
- ret |= call(node->next, data);
return ret;
}
-size_t ast_list_len(struct ast_node *node)
+size_t ast_list_len(struct ast *node)
{
size_t count = 0;
while (node) {
count++;
- node = node->next;
+ node = node->n;
}
return count;
}
-struct ast_node *ast_last_node(struct ast_node *list)
+struct ast *ast_last(struct ast *list)
{
if (!list)
return NULL;
- while (list->next)
- list = list->next;
+ while (list->n)
+ list = list->n;
return list;
}
-struct ast_node *ast_block_last(struct ast_node *block)
+struct ast *ast_block_last(struct ast *block)
{
- struct ast_node *b = ast_last_node(block);
- if (b && b->node_type == AST_BLOCK)
- return ast_block_last(b->_block.body);
+ struct ast *b = ast_last(block);
+ if (b && b->k == AST_BLOCK)
+ return ast_block_last(block_body(b));
return b;
}
-int same_id(struct ast_node *id1, struct ast_node *id2)
+int same_id(char *id1, char *id2)
{
- assert(id1->node_type == AST_ID);
- assert(id2->node_type == AST_ID);
- return equiv_nodes(id1, id2);
+ return strcmp(id1, id2) == 0;
}
-int equiv_nodes(struct ast_node *n1, struct ast_node *n2)
+int equiv_types(struct type *n1, struct type *n2)
{
- if (n1->node_type != n2->node_type)
+ if (n1 == n2)
+ return 1;
+
+ if (n1 && !n2)
return 0;
- switch (n1->node_type) {
- case AST_ID:
- if (strcmp(AST_ID(n1).id, AST_ID(n2).id) != 0)
- return 0;
+ if (!n1 && n2)
+ return 0;
- break;
- default:
- internal_error("unimplemented equivalency");
+ if (n1->k != n2->k)
+ return 0;
+
+ if (n1->id && strcmp(n1->id, n2->id) != 0)
+ return 0;
+
+ if (n1->t0 && !equiv_type_lists(n1->t0, n2->t0))
+ return 0;
+
+ if (n1->t1 && !equiv_type_lists(n1->t1, n2->t1))
return 0;
- }
return 1;
}
-int equiv_node_chains(struct ast_node *c1, struct ast_node *c2)
+int equiv_nodes(struct ast *n1, struct ast *n2)
{
- if (c1 && !c2)
+ if (n1 && !n2)
return 0;
- if (!c1 && c2)
+
+ if (!n1 && n2)
return 0;
- if (!c1 && !c2)
+ if (!n1 && !n2)
return 1;
+ if (n1->k != n2->k)
+ return 0;
+
+ if (n1->s && strcmp(n1->s, n2->s) != 0)
+ return 0;
+
+ if (n1->a0 && !equiv_node_lists(n1->a0, n2->a0))
+ return 0;
+
+ if (n1->a1 && !equiv_node_lists(n1->a1, n2->a1))
+ return 0;
+
+ if (n1->a2 && !equiv_node_lists(n1->a2, n2->a2))
+ return 0;
+
+ if (n1->a3 && !equiv_node_lists(n1->a3, n2->a3))
+ return 0;
+
+ if (n1->t2 && !equiv_type_lists(n1->t2, n2->t2))
+ return 0;
+
+ return 1;
+}
+
+int equiv_node_lists(struct ast *c1, struct ast *c2)
+{
do {
if (!equiv_nodes(c1, c2))
return 0;
- c1 = c1->next;
- c2 = c2->next;
+ c1 = c1->n;
+ c2 = c2->n;
} while (c1 && c2);
return 1;
}
+
+int equiv_type_lists(struct type *t1, struct type *t2)
+{
+ do {
+ if (!equiv_types(t1, t2))
+ return 0;
+
+ t1 = t1->n;
+ t2 = t2->n;
+
+ } while (t1 && t2);
+
+ return 1;
+}
diff --git a/src/compiler.c b/src/compiler.c
index b345e16..5aa6787 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -85,14 +85,14 @@ static int process(struct scope **parent, int public, const char *file)
if (!p)
return -1;
parse(p, file, buf);
- struct ast_node *tree = p->tree;
+ struct ast *tree = p->tree;
bool failed = p->failed;
destroy_parser(p);
if (failed)
return -1;
- dump_ast(0, tree);
+ ast_dump_list(0, tree);
struct scope *scope = create_scope();
if (!scope)
@@ -167,19 +167,19 @@ int compile(const char *input) {
struct scope *root = NULL;
if (process_file(&root, 0, input)) {
destroy_scope(root);
- destroy_ast_nodes();
+ destroy_allocs();
error("compilation of %s stopped due to errors", input);
return ret;
}
- if ((ret = lower_actuals(root))) {
+ if ((ret = lower(root))) {
destroy_scope(root);
- destroy_ast_nodes();
+ destroy_allocs();
error("compilation of %s stopped due to errors", input);
return ret;
}
destroy_scope(root);
- destroy_ast_nodes();
+ destroy_allocs();
return 0;
}
diff --git a/src/debug.c b/src/debug.c
index 2c873a2..f4b481d 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -120,7 +120,7 @@ void src_issue(struct src_issue issue, const char *err_msg, ...)
va_end(args);
}
-void semantic_error(struct file_ctx fctx, struct ast_node *node,
+void semantic_error(struct file_ctx fctx, struct ast *node,
const char *fmt, ...)
{
va_list args;
@@ -133,7 +133,20 @@ void semantic_error(struct file_ctx fctx, struct ast_node *node,
va_end(args);
}
-void semantic_warn(struct file_ctx fctx, struct ast_node *node, const char *fmt,
+void type_error(struct file_ctx fctx, struct type *node,
+ const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ struct src_issue issue;
+ issue.level = SRC_ERROR;
+ issue.loc = node->loc;
+ issue.fctx = fctx;
+ _issue(issue, fmt, args);
+ va_end(args);
+}
+
+void semantic_warn(struct file_ctx fctx, struct ast *node, const char *fmt,
...)
{
va_list args;
@@ -146,7 +159,20 @@ void semantic_warn(struct file_ctx fctx, struct ast_node *node, const char *fmt,
va_end(args);
}
-void semantic_info(struct file_ctx fctx, struct ast_node *node, const char *fmt,
+void semantic_info(struct file_ctx fctx, struct ast *node, const char *fmt,
+ ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ struct src_issue issue;
+ issue.level = SRC_INFO;
+ issue.loc = node->loc;
+ issue.fctx = fctx;
+ _issue(issue, fmt, args);
+ va_end(args);
+}
+
+void type_info(struct file_ctx fctx, struct type *node, const char *fmt,
...)
{
va_list args;
@@ -185,117 +211,60 @@ void internal_warn(const char *fmt, ...)
* @param fp File pointer to write string representation to.
* @param type Type to generate string representation for.
*/
-static void _type_str(FILE *fp, struct ast_node *type)
+static void _type_str(FILE *fp, struct type *type)
{
if (!type)
return;
- assert(type->node_type == AST_TYPE);
-
- switch (AST_TYPE(type).kind) {
- case AST_TYPE_POINTER:
+ switch (type->k) {
+ case TYPE_PTR:
fputc('*', fp);
- _type_str(fp, AST_PTR_TYPE(type).base);
+ _type_str(fp, ptr_base(type));
break;
- case AST_TYPE_ID: {
- struct ast_node *id = AST_ID_TYPE(type).id;
- fprintf(fp, "%s", AST_ID(id).id);
+ case TYPE_ID: {
+ fprintf(fp, "%s", type->id);
break;
}
- case AST_TYPE_TRAIT: {
- struct ast_node *def = AST_TRAIT_TYPE(type).def;
- if (AST_TRAIT(def).id) {
- struct ast_node *name = AST_TRAIT(def).id;
- fprintf(fp, "%s ", AST_ID(name).id);
+ case TYPE_TRAIT: {
+ struct ast *def = type->d;
+ if (trait_id(def)) {
+ fprintf(fp, "%s ", trait_id(def));
}
fprintf(fp, "(trait)");
break;
}
- case AST_TYPE_STRUCT: {
- struct ast_node *def = AST_STRUCT_TYPE(type).def;
- if (AST_STRUCT(def).id) {
- struct ast_node *name = AST_STRUCT(def).id;
- fprintf(fp, "%s ", AST_ID(name).id);
+ case TYPE_STRUCT: {
+ struct ast *def = type->d;
+ if (struct_id(def)) {
+ fprintf(fp, "%s ", struct_id(def));
}
fprintf(fp, "(struct)");
- /** @todo print out anonymous structs with members? */
- break;
- }
-
- case AST_TYPE_PRIMITIVE: {
- fprintf(fp, "%s", primitive_str(AST_PRIMITIVE_TYPE(type).type));
break;
}
default:
- fprintf(fp, "NOT YET IMPLEMENTED");
+ if (is_primitive(type))
+ fprintf(fp, "%s", primitive_str(type));
+ else
+ fprintf(fp, "UNKNOWN TYPE");
}
-
- _type_str(fp, AST_TYPE(type).next);
}
-char *type_str(struct ast_node *node)
+char *type_str(struct type *t)
{
/* maybe hacky? */
- if (!node)
+ if (!t)
return strdup("void");
char *buf = NULL; size_t size = 0;
+ /* hehe */
FILE *memstream = open_memstream(&buf, &size);
- /* TODO: improve trait detection */
- /* we were given a plain type, pass it directly along to _type_str */
- if (node->node_type == AST_TYPE)
- _type_str(memstream, node);
- else
- /* otherwise, try to fish out the type of the node */
- _type_str(memstream, node->type);
+ _type_str(memstream, t);
fclose(memstream);
return buf;
}
-
-/**
- * Workhorse for call_str().
- *
- * @param f File pointer to write string representation to.
- * @param call Call to generate string representation for.
- */
-static void _call_str(FILE *f, struct ast_node *call)
-{
- 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 = AST_CALL(call).args;
- fprintf(f, "(");
-
- while (args) {
- char *type = type_str(args);
- fprintf(f, "%s", type);
- free(type);
-
- args = args->next;
- if (args)
- fprintf(f, ", ");
- else
- break;
- }
-
- fprintf(f, ")");
-}
-
-char *call_str(struct ast_node *call)
-{
- assert(call->node_type == AST_CALL);
- char *buf = NULL; size_t size = 0;
- FILE *memstream = open_memstream(&buf, &size);
- _call_str(memstream, call);
- fclose(memstream);
- return buf;
-}
diff --git a/src/lexer.l b/src/lexer.l
index c819328..b38833d 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -84,36 +84,26 @@ STRING \"(\\.|[^"\\])*\"
"%" {return REM;}
"^" {return XOR;}
-'[^'\\]' {
- /* regular character constant, 'a' */
- yylval->integer = yytext[1];
- return INT;
+"true" {
+ yylval->integer = 1;
+ return BOOL;
}
-'\\x[0-9a-fA-F]+' {
- /* hex character constant, '\xef' */
- /* handling is slightly different from C, here it's more or less just
- * another way to specify a hex integer */
- yylval->integer = strtoll(yytext + 3, NULL, 16);
- return INT;
-}
-
-'\\[0-8]+' {
- /* octal character constant, '\033' */
- yylval->integer = strtoll(yytext + 2, NULL, 8);
- return INT;
+"false" {
+ yylval->integer = 0;
+ return BOOL;
}
-'\\b[01]+' {
- /* binary character constant, '\b101' */
- yylval->integer = strtoll(yytext + 3, NULL, 2);
- return INT;
+'[^'\\]' {
+ /* regular character constant, 'a' */
+ yylval->integer = yytext[1];
+ return CHAR;
}
'\\.' {
/* escaped character constant */
yylval->integer = match_escape(yytext[2]);
- return INT;
+ return CHAR;
}
"?" {return QUESTION;}
@@ -185,7 +175,7 @@ STRING \"(\\.|[^"\\])*\"
}
{ID} {
- yylval->str = yytext;
+ yylval->str = strdup(yytext);
return ID;
}
@@ -194,7 +184,7 @@ STRING \"(\\.|[^"\\])*\"
char *s = yytext + strlen(yytext);
s[-1] = '\0';
- yylval->str = yytext;
+ yylval->str = strdup(yytext);
return APPLY;
}
diff --git a/src/lower.c b/src/lower.c
index c78ac96..bf36fae 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -108,12 +108,17 @@ static bool retval_is_const(struct retval r)
return r.kind == CONST_I9 || r.kind == CONST_I27;
}
-static bool is_i9(struct ast_node *n)
+static bool is_small_type(struct type *type)
{
- if (AST_TYPE(n->type).kind != AST_TYPE_PRIMITIVE)
- return false;
+ switch (type->k) {
+ case TYPE_I9:
+ case TYPE_BOOL:
+ return true;
- return AST_PRIMITIVE_TYPE(n->type).type == AST_I9;
+ default:
+ }
+
+ return false;
}
#define retval_create() \
@@ -157,26 +162,27 @@ char *build_str(const char *fmt, ...) {
return buf;
}
-static size_t get_scope_number(struct ast_node *id)
+static size_t get_scope_number(struct ast *id)
{
/** @todo this mirrors what's in actualize.c:actualize_id, same comments
* apply */
- struct ast_node *def = file_scope_find_var(id->scope, id);
+ struct ast *def = file_scope_find_var(id->scope, id->s);
if (def)
return def->scope->number;
- def = file_scope_find_proc(id->scope, id);
+ def = file_scope_find_proc(id->scope, id->s);
if (def)
return def->scope->number;
return 0;
}
-static char *mangle_idx(struct ast_node *id, size_t idx)
+static char *mangle_idx(struct ast *id, size_t idx)
{
- assert(id->node_type == AST_ID);
assert(id->scope);
- const char *name = AST_ID(id).id;
+ assert(id->s);
+
+ const char *name = id->s;
/* oh wait, I need to do a variable lookup on the ID, not use the ID's
* scope number, duh */
size_t number = get_scope_number(id);
@@ -187,89 +193,74 @@ static char *mangle_idx(struct ast_node *id, size_t idx)
return build_str("%s_s%zif%zi", name, number, idx);
}
-static char *mangle(struct ast_node *id)
+static char *mangle(struct ast *id)
{
return mangle_idx(id, 0);
}
-static int lower_expr(struct lower_state *s, struct ast_node *e,
+static int lower_expr(struct lower_state *s, struct ast *e,
struct vec *retval);
-static int lower_statement(struct lower_state *s, struct ast_node *n);
+static int lower_statement(struct lower_state *s, struct ast *n);
-static void output_id(struct ast_node *id)
+static void output_ast_id(struct ast *id)
{
+ assert(id->s);
char *name = mangle(id);
printf("%s", name);
free(name);
}
-static int lower_global_var(struct ast_node *n)
+static int lower_global_var(struct ast *n)
{
/* trivial types are reasonably easy, but stuff like compound types need
* a lot of work */
- struct ast_node *type = AST_VAR(n).type;
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE) {
+ struct type *type = var_type(n);
+ if (is_primitive(type)) {
semantic_error(n->scope->fctx, n,
"only primitive globals currently implemented");
return -1;
}
- struct ast_node *id = AST_VAR(n).id;
- struct ast_node *init = AST_VAR(n).init;
- if (init->node_type != AST_CONST) {
+ struct ast *init = var_init(n);
+ if (init->k != AST_CONST_INT) {
semantic_error(n->scope->fctx, n,
- "constant expressions currently not implemented");
+ "only constant expressions currently implemented");
return -1;
}
- output_id(id);
+ output_ast_id(n);
printf(" = ");
/* hmm, this might be useful elsewhere as well */
- switch (AST_PRIMITIVE_TYPE(type).type) {
- case AST_I27: printf("i27 %lli", AST_CONST(init).integer); break;
- case AST_I9: printf("i9 %lli", AST_CONST(init).integer); break;
- default:
- semantic_error(n->scope->fctx, n,
- "unhandled primitive type");
- return -1;
- }
-
+ char *t = is_small_type(type) ? "i9" : "i27";
+ printf("%s %lli", t, int_val(init));
printf(";\n");
return 0;
}
-static int lower_param(struct lower_state *s, struct ast_node *p)
+static int lower_param(struct lower_state *s, struct ast *p)
{
UNUSED(s);
- assert(p->node_type == AST_VAR);
- struct ast_node *type = AST_VAR(p).type;
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE) {
+ assert(p->k == AST_VAR_DEF);
+ struct type *type = var_type(p);
+ if (!is_primitive(type)) {
semantic_error(p->scope->fctx, p,
"only primitive params currently implemented");
return -1;
}
- assert(AST_VAR(p).init == NULL);
-
- switch (AST_PRIMITIVE_TYPE(type).type) {
- case AST_I27: printf("i27 "); break;
- case AST_I9: printf("i9 "); break;
- default:
- semantic_error(p->scope->fctx, p,
- "unhandled primitive type");
- return -1;
- }
+ assert(var_init(p) == NULL);
- struct ast_node *id = AST_VAR(p).id;
- output_id(id);
+ char *t = is_small_type(type) ? "i9" : "i27";
+ printf("%s ", t);
+ output_ast_id(p);
printf(",");
return 0;
}
-static int lower_params(struct lower_state *s, struct ast_node *params)
+static int lower_params(struct lower_state *s, struct ast *params)
{
- for (struct ast_node *p = params; p; p = p->next) {
+ foreach_node(p, params) {
if (lower_param(s, p))
return -1;
}
@@ -277,20 +268,19 @@ static int lower_params(struct lower_state *s, struct ast_node *params)
return 0;
}
-static int lower_var(struct lower_state *s, struct ast_node *v,
+static int lower_var(struct lower_state *s, struct ast *v,
struct vec *retval)
{
- assert(v->node_type == AST_VAR);
+ assert(v->k == AST_VAR_DEF);
struct vec input = retval_create();
- if (lower_expr(s, AST_VAR(v).init, &input))
+ if (lower_expr(s, var_init(v), &input))
return -1;
- struct ast_node *id = AST_VAR(v).id;
/* if we have a struct, we should add the member name to the base name
* */
foreach_retval(ri, input) {
struct retval r = retval_at(input, ri);
- char *name = mangle_idx(id, ri);
+ char *name = mangle_idx(v, ri);
/* I assume we're always dealing with i27 for now */
/** @todo qbt could maybe skip the type stuff except for casts */
printf("i27 %s = %s;\n", name, r.s);
@@ -355,27 +345,24 @@ static void do_store(struct lower_state *s, struct vec *from, struct vec *to,
}
}
-static int lower_cast(struct lower_state *s, struct ast_node *e,
+static int lower_cast(struct lower_state *s, struct ast *e,
struct vec *retval)
{
- assert(e->node_type == AST_CAST);
+ assert(e->k == AST_CAST);
/** @todo make sure actualize removes casts that aren't of these types
* */
- assert(AST_TYPE(e->type).kind == AST_TYPE_PRIMITIVE
- || AST_TYPE(e->type).kind == AST_TYPE_POINTER);
+ assert(is_primitive(e->t));
- if (lower_expr(s, AST_CAST(e).expr, retval))
+ if (lower_expr(s, cast_expr(e), retval))
return -1;
- enum retval_kind kind = REG_I27;
- if (is_i9(e))
- kind = REG_I9;
+ enum retval_kind kind = is_small_type(e->t) ? REG_I9 : REG_I27;
foreach_retval(ri, *retval) {
struct retval r = retval_at(*retval, ri);
/* build new temporary cast result and replace the previous
* retval */
- char *s = build_str("%s%s", "cast_", r.s);
+ char *s = build_str("%s%s", "cast", r.s);
printf("%s %s = %s;\n", retval_kind_str(kind), s, r.s);
free(r.s);
@@ -388,49 +375,35 @@ static int lower_cast(struct lower_state *s, struct ast_node *e,
return 0;
}
-static int lower_const(struct lower_state *s, struct ast_node *c,
+static int lower_const(struct lower_state *s, struct ast *c,
struct vec *retval)
{
UNUSED(s);
- assert(c->node_type == AST_CONST);
- if (AST_CONST(c).kind == AST_CONST_STRING) {
- /* requires pushing strings as variables and replacing them with
- * references */
- semantic_error(c->scope->fctx, c,
- "string constant lowering not yet implemented");
- return -1;
- }
-
- enum retval_kind type = CONST_I27;
- if (AST_PRIMITIVE_TYPE(c->type).type == AST_I9)
- type = CONST_I9;
-
- char *str = build_str("%lli", (long long int)AST_CONST(c).integer);
- struct retval r = build_retval(type, str);
+ assert(is_const(c));
+ char *str = build_str("%lli", (long long)c->v);
+ enum retval_kind kind = is_small_type(c->t) ? CONST_I9: CONST_I27;
+ struct retval r = build_retval(kind, str);
vec_append(retval, &r);
return 0;
}
-static int lower_assign(struct lower_state *s, struct ast_node *a,
+static int lower_assign(struct lower_state *s, struct ast *a,
struct vec *retval)
{
-#define IS_DEREF(t) (t->node_type == AST_UNOP && AST_UNOP(t).op == AST_DEREF)
-#define IS_ARR(t) (t->node_type == AST_ARR_ACCESS)
-
- assert(a->node_type == AST_ASSIGN);
- if (lower_expr(s, AST_ASSIGN(a).from, retval))
+ assert(a->k == AST_ASSIGN);
+ if (lower_expr(s, assign_from(a), retval))
return -1;
struct vec loc = retval_create();
struct vec off = retval_create();
- struct ast_node *to = AST_ASSIGN(a).to;
- struct ast_node *base = to;
- if (IS_DEREF(to))
- base = AST_UNOP(to).expr;
- else if (IS_ARR(to)) {
- base = AST_ARR_ACCESS(to).base;
- if (lower_expr(s, AST_ARR_ACCESS(to).idx, &off)) {
+ struct ast *to = assign_to(a);
+ struct ast *base = to;
+ if (to->k == AST_DEREF)
+ base = unop_expr(to);
+ else if (to->k == AST_ARR) {
+ base = arr_base(to);
+ if (lower_expr(s, arr_idx(to), &off)) {
retval_destroy(&loc);
retval_destroy(&off);
return -1;
@@ -443,10 +416,10 @@ static int lower_assign(struct lower_state *s, struct ast_node *a,
return -1;
}
- if (IS_DEREF(to)) {
+ if (to->k == AST_DEREF) {
do_store(s, retval, &loc, NULL);
}
- else if (IS_ARR(to)) {
+ else if (to->k == AST_ARR) {
do_store(s, retval, &loc, &off);
} else {
assert(vec_len(retval) == vec_len(&loc));
@@ -464,29 +437,25 @@ static int lower_assign(struct lower_state *s, struct ast_node *a,
#undef IS_ARR
}
-static int lower_id(struct lower_state *s, struct ast_node *id,
+static int lower_id(struct lower_state *s, struct ast *id,
struct vec *retval)
{
UNUSED(s);
- assert(id->node_type == AST_ID);
+ assert(id->k == AST_ID);
char *m = mangle(id);
- struct ast_node *type = id->type;
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE
- && AST_TYPE(type).kind != AST_TYPE_POINTER
- && AST_TYPE(type).kind != AST_TYPE_SIGN) {
+ struct type *type = id->t;
+ if (!is_primitive(type) && type->k != TYPE_CALLABLE) {
semantic_error(id->scope->fctx, id,
"only primitive ids currently implemented");
return -1;
}
- enum retval_kind kind = REG_I27;
- if (is_i9(id))
- kind = REG_I9;
+ enum retval_kind kind = is_small_type(type) ? REG_I9 : REG_I27;
/* this likely isn't enough and we need to add the & to most things we
* want to take the address of */
- if (AST_TYPE(type).kind == AST_TYPE_SIGN) {
+ if (type->k == TYPE_CALLABLE) {
char *o = m;
m = build_str("&%s", m);
free(o);
@@ -497,11 +466,12 @@ static int lower_id(struct lower_state *s, struct ast_node *id,
return 0;
}
-static int lower_return(struct lower_state *s, struct ast_node *r,
+static int lower_return(struct lower_state *s, struct ast *r,
struct vec *retval)
{
- assert(r->node_type == AST_RETURN);
- if (lower_expr(s, AST_RETURN(r).expr, retval))
+ assert(r->k == AST_RETURN);
+ /** @todo defers, should they be handled here or in ast? */
+ if (lower_expr(s, return_expr(r), retval))
return -1;
printf("=> ( ");
@@ -515,11 +485,11 @@ static int lower_return(struct lower_state *s, struct ast_node *r,
return 0;
}
-static int lower_if(struct lower_state *s, struct ast_node *i,
+static int lower_if(struct lower_state *s, struct ast *i,
struct vec *retval)
{
- assert(i->node_type == AST_IF);
- if (lower_expr(s, AST_IF(i).cond, retval))
+ assert(i->k == AST_IF);
+ if (lower_expr(s, if_cond(i), retval))
return -1;
assert(vec_len(retval) == 1);
@@ -533,7 +503,7 @@ static int lower_if(struct lower_state *s, struct ast_node *i,
printf("! %s -> %s;\n", (retval_at(*retval, 0)).s, bottom);
/* a block counts as a statement in this case */
- if (lower_statement(s, AST_IF(i).body)) {
+ if (lower_statement(s, if_body(i))) {
free(bottom);
return -1;
}
@@ -542,7 +512,7 @@ static int lower_if(struct lower_state *s, struct ast_node *i,
printf("%s:\n", bottom);
free(bottom);
- if (AST_IF(i).els && lower_statement(s, AST_IF(i).els)) {
+ if (if_else(i) && lower_statement(s, if_else(i))) {
free(out);
return -1;
}
@@ -552,11 +522,11 @@ static int lower_if(struct lower_state *s, struct ast_node *i,
return 0;
}
-static int lower_for(struct lower_state *s, struct ast_node *f,
+static int lower_for(struct lower_state *s, struct ast *f,
struct vec *retval)
{
- assert(f->node_type == AST_FOR);
- if (lower_statement(s, AST_FOR(f).pre))
+ assert(f->k == AST_FOR);
+ if (lower_statement(s, for_pre(f)))
return -1;
long long uniq = s->uniq++;
@@ -570,19 +540,19 @@ static int lower_for(struct lower_state *s, struct ast_node *f,
printf("-> %s;\n", out);
printf("%s:\n", top);
- if (lower_statement(s, AST_FOR(f).body)) {
+ if (lower_statement(s, for_body(f))) {
pop_loop(s);
return -1;
}
printf("%s:\n", bottom);
- if (lower_statement(s, AST_FOR(f).post)) {
+ if (lower_statement(s, for_post(f))) {
pop_loop(s);
return -1;
}
printf("%s:\n", out);
- if (lower_expr(s, AST_FOR(f).cond, retval)) {
+ if (lower_expr(s, for_cond(f), retval)) {
pop_loop(s);
return -1;
}
@@ -594,7 +564,7 @@ static int lower_for(struct lower_state *s, struct ast_node *f,
return 0;
}
-static int lower_expr_if(struct lower_state *s, struct ast_node *i,
+static int lower_expr_if(struct lower_state *s, struct ast *i,
struct vec *retval)
{
semantic_error(i->scope->fctx, i,
@@ -602,19 +572,19 @@ static int lower_expr_if(struct lower_state *s, struct ast_node *i,
return 0;
}
-static int lower_binop(struct lower_state *s, struct ast_node *i,
+static int lower_binop(struct lower_state *s, struct ast *i,
struct vec *retval)
{
struct vec l = retval_create();
struct vec r = retval_create();
- if (lower_expr(s, AST_BINOP(i).left, &l)) {
+ if (lower_expr(s, binop_left(i), &l)) {
retval_destroy(&l);
retval_destroy(&r);
return -1;
}
- if (lower_expr(s, AST_BINOP(i).right, &r)) {
+ if (lower_expr(s, binop_right(i), &r)) {
retval_destroy(&l);
retval_destroy(&r);
return -1;
@@ -623,12 +593,12 @@ static int lower_binop(struct lower_state *s, struct ast_node *i,
assert(vec_len(&l) == 1);
assert(vec_len(&r) == 1);
- char *name = build_str("tmp%lli", (long long)s->uniq++);
+ char *name = build_str("binop%lli", (long long)s->uniq++);
struct retval ret = build_retval(REG_I27, name);
vec_append(retval, &ret);
char *op = "";
- switch (AST_BINOP(i).op) {
+ switch (i->k) {
case AST_ADD: op = "+"; break;
case AST_SUB: op = "-"; break;
case AST_MUL: op = "*"; break;
@@ -636,6 +606,50 @@ static int lower_binop(struct lower_state *s, struct ast_node *i,
case AST_REM: op = "%"; break;
case AST_LSHIFT: op = "<<"; break;
case AST_RSHIFT: op = ">>"; break;
+ default: semantic_error(i->scope->fctx, i,
+ "unimplemented binary operation");
+ retval_destroy(&l);
+ retval_destroy(&r);
+ return -1;
+ }
+
+ printf("i27 %s = %s %s %s;\n", name,
+ (retval_at(l, 0)).s,
+ op,
+ (retval_at(r, 0)).s);
+
+ retval_destroy(&l);
+ retval_destroy(&r);
+ return 0;
+}
+
+static int lower_comparison(struct lower_state *s, struct ast *i, struct vec *retval)
+{
+ /* very similar to lower_binop, hmm */
+ struct vec l = retval_create();
+ struct vec r = retval_create();
+
+ if (lower_expr(s, comparison_left(i), &l)) {
+ retval_destroy(&l);
+ retval_destroy(&r);
+ return -1;
+ }
+
+ if (lower_expr(s, comparison_right(i), &r)) {
+ retval_destroy(&l);
+ retval_destroy(&r);
+ return -1;
+ }
+
+ assert(vec_len(&l) == 1);
+ assert(vec_len(&r) == 1);
+
+ char *name = build_str("comp%lli", (long long)s->uniq++);
+ struct retval ret = build_retval(REG_I27, name);
+ vec_append(retval, &ret);
+
+ char *op = "";
+ switch (i->k) {
case AST_LT: op = "<"; break;
case AST_GT: op = ">"; break;
case AST_LE: op = "<="; break;
@@ -643,13 +657,13 @@ static int lower_binop(struct lower_state *s, struct ast_node *i,
case AST_NE: op = "!="; break;
case AST_EQ: op = "=="; break;
default: semantic_error(i->scope->fctx, i,
- "unimplemented binary operation");
+ "unimplemented comparison operation");
retval_destroy(&l);
retval_destroy(&r);
return -1;
}
- printf("i27 %s = %s %s %s;\n", name,
+ printf("i9 %s = %s %s %s;\n", name,
(retval_at(l, 0)).s,
op,
(retval_at(r, 0)).s);
@@ -659,20 +673,20 @@ static int lower_binop(struct lower_state *s, struct ast_node *i,
return 0;
}
-static int lower_call(struct lower_state *s, struct ast_node *c,
+static int lower_call(struct lower_state *s, struct ast *c,
struct vec *retval)
{
- assert(c->node_type == AST_CALL);
+ assert(c->k == AST_CALL);
struct vec call = retval_create();
- if (lower_expr(s, AST_CALL(c).expr, &call)) {
+ if (lower_expr(s, call_expr(c), &call)) {
retval_destroy(&call);
return -1;
}
/* collect all args */
struct vec args = retval_create();
- foreach_node(a, AST_CALL(c).args) {
+ foreach_node(a, call_args(c)) {
struct vec arg = retval_create();
if (lower_expr(s, a, &arg)) {
retval_destroy(&arg);
@@ -699,37 +713,51 @@ static int lower_call(struct lower_state *s, struct ast_node *c,
printf("%s, ", r.s);
}
-#define IS_VOID(t) \
- (t->node_type == AST_TYPE && AST_TYPE(t).kind == AST_TYPE_PRIMITIVE && \
- AST_PRIMITIVE_TYPE(t).type == AST_VOID)
-
- if (!IS_VOID(c->type)) {
+ if (!is_primitive(c->t) && c->t->k != TYPE_VOID) {
semantic_error(c->scope->fctx, c,
- "only void return type implemented");
+ "only primitive return types implemented");
retval_destroy(&args);
return -1;
}
- printf(") => ();\n");
+ printf(") => ( ");
+
+ int i = 0;
+ foreach_type(t, c->t) {
+ char *s = build_str("r%i\n", i);
+ enum retval_kind k = is_small_type(t) ? REG_I9 : REG_I27;
+ struct retval r = build_retval(k, s);
+ vec_append(retval, &r);
+ i++;
+ }
+
+ printf(" );\n");
retval_destroy(&args);
return 0;
}
-static int lower_expr(struct lower_state *s, struct ast_node *e,
+static int lower_expr(struct lower_state *s, struct ast *e,
struct vec *retval)
{
if (!e)
return 0;
- switch (e->node_type) {
+ if (is_const(e))
+ return lower_const(s, e, retval);
+
+ if (is_binop(e))
+ return lower_binop(s, e, retval);
+
+ if (is_comparison(e))
+ return lower_comparison(s, e, retval);
+
+ switch (e->k) {
+ case AST_VAR_DEF: return lower_var(s, e, retval);
case AST_ID: return lower_id(s, e, retval);
/* var is considered an expression in this case */
- case AST_VAR: return lower_var(s, e, retval);
case AST_CAST: return lower_cast(s, e, retval);
- case AST_CONST: return lower_const(s, e, retval);
case AST_RETURN: return lower_return(s, e, retval);
case AST_ASSIGN: return lower_assign(s, e, retval);
- case AST_BINOP: return lower_binop(s, e, retval);
case AST_CALL: return lower_call(s, e, retval);
case AST_IF: return lower_expr_if(s, e, retval);
default:
@@ -741,25 +769,24 @@ static int lower_expr(struct lower_state *s, struct ast_node *e,
return 0;
}
-static int lower_block(struct lower_state *s, struct ast_node *body)
+static int lower_block(struct lower_state *s, struct ast *block)
{
- assert(body->node_type == AST_BLOCK);
- assert(!ast_flags(body, AST_FLAG_DOEXPR));
- struct ast_node *stmt = AST_BLOCK(body).body;
- for (; stmt; stmt = stmt->next) {
- if (lower_statement(s, stmt))
+ assert(block->k == AST_BLOCK);
+ assert(!ast_flags(block, AST_FLAG_DOEXPR));
+ foreach_node(n, block_body(block)) {
+ if (lower_statement(s, n))
return -1;
}
return 0;
}
-static int lower_statement(struct lower_state *s, struct ast_node *n)
+static int lower_statement(struct lower_state *s, struct ast *n)
{
struct vec retval = retval_create();
int ret = 0;
- switch (n->node_type) {
+ switch (n->k) {
case AST_RETURN: ret = lower_return(s, n, &retval); break;
case AST_IF: ret = lower_if(s, n, &retval); break;
case AST_FOR: ret = lower_for(s, n, &retval); break;
@@ -771,24 +798,22 @@ static int lower_statement(struct lower_state *s, struct ast_node *n)
return ret;
}
-static int lower_proc(struct ast_node *n)
+static int lower_proc(struct ast *n)
{
- assert(n->node_type == AST_PROC);
+ assert(n->k == AST_PROC_DEF);
/* nobody uses the proc, so no need to do anything */
- if (n->uses == 0 && !ast_flags(AST_PROC(n).id, AST_FLAG_NOMANGLE))
+ if (n->uses == 0 && !ast_flags(n, AST_FLAG_NOMANGLE))
return 0;
struct lower_state state = create_state();
/* name */
- struct ast_node *id = AST_PROC(n).id;
- output_id(id);
+ output_ast_id(n);
/* args */
printf("(");
- struct ast_node *sign = AST_PROC(n).sign;
- if (lower_params(&state, AST_SIGN_TYPE(sign).params)) {
+ if (lower_params(&state, proc_params(n))) {
destroy_state(&state);
return -1;
}
@@ -799,7 +824,7 @@ static int lower_proc(struct ast_node *n)
/* body */
printf("{\n");
- if (lower_block(&state, AST_PROC(n).body)) {
+ if (lower_block(&state, proc_body(n))) {
destroy_state(&state);
return -1;
}
@@ -809,19 +834,13 @@ static int lower_proc(struct ast_node *n)
return 0;
}
-static int lower_actual(struct ast_node *n)
-{
- assert(AST_TYPE(n).kind == AST_TYPE_CONSTRUCT);
- return 0;
-}
-
-static int _lower_actuals(struct scope *root)
+int lower(struct scope *root)
{
/* go through all child scopes but only do actual work on file-scope
* includes are allowed inside procs etc to make something only locally
* visible */
for (struct scope *c = root->children; c; c = c->next) {
- if (_lower_actuals(c))
+ if (lower(c))
return -1;
}
@@ -842,17 +861,3 @@ static int _lower_actuals(struct scope *root)
return 0;
}
-
-int lower_actuals(struct scope *root)
-{
- int ret = _lower_actuals(root);
- /* actuals are currently global, would it make more sense for them to be
- * scope-local? */
- for (struct actual *a = root->actuals; a; a = a->next) {
- assert(a->node);
- if (lower_actual(a->node))
- return -1;
- }
-
- return ret;
-}
diff --git a/src/parser.y b/src/parser.y
index d6aefc8..51d950c 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -11,6 +11,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
+
#include <ek/parser.h>
%}
@@ -26,12 +28,15 @@
%parse-param {void *scanner} {struct parser* parser}
%union {
- struct ast_node *node;
+ struct ast *node;
+ struct type *type;
long long integer;
char *str;
};
%token <integer> INT
+%token <integer> CHAR
+%token <integer> BOOL
%token <dbl> FLOAT
%token <str> STRING
%token <str> ID
@@ -122,16 +127,18 @@
%left "::"
/* why doesn't bison allow <*> for %nterm? would be so much easier */
-%nterm <node> import binop unop decls expr
+%nterm <node> import binop unop decls opt_decls expr
%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_decl var
%nterm <node> var_init proc
%nterm <node> alias trait enum_val enums enum top unit id
%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 types
+%nterm <node> statelet apply
+
+%nterm <type> types type opt_type
%nterm <node> tagged_struct expr_if
@@ -140,14 +147,15 @@
%nterm <node> macro_expand type_expand
-%nterm <node> type_params type_param opt_for_inits for_inits for_init
+%nterm <node> type_params opt_type_params type_param opt_for_inits for_inits for_init
/* array stuff */
%nterm <node> arr arr_inits arr_init
/* optional stuff */
%nterm <node> opt_exprs proc_decl member opt_members
-%nterm <node> opt_statements opt_types opt_type_params
+%nterm <node> opt_statements
+%nterm <type> opt_types opt_sign_decls sign_decls sign_decl sign_var_decl
%{
@@ -209,7 +217,7 @@ static void yyerror(YYLTYPE *yylloc, void *lexer,
* @param c Escape character without backslash.
* @return Corresponding value.
*/
-static long long match_escape(char c);
+static char match_escape(char c);
/**
* Similar to strdup() but skips quotation marks that would
@@ -219,18 +227,18 @@ static long long match_escape(char c);
* @param s String to clone, with quotation marks surrounding it.
* @return Identical string but without quotation marks around it.
*/
-static const char *clone_string(const char *s);
+static char *strip(const char *s);
%}
%start input;
%%
id
- : ID {$$ = gen_id(strdup($1), src_loc(@$));}
+ : ID {$$ = gen_id($1, src_loc(@$));}
apply
: APPLY {
- $$ = gen_id(strdup($1), src_loc(@$));
+ $$ = gen_id($1, src_loc(@$));
}
var
@@ -238,10 +246,10 @@ var
| var_init
embed
- : "embed" "(" STRING ")" { $$ = gen_embed(clone_string($3), src_loc(@$)); }
+ : "embed" "(" STRING ")" { $$ = gen_embed(strip($3), src_loc(@$)); }
import
- : "import" STRING { $$ = gen_import(clone_string($2), src_loc(@$)); }
+ : "import" STRING { $$ = gen_import(strip($2), src_loc(@$)); }
assign
: expr "=" expr { $$ = gen_assign($1, $3, src_loc(@$)); }
@@ -265,12 +273,12 @@ binop
| expr ">>=" expr {
$$ = gen_binop(AST_ASSIGN_RSHIFT, $1, $3, src_loc(@$));
}
- | expr "<" expr { $$ = gen_binop(AST_LT, $1, $3, src_loc(@$)); }
- | expr ">" expr { $$ = gen_binop(AST_GT, $1, $3, src_loc(@$)); }
- | expr "<=" expr { $$ = gen_binop(AST_LE, $1, $3, src_loc(@$)); }
- | expr ">=" expr { $$ = gen_binop(AST_GE, $1, $3, src_loc(@$)); }
- | expr "!=" expr { $$ = gen_binop(AST_NE, $1, $3, src_loc(@$)); }
- | expr "==" expr { $$ = gen_binop(AST_EQ, $1, $3, src_loc(@$)); }
+ | expr "<" expr { $$ = gen_comparison(AST_LT, $1, $3, src_loc(@$)); }
+ | expr ">" expr { $$ = gen_comparison(AST_GT, $1, $3, src_loc(@$)); }
+ | expr "<=" expr { $$ = gen_comparison(AST_LE, $1, $3, src_loc(@$)); }
+ | expr ">=" expr { $$ = gen_comparison(AST_GE, $1, $3, src_loc(@$)); }
+ | expr "!=" expr { $$ = gen_comparison(AST_NE, $1, $3, src_loc(@$)); }
+ | expr "==" expr { $$ = gen_comparison(AST_EQ, $1, $3, src_loc(@$)); }
unop
: "-" expr { $$ = gen_unop(AST_NEG, $2, src_loc(@$)); }
@@ -280,15 +288,17 @@ unop
arr_init
: "=>" const_expr "..." const_expr "=" expr {
- $$ = gen_var($2, $4, $6, src_loc(@$));
+ assert(0 && "range array init is unimplemented");
+ abort();
}
| "=>" const_expr "=" expr {
- $$ = gen_var($2, NULL, $4, src_loc(@$));
+ assert(0 && "range array init is unimplemented");
+ abort();
}
| expr
arr_inits
- : arr_init "," arr_inits { $$ = $1; $1->next = $3; }
+ : arr_init "," arr_inits { $$ = $1; $1->n = $3; }
| arr_init
arr
@@ -298,10 +308,22 @@ param_decl
: type { $$ = gen_var(NULL, $1, NULL, src_loc(@$)); }
| var_decl
+sign_decl
+ : type
+ | sign_var_decl
+
decls
- : param_decl "," decls { $$ = $1; $1->next = $3; }
+ : param_decl "," decls { $$ = $1; $1->n = $3; }
| param_decl
+sign_decls
+ : sign_decl "," sign_decls { $$ = $1; $1->n = $3; }
+ | sign_decl
+
+opt_decls
+ : decls
+ | {$$ = NULL;}
+
defer
: "defer" body { $$ = gen_defer($2, src_loc(@$)); }
@@ -352,19 +374,20 @@ const_unop
const_expr
: "(" const_expr ")" { $$ = $2; }
- | INT { $$ = gen_int($1, src_loc(@$)); }
+ | INT { $$ = gen_const_int($1, src_loc(@$)); }
+ | CHAR { $$ = gen_const_char($1, src_loc(@$)); }
+ | BOOL { $$ = gen_const_bool($1, src_loc(@$)); }
| const_binop
| const_unop
| id
/* TODO: concatenate multiple strings together? Or is that the lexer's job? */
expr
- : expr "." id { $$ = gen_dot($1, $3, src_loc(@$)); }
- | "..." id { $$ = $2; }
- | INT { $$ = gen_int($1, src_loc(@$)); }
- | STRING {
- $$ = gen_string(clone_string($1), src_loc(@$));
- }
+ : expr "." ID { $$ = gen_dot($3, $1, src_loc(@$)); }
+ | INT { $$ = gen_const_int($1, src_loc(@$)); }
+ | CHAR { $$ = gen_const_char($1, src_loc(@$)); }
+ | BOOL { $$ = gen_const_bool($1, src_loc(@$)); }
+ | STRING {$$ = gen_const_str(strip($1), src_loc(@$));}
| "(" expr ")" { $$ = $2; }
/* special rule, user is allowed to define new variables in if
* statements etc but it should stand out, which is why we require
@@ -381,10 +404,10 @@ expr
| "do" switch { $$ = $2; ast_set_flags($$, AST_FLAG_DOEXPR); }
| "do" "const" switch { $$ = $3; ast_set_flags($$, AST_FLAG_DOEXPR); }
| expr "(" opt_exprs ")" { $$ = gen_call($1, $3, src_loc(@$)); }
- | expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); }
+ | expr "[" expr "]" { $$ = gen_arr($1, $3, src_loc(@$)); }
| "sizeof" expr { $$ = gen_sizeof($2, src_loc(@$)); }
| expr "as" type { $$ = gen_cast($1, $3, src_loc(@$)); }
- | id "::" type { $$ = gen_fetch($1, $3, src_loc(@$)); }
+ | ID "::" type { $$ = gen_fetch($1, $3, src_loc(@$)); }
| macro_expand
| construct
| assign
@@ -404,13 +427,13 @@ do_while
}
goto
- : "goto" id { $$ = gen_goto(gen_label($2, src_loc(@$)), src_loc(@$)); }
+ : "goto" ID { $$ = gen_goto($[ID], NULL, src_loc(@$)); }
statelet
- : "return" exprs { $$ = gen_return($2, src_loc(@$)); }
- | "return" { $$ = gen_return(NULL, src_loc(@$)); }
- | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(@$)); }
- | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(@$)); }
+ : "return" exprs { $$ = gen_return($2, NULL, src_loc(@$)); }
+ | "return" { $$ = gen_return(NULL, NULL, src_loc(@$)); }
+ | "break" { $$ = gen_break(NULL, src_loc(@$)); }
+ | "continue" { $$ = gen_continue(NULL, src_loc(@$)); }
| trait
| import
| alias
@@ -420,7 +443,7 @@ statelet
| error {
/* TODO: figure out how to destroy any and all possible ast nodes we
* may have generated up until the error */
- $$ = gen_empty();
+ $$ = gen_empty(src_loc(@$));
parser->failed = true;
/* If we're failing to parse a statement in a block, continue by trying to
* parse the next statement in the block */
@@ -444,11 +467,11 @@ statement
| const
| enum
| macro
- | ";" { $$ = gen_empty(); }
- | id ":" { $$ = gen_label($1, src_loc(@$)); }
+ | ";" { $$ = gen_empty(src_loc(@$)); }
+ | ID ":" { $$ = gen_label($[ID], NULL, src_loc(@$)); }
statements
- : statement statements { $$ = $1; $1->next = $2; }
+ : statement statements { $$ = $1; $1->n = $2; }
| statement
| statelet
@@ -457,49 +480,49 @@ opt_statements
| {$$ = NULL;}
body
- : "{" opt_statements "}" { $$ = gen_block($2, src_loc(@$)); }
+ : "{" opt_statements "}" { $$ = gen_block($2, NULL, src_loc(@$)); }
references
- : id "," references { $$ = $1; $$->next = $3; }
+ : id "," references { $$ = $1; $$->n = $3; }
| "..." id { $$ = $2; ast_set_flags($$, AST_FLAG_VARIADIC); }
| id
macro
- : "define" id "(" references ")" body {
- $$ = gen_macro_construct($2, $4, $6, src_loc(@$));
+ : "define" ID "(" references ")" body {
+ $$ = gen_macro_def($[ID], $[references], $[body], src_loc(@$));
ast_set_flags($6, AST_FLAG_UNHYGIENIC);
}
- | "define" id "(" references "..." id ")" body {
+ | "define" ID "(" references "..." id ")" body {
ast_append($4, $6);
- $$ = gen_macro_construct($2, $4, $8, src_loc(@$));
+ $$ = gen_macro_def($[ID], $4, $8, src_loc(@$));
ast_set_flags($$, AST_FLAG_VARIADIC);
ast_set_flags($8, AST_FLAG_UNHYGIENIC);
}
- | "define" id "(" ")" body {
- $$ = gen_macro_construct($2, NULL, $5, src_loc(@$));
+ | "define" ID "(" ")" body {
+ $$ = gen_macro_def($[ID], NULL, $5, src_loc(@$));
ast_set_flags($5, AST_FLAG_UNHYGIENIC);
}
exprs
- : expr "," exprs { $$ = $1; $1->next = $3; }
+ : expr "," exprs { $$ = $1; $1->n = $3; }
| expr
construct_arg
- : "." id "=" expr {
+ : "." ID "=" expr {
$$ = gen_var($2, NULL, $4, src_loc(@$));
ast_set_flags($$, AST_FLAG_MEMBER);
}
construct_args
- : construct_arg "," construct_args { $$ = $1; $1->next = $3; }
+ : construct_arg "," construct_args { $$ = $1; $1->n = $3; }
| construct_arg
construct
- : apply "{" construct_args "}" {
+ : APPLY "{" construct_args "}" {
/** @todo add type info? */
$$ = gen_init($3, src_loc(@$));
}
- | apply "[" opt_types "]" "{" construct_args "}" {
+ | APPLY "[" opt_types "]" "{" construct_args "}" {
$$ = gen_init($6, src_loc(@$));
}
@@ -521,7 +544,7 @@ for_init
| var_init
for_inits
- : for_init "," for_inits { $$ = $1; $$->next = $3; }
+ : for_init "," for_inits { $$ = $1; $$->n = $3; }
| for_init
opt_for_inits
@@ -543,7 +566,7 @@ case
}
cases
- : case cases { $$ = $1; $1->next = $2; }
+ : case cases { $$ = $1; $1->n = $2; }
| case
switch
@@ -578,41 +601,43 @@ const
: "const" const_if { $$ = $2; ast_set_flags($$, AST_FLAG_CONST); }
| "const" const_for { $$ = $2; ast_set_flags($$, AST_FLAG_CONST); }
-func_sign
- : "(" decls "=>" type ")" {
- $$ = gen_type(AST_TYPE_SIGN, $2, $4, src_loc(@$));
- }
- | "(" 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(@$)); }
+opt_sign_decls
+ : sign_decls
+ | {$$ = NULL;}
type
- : id { $$ = gen_type(AST_TYPE_ID, $1, NULL, src_loc(@$)); }
- | "^" func_sign {
+ : ID { $$ = tgen_id($1, src_loc(@$)); }
+ | "^" "(" opt_sign_decls "=>" opt_type ")" {
/* still not entirely sold on this signature, but it's not terrible I
* guess */
- $$ = gen_type(AST_TYPE_POINTER, $2, NULL, src_loc(@$));
+ $$ = tgen_callable($[opt_sign_decls], $[opt_type], src_loc(@$));
+ }
+ | "^" "(" opt_sign_decls ")" {
+ $$ = tgen_callable($[opt_sign_decls], NULL, src_loc(@$));
}
| "*" type {
- $$ = gen_type(AST_TYPE_POINTER, $2, NULL, src_loc(@$));
+ $$ = tgen_ptr($2, src_loc(@$));
}
| "[" const_expr "]" type {
- $$ = gen_type(AST_TYPE_ARR, $2, $4, src_loc(@$));
+ assert(0 && "arrays unimplemented");
+ abort();
}
| "const" type {
$$ = $2;
}
| "mut" type {
- $$ = $2; ast_set_flags($$, AST_FLAG_MUTABLE);
+ $$ = $2; /* ignored for now */
}
- | apply "[" opt_types "]" {
- $$ = gen_type(AST_TYPE_CONSTRUCT, $1, $3, src_loc(@$));
+ | APPLY "[" opt_types "]" {
+ $$ = tgen_construct($[APPLY], $[opt_types], src_loc(@$));
}
+opt_type
+ : type
+ | {$$ = NULL;}
+
types
- : type "," types { $$ = $1; $$->next = $3; }
+ : type "," types { $$ = $1; $$->n = $3; }
| type
opt_types
@@ -620,32 +645,56 @@ opt_types
| { $$ = NULL; }
type_expand
- : apply "[" opt_types "]" { $$ = gen_type_expand($1, $3, src_loc(@$)); }
+ : APPLY "[" opt_types "]" { $$ = gen_type_expand($1, $3, src_loc(@$)); }
var_decl
- : type id { $$ = gen_var($2, $1, NULL, src_loc(@$)); }
+ : type ID { $$ = gen_var($2, $1, NULL, src_loc(@$)); }
+
+sign_var_decl
+ : type ID { $$ = $1; free((void *)$[ID]);}
var_init
- : var_decl "=" expr { $$ = $1; $$->_var.init = $3; }
- | "const" id "=" expr { $$ = gen_var($2, NULL, $4, src_loc(@$)); }
- | "mut" id "=" expr {
+ : var_decl "=" expr { $$ = $1; var_init($$) = $3; }
+ | "const" ID "=" expr { $$ = gen_var($2, NULL, $4, src_loc(@$)); }
+ | "mut" ID "=" expr {
$$ = 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(@$));
+ : ID "(" opt_decls "=>" opt_type ")" {
+ $$ = gen_proc($[ID],
+ $[opt_decls],
+ $[opt_type],
+ NULL,
+ src_loc(@$));
}
+ | ID "(" opt_decls ")" {
+ $$ = gen_proc($[ID], $[opt_decls], NULL, NULL, src_loc(@$));
+ }
+
proc
- : id func_sign body {
- $$ = gen_proc($1, $2, $3, src_loc(@$));
- ast_set_flags($$, $2->flags);
- ast_set_flags($3, AST_FLAG_UNHYGIENIC);
+ : ID "(" opt_decls "=>" opt_type ")" body {
+ $$ = gen_proc($[ID],
+ $[opt_decls],
+ $[opt_type],
+ $[body],
+ src_loc(@$));
+ }
+ | ID "(" opt_decls ")" body {
+ $$ = gen_proc($[ID], $[opt_decls], NULL, $[body], src_loc(@$));
+ }
+ | "extern" ID "(" opt_decls "=>" opt_type ")" {
+ $$ = gen_proc($[ID],
+ $[opt_decls],
+ $[opt_type],
+ NULL,
+ src_loc(@$));
+
+ ast_set_flags($$, AST_FLAG_EXTERN);
}
- | "extern" id func_sign {
- /* todo check that we don't have a variadic function */
- $$ = gen_proc($2, $3, NULL, src_loc(@$));
+ | "extern" ID "(" opt_decls ")" {
+ $$ = gen_proc($[ID], $[opt_decls], NULL, NULL, src_loc(@$));
ast_set_flags($$, AST_FLAG_EXTERN);
}
@@ -657,7 +706,7 @@ member
;
members
- : member members { $$ = $1; $1->next = $2; }
+ : member members { $$ = $1; $1->n = $2; }
| member
opt_members
@@ -665,31 +714,31 @@ opt_members
| {$$ = NULL;}
macro_expand
- : apply "(" opt_exprs ")" {
+ : APPLY "(" opt_exprs ")" {
$$ = gen_macro_expand($1, $3, src_loc(@$));
}
tagged_struct
- : "typedef" id "[" opt_type_params "]" "{" opt_members "}" {
+ : "typedef" ID "[" opt_type_params "]" "{" opt_members "}" {
$$ = gen_struct($2, $4, $7, src_loc(@$));
}
- | "typedef" id "{" opt_members "}" {
+ | "typedef" ID "{" opt_members "}" {
$$ = gen_struct($2, NULL, $4, src_loc(@$));
}
alias
- : "typedef" id type {
+ : "typedef" ID type {
$$ = gen_alias($2, $3, src_loc(@$));
}
type_param
- : id id {
- struct ast_node *t = gen_type(AST_TYPE_ID, $1, NULL, src_loc(@1));
+ : ID ID {
+ struct type *t = tgen_id($1, src_loc(@1));
$$ = gen_var($2, t, NULL, src_loc(@$));
}
type_params
- : type_param "," type_params { $$ = $1; $1->next = $3; }
+ : type_param "," type_params { $$ = $1; $1->n = $3; }
| type_param
opt_type_params
@@ -697,28 +746,28 @@ opt_type_params
| { $$ = NULL; }
trait
- : "define" id "[" opt_type_params "]" "{" opt_members "}" {
- $$ = gen_trait($2, $4, $7, NULL, src_loc(@$));
+ : "define" ID "[" opt_type_params "]" "{" opt_members "}" {
+ $$ = gen_trait($2, $4, $7, src_loc(@$));
}
enum_val
- : id {
+ : ID {
$$ = gen_val($1, NULL, src_loc(@$));
}
- | id "=" expr {
+ | ID "=" expr {
$$ = gen_val($1, $3, src_loc(@$));
}
enums
- : enum_val "," enums { $$ = $1; $1->next = $3; }
+ : enum_val "," enums { $$ = $1; $1->n = $3; }
| enum_val "," { $$ = $1; }
| enum_val { $$ = $1; }
enum
- : "enum" id ":" type "{" enums "}" {
+ : "enum" ID ":" type "{" enums "}" {
$$ = gen_enum($2, $4, $6, src_loc(@$));
}
- | "enum" id "{" enums "}" {
+ | "enum" ID "{" enums "}" {
$$ = gen_enum($2, NULL, $4, src_loc(@$));
ast_set_flags($$, AST_FLAG_UNTYPED);
}
@@ -755,9 +804,9 @@ top
| "pub" import { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" alias { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
| "pub" trait { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); }
- | ";" { $$ = gen_empty(); }
+ | ";" { $$ = gen_empty(src_loc(@$)); }
| error {
- $$ = gen_empty();
+ $$ = gen_empty(src_loc(@$));
parser->failed = true;
/* ignore any content inside a top level thing and just move onto
* the next one */
@@ -770,7 +819,7 @@ top
unit
: top { $$ = $1; }
- | top unit { $$ = $1; $1->next = $2; }
+ | top unit { $$ = $1; $1->n = $2; }
input
: unit { parser->tree = $1; }
@@ -832,7 +881,7 @@ static void yyerror(YYLTYPE *yylloc, void *lexer,
src_issue(issue, msg);
}
-static long long match_escape(char c)
+static char match_escape(char c)
{
switch (c) {
case '\'': return '\'';
@@ -849,13 +898,14 @@ static long long match_escape(char c)
return c;
}
-static const char *clone_string(const char *str)
+static char *strip(const char *str)
{
const size_t len = strlen(str) + 1;
char *buf = malloc(len);
if (!buf) {
/* should probably try to handle the error in some way... */
internal_error("failed allocating buffer for string clone");
+ free((void *)str);
return NULL;
}
@@ -871,6 +921,7 @@ static const char *clone_string(const char *str)
}
buf[j] = 0;
+ free((void *)str);
return buf;
}
diff --git a/src/scope.c b/src/scope.c
index 205e858..13c3dce 100644
--- a/src/scope.c
+++ b/src/scope.c
@@ -74,14 +74,13 @@ void scope_set_flags(struct scope *scope, enum scope_flags flags)
scope->flags |= flags;
}
-int scope_flags(struct scope *scope, enum scope_flags flags)
+unsigned scope_flags(struct scope *scope, enum scope_flags flags)
{
assert(scope);
return scope->flags & flags;
}
-static struct visible *create_visible(struct ast_node *id,
- struct ast_node *node)
+static struct visible *create_visible(char *id, struct ast *node)
{
struct visible *visible = calloc(1, sizeof(struct visible));
visible->id = id;
@@ -89,8 +88,7 @@ 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, char *id, struct ast *type)
{
struct visible *n = create_visible(id, type);
if (!n)
@@ -102,8 +100,7 @@ struct visible *create_type(struct scope *scope, struct ast_node *id,
return n;
}
-struct visible *create_var(struct scope *scope, struct ast_node *id,
- struct ast_node *var)
+struct visible *create_var(struct scope *scope, char *id, struct ast *var)
{
struct visible *n = create_visible(id, var);
if (!n)
@@ -115,8 +112,7 @@ struct visible *create_var(struct scope *scope, struct ast_node *id,
return n;
}
-struct visible *create_macro(struct scope *scope, struct ast_node *id,
- struct ast_node *macro)
+struct visible *create_macro(struct scope *scope, char *id, struct ast *macro)
{
struct visible *n = create_visible(id, macro);
if (!n)
@@ -128,8 +124,7 @@ struct visible *create_macro(struct scope *scope, struct ast_node *id,
return n;
}
-struct visible *create_proc(struct scope *scope, struct ast_node *id,
- struct ast_node *proc)
+struct visible *create_proc(struct scope *scope, char *id, struct ast *proc)
{
struct visible *n = create_visible(id, proc);
if (!n)
@@ -141,16 +136,16 @@ struct visible *create_proc(struct scope *scope, struct ast_node *id,
return n;
}
-int scope_add_var(struct scope *scope, struct ast_node *var)
+int scope_add_var(struct scope *scope, struct ast *var)
{
- struct ast_node *exists = file_scope_find_var(scope, AST_VAR(var).id);
+ struct ast *exists = file_scope_find_var(scope, var_id(var));
if (exists) {
semantic_error(scope->fctx, var, "var redefined");
semantic_info(scope->fctx, exists, "previously here");
return -1;
}
- create_var(scope, AST_VAR(var).id, var);
+ create_var(scope, var_id(var), var);
if (scope->parent &&
scope_flags(scope, SCOPE_FILE) && ast_flags(var, AST_FLAG_PUBLIC))
return scope_add_var(scope->parent, var);
@@ -158,10 +153,9 @@ int scope_add_var(struct scope *scope, struct ast_node *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, char *id, struct ast *type)
{
- struct ast_node *exists = file_scope_find_type(scope, id);
+ struct ast *exists = file_scope_find_type(scope, id);
if (exists) {
semantic_error(scope->fctx, type, "type redefined");
semantic_info(scope->fctx, exists, "previously here");
@@ -176,12 +170,10 @@ int scope_add_type(struct scope *scope, struct ast_node *id,
return 0;
}
-int scope_add_macro(struct scope *scope, struct ast_node *macro)
+int scope_add_macro(struct scope *scope, struct ast *macro)
{
- assert(macro->node_type == AST_MACRO_CONSTRUCT);
- struct ast_node *exists = file_scope_find_macro(scope,
- AST_MACRO_CONSTRUCT(
- macro).id);
+ assert(macro->k == AST_MACRO_DEF);
+ struct ast *exists = file_scope_find_macro(scope, macro_def_id(macro));
if (exists) {
semantic_error(scope->fctx, macro, "macro redefined");
semantic_info(scope->fctx, exists, "previously here");
@@ -189,7 +181,7 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro)
}
/* always add to scope, do resolve checking later */
- create_macro(scope, AST_MACRO_CONSTRUCT(macro).id, macro);
+ create_macro(scope, macro_def_id(macro), macro);
if (scope->parent &&
scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC))
return scope_add_macro(scope->parent, macro);
@@ -197,11 +189,10 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro)
return 0;
}
-int scope_add_proc(struct scope *scope, struct ast_node *proc)
+int scope_add_proc(struct scope *scope, struct ast *proc)
{
- assert(proc->node_type == AST_PROC);
- struct ast_node *exists =
- file_scope_find_proc(scope, AST_PROC(proc).id);
+ assert(proc->k == AST_PROC_DEF);
+ struct ast *exists = file_scope_find_proc(scope, proc_id(proc));
if (exists) {
semantic_error(scope->fctx, proc, "proc redefined");
semantic_info(scope->fctx, exists, "previously here");
@@ -209,7 +200,7 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc)
}
/* always add to scope, do resolve checking later */
- create_proc(scope, AST_PROC(proc).id, proc);
+ create_proc(scope, proc_id(proc), proc);
if (scope->parent &&
scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC))
return scope_add_proc(scope->parent, proc);
@@ -217,12 +208,12 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc)
return 0;
}
-int scope_add_trait(struct scope *scope, struct ast_node *trait)
+int scope_add_trait(struct scope *scope, struct ast *trait)
{
- assert(trait->node_type == AST_TRAIT);
+ assert(trait->k == AST_TRAIT_DEF);
- struct ast_node *id = AST_TRAIT(trait).id;
- struct ast_node *exists = file_scope_find_type(scope, id);
+ char *id = trait_id(trait);
+ struct ast *exists = file_scope_find_type(scope, id);
if (exists) {
semantic_error(scope->fctx, trait, "type redefined");
semantic_info(scope->fctx, exists, "previously here");
@@ -237,105 +228,96 @@ int scope_add_trait(struct scope *scope, struct ast_node *trait)
return 0;
}
-static struct ast_node *scope_find_visible(struct visible *v,
- struct ast_node *id)
+static struct ast *scope_find_visible(struct visible *v, char *id)
{
if (!v)
return NULL;
- while (v) {
- if (same_id(v->id, id))
- return v->node;
-
- v = v->next;
+ foreach_visible(n, v) {
+ struct ast *node = n->node;
+ if (same_id(node->s, id))
+ return node;
}
return NULL;
}
-struct ast_node *scope_find_type(struct scope *scope, struct ast_node *type)
+struct ast *scope_find_type(struct scope *scope, char *id)
{
- return scope_find_visible(scope->types, type);
+ return scope_find_visible(scope->types, id);
}
-struct ast_node *file_scope_find_type(struct scope *scope,
- struct ast_node *type)
+struct ast *file_scope_find_type(struct scope *scope, char *id)
{
- assert(type->node_type == AST_ID);
if (!scope)
return NULL;
- struct ast_node *found = scope_find_type(scope, type);
+ struct ast *found = scope_find_type(scope, id);
if (found)
return found;
if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_find_type(scope->parent, type);
+ return file_scope_find_type(scope->parent, id);
return NULL;
}
-struct ast_node *scope_find_macro(struct scope *scope, struct ast_node *macro)
+struct ast *scope_find_macro(struct scope *scope, char *id)
{
- return scope_find_visible(scope->macros, macro);
+ return scope_find_visible(scope->macros, id);
}
-struct ast_node *file_scope_find_macro(struct scope *scope,
- struct ast_node *macro)
+struct ast *file_scope_find_macro(struct scope *scope, char *id)
{
- assert(macro->node_type == AST_ID);
if (!scope)
return NULL;
- struct ast_node *found = scope_find_macro(scope, macro);
+ struct ast *found = scope_find_macro(scope, id);
if (found)
return found;
if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_find_macro(scope->parent, macro);
+ return file_scope_find_macro(scope->parent, id);
return NULL;
}
-struct ast_node *scope_find_proc(struct scope *scope, struct ast_node *proc)
+struct ast *scope_find_proc(struct scope *scope, char *id)
{
- return scope_find_visible(scope->procs, proc);
+ return scope_find_visible(scope->procs, id);
}
-struct ast_node *file_scope_find_proc(struct scope *scope,
- struct ast_node *proc)
+struct ast *file_scope_find_proc(struct scope *scope, char *id)
{
- assert(proc->node_type == AST_ID);
if (!scope)
return NULL;
- struct ast_node *found = scope_find_proc(scope, proc);
+ struct ast *found = scope_find_proc(scope, id);
if (found)
return found;
if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_find_proc(scope->parent, proc);
+ return file_scope_find_proc(scope->parent, id);
return NULL;
}
-struct ast_node *scope_find_var(struct scope *scope, struct ast_node *var)
+struct ast *scope_find_var(struct scope *scope, char *id)
{
- return scope_find_visible(scope->vars, var);
+ return scope_find_visible(scope->vars, id);
}
-struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *var)
+struct ast *file_scope_find_var(struct scope *scope, char *id)
{
- assert(var->node_type == AST_ID);
if (!scope)
return NULL;
- struct ast_node *found = scope_find_var(scope, var);
+ struct ast *found = scope_find_var(scope, id);
if (found)
return found;
if (!scope_flags(scope, SCOPE_FILE))
- return file_scope_find_var(scope->parent, var);
+ return file_scope_find_var(scope->parent, id);
return NULL;
}
@@ -355,7 +337,7 @@ void scope_add_scope(struct scope *parent, struct scope *child)
parent->children = child;
}
-static int add_actual(struct actual *actuals, struct ast_node *node)
+static int add_actual(struct actual *actuals, struct ast *node)
{
if (!actuals->node) {
/* fill empty first element */
@@ -374,7 +356,7 @@ static int add_actual(struct actual *actuals, struct ast_node *node)
return 0;
}
-int scope_add_actual(struct scope *scope, struct ast_node *node)
+int scope_add_actual(struct scope *scope, struct ast *node)
{
return add_actual(scope->actuals, node);
}
diff --git a/tests/if2.ek b/tests/if2.ek
index b41b389..7589571 100644
--- a/tests/if2.ek
+++ b/tests/if2.ek
@@ -11,17 +11,17 @@ main()
{
if 0 {
for i27 i = 0; i < 5; i = i + 1 {
- putchar('0' + i);
+ putchar('0' + i as i9);
}
}
else if 1 {
for i27 i = 0; i < 5; i = i + 1 {
- putchar('A' + i);
+ putchar('A' + i as i9);
}
}
else {
for i27 i = 0; i < 5; i = i + 1 {
- putchar('K' + i);
+ putchar('K' + i as i9);
}
}
diff --git a/tests/loop.ek b/tests/loop.ek
index 301e7ea..265d09f 100644
--- a/tests/loop.ek
+++ b/tests/loop.ek
@@ -1,5 +1,6 @@
typedef i9 {}
typedef i27 {}
+typedef bool {}
putchar(i9 c)
{
@@ -10,6 +11,6 @@ putchar(i9 c)
main()
{
for i27 i = 0; i < 5; i = i + 1 {
- putchar('A' + i);
+ putchar('A' + (i as i9));
}
}