Commit 474340a003
Changed files (5)
src/ast_render.cpp
@@ -73,13 +73,20 @@ static const char *visib_mod_string(VisibMod mod) {
}
static const char *extern_string(bool is_extern) {
- return is_extern ? "export " : "";
+ return is_extern ? "extern " : "";
}
static const char *const_or_var_string(bool is_const) {
return is_const ? "const" : "var";
}
+static const char *container_string(ContainerKind kind) {
+ switch (kind) {
+ case ContainerKindEnum: return "enum";
+ case ContainerKindStruct: return "struct";
+ }
+}
+
static const char *node_type_str(NodeType node_type) {
switch (node_type) {
case NodeTypeRoot:
@@ -486,6 +493,10 @@ static void print_indent(AstRender *ar) {
}
}
+static bool is_node_void(AstNode *node) {
+ return node->type == NodeTypeSymbol && buf_eql_str(&node->data.symbol_expr.symbol, "void");
+}
+
static void render_node(AstRender *ar, AstNode *node) {
assert(node->type == NodeTypeRoot || *node->parent_field == node);
@@ -533,9 +544,7 @@ static void render_node(AstRender *ar, AstNode *node) {
fprintf(ar->f, ")");
AstNode *return_type_node = node->data.fn_proto.return_type;
- bool is_void = return_type_node->type != NodeTypeSymbol &&
- buf_eql_str(&return_type_node->data.symbol_expr.symbol, "void");
- if (!is_void) {
+ if (!is_node_void(return_type_node)) {
fprintf(ar->f, " -> ");
render_node(ar, return_type_node);
}
@@ -601,7 +610,13 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeSliceExpr:
zig_panic("TODO");
case NodeTypeFieldAccessExpr:
- zig_panic("TODO");
+ {
+ AstNode *lhs = node->data.field_access_expr.struct_expr;
+ Buf *rhs = &node->data.field_access_expr.field_name;
+ render_node(ar, lhs);
+ fprintf(ar->f, ".%s", buf_ptr(rhs));
+ break;
+ }
case NodeTypeImport:
zig_panic("TODO");
case NodeTypeCImport:
@@ -640,15 +655,19 @@ static void render_node(AstRender *ar, AstNode *node) {
{
const char *struct_name = buf_ptr(&node->data.struct_decl.name);
const char *pub_str = visib_mod_string(node->data.struct_decl.visib_mod);
- fprintf(ar->f, "%sstruct %s {\n", pub_str, struct_name);
+ const char *container_str = container_string(node->data.struct_decl.kind);
+ fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name);
ar->indent += ar->indent_size;
for (int field_i = 0; field_i < node->data.struct_decl.fields.length; field_i += 1) {
AstNode *field_node = node->data.struct_decl.fields.at(field_i);
assert(field_node->type == NodeTypeStructField);
const char *field_name = buf_ptr(&field_node->data.struct_field.name);
print_indent(ar);
- fprintf(ar->f, "%s: ", field_name);
- render_node(ar, field_node->data.struct_field.type);
+ fprintf(ar->f, "%s", field_name);
+ if (!is_node_void(field_node->data.struct_field.type)) {
+ fprintf(ar->f, ": ");
+ render_node(ar, field_node->data.struct_field.type);
+ }
fprintf(ar->f, ",\n");
}
src/buffer.hpp
@@ -140,6 +140,13 @@ static inline bool buf_eql_str(Buf *buf, const char *str) {
return buf_eql_mem(buf, str, strlen(str));
}
+static inline bool buf_starts_with_buf(Buf *buf, Buf *sub) {
+ if (buf_len(buf) < buf_len(sub)) {
+ return false;
+ }
+ return buf_eql_mem(sub, buf_ptr(buf), buf_len(sub));
+}
+
bool buf_eql_buf(Buf *buf, Buf *other);
uint32_t buf_hash(Buf *buf);
src/parseh.cpp
@@ -11,6 +11,7 @@
#include "error.hpp"
#include "parser.hpp"
#include "all_types.hpp"
+#include "tokenizer.hpp"
#include <clang/Frontend/ASTUnit.h>
#include <clang/Frontend/CompilerInstance.h>
@@ -24,11 +25,12 @@ struct Context {
ZigList<ErrorMsg *> *errors;
bool warnings_on;
VisibMod visib_mod;
- AstNode *c_void_decl_node;
+ bool have_c_void_decl_node;
AstNode *root;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> type_table;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
SourceManager *source_manager;
+ ZigList<AstNode *> aliases;
};
__attribute__ ((format (printf, 3, 4)))
@@ -57,7 +59,7 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...)
fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg));
}
-static AstNode *make_qual_type_node(Context *c, QualType qt, Decl *decl);
+static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl);
static AstNode *create_node(Context *c, NodeType type) {
AstNode *node = allocate<AstNode>(1);
@@ -66,33 +68,48 @@ static AstNode *create_node(Context *c, NodeType type) {
return node;
}
-static AstNode *simple_type_node(Context *c, const char *type_name) {
+static AstNode *create_symbol_node(Context *c, const char *type_name) {
AstNode *node = create_node(c, NodeTypeSymbol);
buf_init_from_str(&node->data.symbol_expr.symbol, type_name);
return node;
}
-static const char *decl_name(const Decl *decl) {
- const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl);
- return (const char *)named_decl->getName().bytes_begin();
+static AstNode *create_field_access_node(Context *c, const char *lhs, const char *rhs) {
+ AstNode *node = create_node(c, NodeTypeFieldAccessExpr);
+ node->data.field_access_expr.struct_expr = create_symbol_node(c, lhs);
+ buf_init_from_str(&node->data.field_access_expr.field_name, rhs);
+ normalize_parent_ptrs(node);
+ return node;
}
static ZigList<AstNode *> *create_empty_directives(Context *c) {
return allocate<ZigList<AstNode*>>(1);
}
-static AstNode *create_typedef_node(Context *c, Buf *new_name, AstNode *target_node) {
- if (!target_node) {
- return nullptr;
- }
+static AstNode *create_var_decl_node(Context *c, const char *var_name, AstNode *expr_node) {
AstNode *node = create_node(c, NodeTypeVariableDeclaration);
- buf_init_from_buf(&node->data.variable_declaration.symbol, new_name);
+ buf_init_from_str(&node->data.variable_declaration.symbol, var_name);
node->data.variable_declaration.is_const = true;
node->data.variable_declaration.visib_mod = c->visib_mod;
- node->data.variable_declaration.expr = target_node;
+ node->data.variable_declaration.expr = expr_node;
node->data.variable_declaration.directives = create_empty_directives(c);
normalize_parent_ptrs(node);
+ return node;
+}
+
+static const char *decl_name(const Decl *decl) {
+ const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl);
+ return (const char *)named_decl->getName().bytes_begin();
+}
+
+static AstNode *add_typedef_node(Context *c, Buf *new_name, AstNode *target_node) {
+ if (!target_node) {
+ return nullptr;
+ }
+ AstNode *node = create_var_decl_node(c, buf_ptr(new_name), target_node);
+
+ c->type_table.put(new_name, true);
c->root->data.root.top_level_decls.append(node);
return node;
}
@@ -101,12 +118,11 @@ static AstNode *convert_to_c_void(Context *c, AstNode *type_node) {
if (type_node->type == NodeTypeSymbol &&
buf_eql_str(&type_node->data.symbol_expr.symbol, "void"))
{
- if (!c->c_void_decl_node) {
- c->c_void_decl_node = create_typedef_node(c, buf_create_from_str("c_void"),
- simple_type_node(c, "u8"));
- assert(c->c_void_decl_node);
+ if (!c->have_c_void_decl_node) {
+ add_typedef_node(c, buf_create_from_str("c_void"), create_symbol_node(c, "u8"));
+ c->have_c_void_decl_node = true;
}
- return simple_type_node(c, "c_void");
+ return create_symbol_node(c, "c_void");
} else {
return type_node;
}
@@ -123,42 +139,42 @@ static AstNode *pointer_to_type(Context *c, AstNode *type_node, bool is_const) {
return node;
}
-static AstNode *make_type_node(Context *c, const Type *ty, Decl *decl) {
+static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) {
switch (ty->getTypeClass()) {
case Type::Builtin:
{
const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
switch (builtin_ty->getKind()) {
case BuiltinType::Void:
- return simple_type_node(c, "void");
+ return create_symbol_node(c, "void");
case BuiltinType::Bool:
- return simple_type_node(c, "bool");
+ return create_symbol_node(c, "bool");
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::Char_S:
- return simple_type_node(c, "u8");
+ return create_symbol_node(c, "u8");
case BuiltinType::SChar:
- return simple_type_node(c, "i8");
+ return create_symbol_node(c, "i8");
case BuiltinType::UShort:
- return simple_type_node(c, "c_ushort");
+ return create_symbol_node(c, "c_ushort");
case BuiltinType::UInt:
- return simple_type_node(c, "c_uint");
+ return create_symbol_node(c, "c_uint");
case BuiltinType::ULong:
- return simple_type_node(c, "c_ulong");
+ return create_symbol_node(c, "c_ulong");
case BuiltinType::ULongLong:
- return simple_type_node(c, "c_ulonglong");
+ return create_symbol_node(c, "c_ulonglong");
case BuiltinType::Short:
- return simple_type_node(c, "c_short");
+ return create_symbol_node(c, "c_short");
case BuiltinType::Int:
- return simple_type_node(c, "c_int");
+ return create_symbol_node(c, "c_int");
case BuiltinType::Long:
- return simple_type_node(c, "c_long");
+ return create_symbol_node(c, "c_long");
case BuiltinType::LongLong:
- return simple_type_node(c, "c_longlong");
+ return create_symbol_node(c, "c_longlong");
case BuiltinType::Float:
- return simple_type_node(c, "f32");
+ return create_symbol_node(c, "f32");
case BuiltinType::Double:
- return simple_type_node(c, "f64");
+ return create_symbol_node(c, "f64");
case BuiltinType::LongDouble:
case BuiltinType::WChar_U:
case BuiltinType::Char16:
@@ -204,29 +220,29 @@ static AstNode *make_type_node(Context *c, const Type *ty, Decl *decl) {
const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
Buf *type_name = buf_create_from_str(decl_name(typedef_decl));
if (buf_eql_str(type_name, "uint8_t")) {
- return simple_type_node(c, "u8");
+ return create_symbol_node(c, "u8");
} else if (buf_eql_str(type_name, "int8_t")) {
- return simple_type_node(c, "i8");
+ return create_symbol_node(c, "i8");
} else if (buf_eql_str(type_name, "uint16_t")) {
- return simple_type_node(c, "u16");
+ return create_symbol_node(c, "u16");
} else if (buf_eql_str(type_name, "int16_t")) {
- return simple_type_node(c, "i16");
+ return create_symbol_node(c, "i16");
} else if (buf_eql_str(type_name, "uint32_t")) {
- return simple_type_node(c, "u32");
+ return create_symbol_node(c, "u32");
} else if (buf_eql_str(type_name, "int32_t")) {
- return simple_type_node(c, "i32");
+ return create_symbol_node(c, "i32");
} else if (buf_eql_str(type_name, "uint64_t")) {
- return simple_type_node(c, "u64");
+ return create_symbol_node(c, "u64");
} else if (buf_eql_str(type_name, "int64_t")) {
- return simple_type_node(c, "i64");
+ return create_symbol_node(c, "i64");
} else if (buf_eql_str(type_name, "intptr_t")) {
- return simple_type_node(c, "isize");
+ return create_symbol_node(c, "isize");
} else if (buf_eql_str(type_name, "uintptr_t")) {
- return simple_type_node(c, "usize");
+ return create_symbol_node(c, "usize");
} else {
auto entry = c->type_table.maybe_get(type_name);
if (entry) {
- return simple_type_node(c, buf_ptr(type_name));
+ return create_symbol_node(c, buf_ptr(type_name));
} else {
return nullptr;
}
@@ -280,7 +296,7 @@ static AstNode *make_type_node(Context *c, const Type *ty, Decl *decl) {
}
}
-static AstNode *make_qual_type_node(Context *c, QualType qt, Decl *decl) {
+static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl) {
return make_type_node(c, qt.getTypePtr(), decl);
}
@@ -311,7 +327,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
buf_init_from_str(¶m_decl_node->data.param_decl.name, name);
QualType qt = param->getOriginalType();
param_decl_node->data.param_decl.is_noalias = qt.isRestrictQualified();
- param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, (Decl*)fn_decl);
+ param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, fn_decl);
if (!param_decl_node->data.param_decl.type) {
all_ok = false;
break;
@@ -322,9 +338,9 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
}
if (fn_decl->isNoReturn()) {
- node->data.fn_proto.return_type = simple_type_node(c, "unreachable");
+ node->data.fn_proto.return_type = create_symbol_node(c, "unreachable");
} else {
- node->data.fn_proto.return_type = make_qual_type_node(c, fn_decl->getReturnType(), (Decl*)fn_decl);
+ node->data.fn_proto.return_type = make_qual_type_node(c, fn_decl->getReturnType(), fn_decl);
}
if (!node->data.fn_proto.return_type) {
@@ -332,7 +348,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
}
if (!all_ok) {
// not all the types could be resolved, so we give up on the function decl
- emit_warning(c, (Decl*)fn_decl, "skipping function %s\n", buf_ptr(&node->data.fn_proto.name));
+ emit_warning(c, fn_decl, "skipping function %s\n", buf_ptr(&node->data.fn_proto.name));
return;
}
@@ -361,12 +377,92 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl)
return;
}
- AstNode *node = create_typedef_node(c, type_name, make_qual_type_node(c, child_qt, (Decl*)typedef_decl));
+ add_typedef_node(c, type_name, make_qual_type_node(c, child_qt, typedef_decl));
+}
+
+static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
+ Buf bare_name = BUF_INIT;
+ buf_init_from_str(&bare_name, decl_name(enum_decl));
+
+ Buf *type_name = buf_alloc();
+ buf_appendf(type_name, "enum_%s", buf_ptr(&bare_name));
+
+ if (c->type_table.maybe_get(type_name)) {
+ // we've already seen it
+ return;
+ }
+
+ const EnumDecl *enum_def = enum_decl->getDefinition();
+
+ if (!enum_def) {
+ // this is a type that we can point to but that's it, same as `struct Foo;`.
+ add_typedef_node(c, type_name, create_symbol_node(c, "u8"));
+ return;
+ }
+
+ AstNode *node = create_node(c, NodeTypeStructDecl);
+ buf_init_from_buf(&node->data.struct_decl.name, type_name);
+
+ node->data.struct_decl.kind = ContainerKindEnum;
+ node->data.struct_decl.visib_mod = c->visib_mod;
+ node->data.struct_decl.directives = create_empty_directives(c);
+
+ ZigList<AstNode *> var_decls = {0};
+ int i = 0;
+ for (auto it = enum_def->enumerator_begin(),
+ it_end = enum_def->enumerator_end();
+ it != it_end; ++it, i += 1)
+ {
+ const EnumConstantDecl *enum_const = *it;
+ if (enum_const->getInitExpr()) {
+ emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(type_name));
+ return;
+ }
+ AstNode *field_node = create_node(c, NodeTypeStructField);
+ Buf enum_val_name = BUF_INIT;
+ buf_init_from_str(&enum_val_name, decl_name(enum_const));
+
+ 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_node->data.struct_field.name, slice);
+ } else {
+ buf_resize(&field_node->data.struct_field.name, 0);
+ buf_appendf(&field_node->data.struct_field.name, "_%s", buf_ptr(slice));
+ }
+ } else {
+ buf_init_from_buf(&field_node->data.struct_field.name, &enum_val_name);
+ }
+
+ field_node->data.struct_field.directives = create_empty_directives(c);
+ field_node->data.struct_field.visib_mod = VisibModPub;
+ field_node->data.struct_field.type = create_symbol_node(c, "void");
+
+ normalize_parent_ptrs(field_node);
+ node->data.struct_decl.fields.append(field_node);
+
+ // 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(type_name),
+ buf_ptr(&field_node->data.struct_field.name));
+ AstNode *var_node = create_var_decl_node(c, buf_ptr(&enum_val_name), field_access_node);
+ var_decls.append(var_node);
+ }
+
+ c->type_table.put(type_name, true);
- if (node) {
- normalize_parent_ptrs(node);
- c->type_table.put(type_name, true);
+ normalize_parent_ptrs(node);
+ c->root->data.root.top_level_decls.append(node);
+
+ for (int i = 0; i < var_decls.length; i += 1) {
+ AstNode *var_node = var_decls.at(i);
+ c->root->data.root.top_level_decls.append(var_node);
}
+
+ // make an alias without the "enum_" prefix. this will get emitted at the
+ // end if it doesn't conflict with anything else
+ AstNode *alias_node = create_var_decl_node(c, buf_ptr(&bare_name), create_symbol_node(c, buf_ptr(type_name)));
+ c->aliases.append(alias_node);
+
}
static bool decl_visitor(void *context, const Decl *decl) {
@@ -379,6 +475,9 @@ static bool decl_visitor(void *context, const Decl *decl) {
case Decl::Typedef:
visit_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl));
break;
+ case Decl::Enum:
+ visit_enum_decl(c, static_cast<const EnumDecl *>(decl));
+ break;
default:
emit_warning(c, decl, "ignoring %s decl\n", decl->getDeclKindName());
}
@@ -386,6 +485,21 @@ static bool decl_visitor(void *context, const Decl *decl) {
return true;
}
+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->type_table.maybe_get(name)) {
+ continue;
+ }
+ if (c->fn_table.maybe_get(name)) {
+ continue;
+ }
+ c->root->data.root.top_level_decls.append(alias_node);
+ }
+}
+
int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source,
const char **args, int args_len, const char *libc_include_path, bool warnings_on)
{
@@ -514,8 +628,10 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors,
c->root = create_node(c, NodeTypeRoot);
ast_unit->visitLocalTopLevelDecls(c, decl_visitor);
- normalize_parent_ptrs(c->root);
+ render_aliases(c);
+
+ normalize_parent_ptrs(c->root);
import->root = c->root;
return 0;
src/tokenizer.cpp
@@ -93,6 +93,10 @@
case DIGIT: \
case '_'
+#define SYMBOL_START \
+ ALPHA: \
+ case '_'
+
enum TokenizeState {
TokenizeStateStart,
TokenizeStateSymbol,
@@ -1170,3 +1174,10 @@ bool is_printable(uint8_t c) {
}
}
+bool valid_symbol_starter(uint8_t c) {
+ switch (c) {
+ case SYMBOL_START:
+ return true;
+ }
+ return false;
+}
src/tokenizer.hpp
@@ -131,4 +131,6 @@ int get_digit_value(uint8_t c);
const char * token_name(TokenId id);
+bool valid_symbol_starter(uint8_t c);
+
#endif