Commit a94ad9e89c

Andrew Kelley <superjoe30@gmail.com>
2016-01-29 10:17:51
parseh defines can reference other defines
1 parent c1691af
src/parseh.cpp
@@ -20,6 +20,11 @@
 
 using namespace clang;
 
+struct MacroSymbol {
+    Buf *name;
+    Buf *value;
+};
+
 struct Context {
     ImportTableEntry *import;
     ZigList<ErrorMsg *> *errors;
@@ -27,13 +32,14 @@ struct Context {
     VisibMod visib_mod;
     bool have_c_void_decl_node;
     AstNode *root;
-    HashMap<Buf *, bool, buf_hash, buf_eql_buf> root_type_table;
+    HashMap<Buf *, bool, buf_hash, buf_eql_buf> root_name_table;
     HashMap<Buf *, bool, buf_hash, buf_eql_buf> struct_type_table;
     HashMap<Buf *, bool, buf_hash, buf_eql_buf> enum_type_table;
     HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
     HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
     SourceManager *source_manager;
     ZigList<AstNode *> aliases;
+    ZigList<MacroSymbol> macro_symbols;
 };
 
 static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl);
@@ -169,7 +175,7 @@ static AstNode *add_typedef_node(Context *c, Buf *new_name, AstNode *target_node
     }
     AstNode *node = create_var_decl_node(c, buf_ptr(new_name), target_node);
 
-    c->root_type_table.put(new_name, true);
+    c->root_name_table.put(new_name, true);
     c->root->data.root.top_level_decls.append(node);
     return node;
 }
@@ -453,7 +459,7 @@ static AstNode *make_qual_type_node_with_table(Context *c, QualType qt, const De
 }
 
 static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl) {
-    return make_qual_type_node_with_table(c, qt, decl, &c->root_type_table);
+    return make_qual_type_node_with_table(c, qt, decl, &c->root_name_table);
 }
 
 static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
@@ -576,13 +582,12 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
             emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name));
             return;
         }
-        Buf enum_val_name = BUF_INIT;
-        buf_init_from_str(&enum_val_name, decl_name(enum_const));
+        Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
 
         Buf field_name = BUF_INIT;
 
-        if (buf_starts_with_buf(&enum_val_name, bare_name)) {
-            Buf *slice = buf_slice(&enum_val_name, buf_len(bare_name), buf_len(&enum_val_name));
+        if (buf_starts_with_buf(enum_val_name, bare_name)) {
+            Buf *slice = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
             if (valid_symbol_starter(buf_ptr(slice)[0])) {
                 buf_init_from_buf(&field_name, slice);
             } else {
@@ -590,7 +595,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
                 buf_appendf(&field_name, "_%s", buf_ptr(slice));
             }
         } else {
-            buf_init_from_buf(&field_name, &enum_val_name);
+            buf_init_from_buf(&field_name, enum_val_name);
         }
 
         AstNode *field_node = create_struct_field_node(c, buf_ptr(&field_name), create_symbol_node(c, "void"));
@@ -598,8 +603,9 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
 
         // in C each enum value is in the global namespace. so we put them there too.
         AstNode *field_access_node = create_field_access_node(c, buf_ptr(full_type_name), buf_ptr(&field_name));
-        AstNode *var_node = create_var_decl_node(c, buf_ptr(&enum_val_name), field_access_node);
+        AstNode *var_node = create_var_decl_node(c, buf_ptr(enum_val_name), field_access_node);
         var_decls.append(var_node);
+        c->root_name_table.put(enum_val_name, true);
     }
 
     normalize_parent_ptrs(node);
@@ -704,18 +710,25 @@ static bool decl_visitor(void *context, const Decl *decl) {
     return true;
 }
 
+static bool name_exists(Context *c, Buf *name) {
+    if (c->root_name_table.maybe_get(name)) {
+        return true;
+    }
+    if (c->fn_table.maybe_get(name)) {
+        return true;
+    }
+    if (c->macro_table.maybe_get(name)) {
+        return true;
+    }
+    return false;
+}
+
 static void render_aliases(Context *c) {
     for (int i = 0; i < c->aliases.length; i += 1) {
         AstNode *alias_node = c->aliases.at(i);
         assert(alias_node->type == NodeTypeVariableDeclaration);
         Buf *name = &alias_node->data.variable_declaration.symbol;
-        if (c->root_type_table.maybe_get(name)) {
-            continue;
-        }
-        if (c->fn_table.maybe_get(name)) {
-            continue;
-        }
-        if (c->macro_table.maybe_get(name)) {
+        if (name_exists(c, name)) {
             continue;
         }
         c->root->data.root.top_level_decls.append(alias_node);
@@ -791,7 +804,30 @@ static int parse_c_num_lit_unsigned(Buf *buf, uint64_t *out_val) {
     return 0;
 }
 
+static bool is_simple_symbol(Buf *buf) {
+    bool first = true;
+    for (int i = 0; i < buf_len(buf); i += 1) {
+        uint8_t c = buf_ptr(buf)[i];
+        bool valid_alpha = (c >= 'a' && c <= 'z') ||
+            (c >= 'A' && c <= 'Z') || c == '_';
+        bool valid_digit = (c >= '0' && c <= '9');
+
+        bool ok = (valid_alpha || (!first && valid_digit));
+        first = false;
+
+        if (!ok) {
+            return false;
+        }
+    }
+    return true;
+}
+
 static void process_macro(Context *c, Buf *name, Buf *value) {
+    //fprintf(stderr, "macro '%s' = '%s'\n", buf_ptr(name), buf_ptr(value));
+    if (is_zig_keyword(name)) {
+        return;
+    }
+
     // maybe it's a character literal
     uint8_t ch;
     if (!parse_c_char_lit(value, &ch)) {
@@ -811,7 +847,20 @@ static void process_macro(Context *c, Buf *name, Buf *value) {
     }
 
     // maybe it's a symbol
-    // TODO
+    if (is_simple_symbol(value)) {
+        c->macro_symbols.append({name, value});
+    }
+}
+
+static void process_symbol_macros(Context *c) {
+    for (int i = 0; i < c->macro_symbols.length; i += 1) {
+        MacroSymbol ms = c->macro_symbols.at(i);
+        if (name_exists(c, ms.value)) {
+            AstNode *var_node = create_var_decl_node(c, buf_ptr(ms.name),
+                    create_symbol_node(c, buf_ptr(ms.value)));
+            c->macro_table.put(ms.name, var_node);
+        }
+    }
 }
 
 static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
@@ -885,7 +934,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors,
     c->import = import;
     c->errors = errors;
     c->visib_mod = VisibModPub;
-    c->root_type_table.init(8);
+    c->root_name_table.init(8);
     c->enum_type_table.init(8);
     c->struct_type_table.init(8);
     c->fn_table.init(8);
@@ -991,6 +1040,8 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors,
 
     process_preprocessor_entities(c, *ast_unit);
 
+    process_symbol_macros(c);
+
     render_macros(c);
     render_aliases(c);
 
src/tokenizer.cpp
@@ -97,6 +97,22 @@
     ALPHA: \
     case '_'
 
+const char * zig_keywords[] = {
+    "true", "false", "null", "fn", "return", "var", "const", "extern",
+    "pub", "export", "import", "c_import", "if", "else", "goto", "asm",
+    "volatile", "struct", "enum", "while", "for", "continue", "break",
+    "null", "noalias", "switch", "undefined", "error"
+};
+
+bool is_zig_keyword(Buf *buf) {
+    for (int i = 0; i < array_length(zig_keywords); i += 1) {
+        if (buf_eql_str(buf, zig_keywords[i])) {
+            return true;
+        }
+    }
+    return false;
+}
+
 enum TokenizeState {
     TokenizeStateStart,
     TokenizeStateSymbol,
src/tokenizer.hpp
@@ -131,5 +131,6 @@ int get_digit_value(uint8_t c);
 const char * token_name(TokenId id);
 
 bool valid_symbol_starter(uint8_t c);
+bool is_zig_keyword(Buf *buf);
 
 #endif
test/run_tests.cpp
@@ -1998,10 +1998,19 @@ pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;)OUTPUT",
 #define CHANNEL_COUNT 24
     )SOURCE", 1, R"OUTPUT(pub const CHANNEL_COUNT = 24;)OUTPUT");
 
+
     add_parseh_case("overide previous #define", R"SOURCE(
 #define A_CHAR 'a'
 #define A_CHAR 'b'
     )SOURCE", 1, "pub const A_CHAR = 'b';");
+
+
+    add_parseh_case("#define referencing another #define", R"SOURCE(
+#define THING2 THING1
+#define THING1 1234
+    )SOURCE", 2,
+            "pub const THING1 = 1234;",
+            "pub const THING2 = THING1;");
 }
 
 static void print_compiler_invocation(TestCase *test_case) {