Commit 3c2093fec6
Changed files (14)
doc/langref.md
@@ -5,15 +5,17 @@
```
Root = many(TopLevelDecl) "EOF"
-TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl)
+TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl)
CImportDecl = "c_import" Block
+TypeDecl = "type" "Symbol" "=" TypeExpr ";"
+
ErrorValueDecl = "error" "Symbol" ";"
GlobalVarDecl = VariableDeclaration ";"
-VariableDeclaration = ("var" | "const") "Symbol" option(":" PrefixOpExpression) "=" Expression
+VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expression
ContainerDecl = ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
@@ -27,7 +29,7 @@ RootExportDecl = "export" "Symbol" "String" ";"
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
-FnProto = "fn" option("Symbol") ParamDeclList option("->" PrefixOpExpression)
+FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
Directive = "#" "Symbol" "(" "String" ")"
@@ -37,7 +39,7 @@ FnDef = FnProto Block
ParamDeclList = "(" list(ParamDecl, ",") ")"
-ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..."
+ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..."
Block = "{" list(option(Statement), ";") "}"
@@ -47,6 +49,8 @@ Label = "Symbol" ":"
Expression = BlockExpression | NonBlockExpression
+TypeExpr = PrefixOpExpression
+
NonBlockExpression = ReturnExpression | AssignmentExpression
AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")"
@@ -55,7 +59,7 @@ AsmOutput = ":" list(AsmOutputItem, ",") option(AsmInput)
AsmInput = ":" list(AsmInputItem, ",") option(AsmClobbers)
-AsmOutputItem = "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")"
+AsmOutputItem = "[" "Symbol" "]" "String" "(" ("Symbol" | "->" TypeExpr) ")"
AsmInputItem = "[" "Symbol" "]" "String" "(" Expression ")"
@@ -91,7 +95,7 @@ IfExpression = IfVarExpression | IfBoolExpression
IfBoolExpression = "if" "(" Expression ")" Expression option(Else)
-IfVarExpression = "if" "(" ("const" | "var") "Symbol" option(":" PrefixOpExpression) "?=" Expression ")" Expression Option(Else)
+IfVarExpression = "if" "(" ("const" | "var") "Symbol" option(":" TypeExpr) "?=" Expression ")" Expression Option(Else)
Else = "else" Expression
@@ -117,7 +121,7 @@ AdditionOperator = "+" | "-" | "++"
MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression
-CurlySuffixExpression = PrefixOpExpression option(ContainerInitExpression)
+CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
MultiplyOperator = "*" | "/" | "%"
@@ -143,13 +147,13 @@ PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%"
PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol")
-ArrayType = "[" option(Expression) "]" option("const") PrefixOpExpression
+ArrayType = "[" option(Expression) "]" option("const") TypeExpr
GotoExpression = "goto" "Symbol"
GroupedExpression = "(" Expression ")"
-KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"
+KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
```
## Operator Precedence
src/all_types.hpp
@@ -124,6 +124,7 @@ enum NodeType {
NodeTypeDirective,
NodeTypeReturnExpr,
NodeTypeVariableDeclaration,
+ NodeTypeTypeDecl,
NodeTypeErrorValueDecl,
NodeTypeBinOpExpr,
NodeTypeUnwrapErrorExpr,
@@ -159,6 +160,7 @@ enum NodeType {
NodeTypeStructValueField,
NodeTypeArrayType,
NodeTypeErrorType,
+ NodeTypeTypeLiteral,
};
struct AstNodeRoot {
@@ -212,9 +214,6 @@ struct AstNodeParamDecl {
// populated by semantic analyzer
VariableTableEntry *variable;
- bool is_byval;
- int src_index;
- int gen_index;
};
struct AstNodeBlock {
@@ -256,6 +255,19 @@ struct AstNodeVariableDeclaration {
VariableTableEntry *variable;
};
+struct AstNodeTypeDecl {
+ VisibMod visib_mod;
+ ZigList<AstNode *> *directives;
+ Buf symbol;
+ AstNode *child_type;
+
+ // populated by semantic analyzer
+ TopLevelDecl top_level_decl;
+ // if this is set, don't process the node; we've already done so
+ // and here is the type (with id TypeTableEntryIdTypeDecl)
+ TypeTableEntry *override_type;
+};
+
struct AstNodeErrorValueDecl {
Buf name;
VisibMod visib_mod;
@@ -684,6 +696,11 @@ struct AstNodeErrorType {
Expr resolved_expr;
};
+struct AstNodeTypeLiteral {
+ // populated by semantic analyzer
+ Expr resolved_expr;
+};
+
struct AstNode {
enum NodeType type;
int line;
@@ -704,6 +721,7 @@ struct AstNode {
AstNodeBlock block;
AstNodeReturnExpr return_expr;
AstNodeVariableDeclaration variable_declaration;
+ AstNodeTypeDecl type_decl;
AstNodeErrorValueDecl error_value_decl;
AstNodeBinOpExpr bin_op_expr;
AstNodeUnwrapErrorExpr unwrap_err_expr;
@@ -740,6 +758,7 @@ struct AstNode {
AstNodeContinueExpr continue_expr;
AstNodeArrayType array_type;
AstNodeErrorType error_type;
+ AstNodeTypeLiteral type_literal;
} data;
};
@@ -755,6 +774,24 @@ struct AsmToken {
int end;
};
+struct FnTypeParamInfo {
+ bool is_noalias;
+ TypeTableEntry *type;
+};
+
+struct FnTypeId {
+ TypeTableEntry *return_type;
+ FnTypeParamInfo *param_info;
+ int param_count;
+ bool is_var_args;
+ bool is_naked;
+ bool is_extern;
+};
+
+uint32_t fn_type_id_hash(FnTypeId);
+bool fn_type_id_eql(FnTypeId a, FnTypeId b);
+
+
struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
@@ -820,17 +857,25 @@ struct TypeTableEntryEnum {
bool complete;
};
+struct FnGenParamInfo {
+ int src_index;
+ int gen_index;
+ bool is_byval;
+};
+
struct TypeTableEntryFn {
- TypeTableEntry *src_return_type;
+ FnTypeId fn_type_id;
TypeTableEntry *gen_return_type;
- TypeTableEntry **param_types;
- int src_param_count;
- LLVMTypeRef raw_type_ref;
- bool is_var_args;
int gen_param_count;
+ FnGenParamInfo *gen_param_info;
+
+ LLVMTypeRef raw_type_ref;
LLVMCallConv calling_convention;
- bool is_extern;
- bool is_naked;
+};
+
+struct TypeTableEntryTypeDecl {
+ TypeTableEntry *child_type;
+ TypeTableEntry *canonical_type;
};
enum TypeTableEntryId {
@@ -852,6 +897,7 @@ enum TypeTableEntryId {
TypeTableEntryIdPureError,
TypeTableEntryIdEnum,
TypeTableEntryIdFn,
+ TypeTableEntryIdTypeDecl,
};
struct TypeTableEntry {
@@ -873,6 +919,7 @@ struct TypeTableEntry {
TypeTableEntryError error;
TypeTableEntryEnum enumeration;
TypeTableEntryFn fn;
+ TypeTableEntryTypeDecl type_decl;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
@@ -900,7 +947,6 @@ struct ImportTableEntry {
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
- HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> fn_type_table;
};
struct LabelTableEntry {
@@ -969,12 +1015,14 @@ struct CodeGen {
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
+ HashMap<FnTypeId, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
uint32_t next_unresolved_index;
struct {
TypeTableEntry *entry_bool;
TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
+ TypeTableEntry *entry_c_int[8];
TypeTableEntry *entry_u8;
TypeTableEntry *entry_u16;
TypeTableEntry *entry_u32;
@@ -1082,12 +1130,16 @@ struct BlockContext {
Buf *c_import_buf;
};
-struct ParseH {
- ZigList<ErrorMsg*> errors;
- ZigList<AstNode *> fn_list;
- ZigList<AstNode *> struct_list;
- ZigList<AstNode *> var_list;
- ZigList<AstNode *> incomplete_struct_list;
+enum CIntType {
+ CIntTypeShort,
+ CIntTypeUShort,
+ CIntTypeInt,
+ CIntTypeUInt,
+ CIntTypeLong,
+ CIntTypeULong,
+ CIntTypeLongLong,
+ CIntTypeULongLong,
};
+
#endif
src/analyze.cpp
@@ -56,6 +56,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeDirective:
case NodeTypeReturnExpr:
case NodeTypeVariableDeclaration:
+ case NodeTypeTypeDecl:
case NodeTypeErrorValueDecl:
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
@@ -83,6 +84,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeSwitchProng:
case NodeTypeArrayType:
case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
case NodeTypeContainerInitExpr:
return node;
}
@@ -123,6 +125,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdTypeDecl:
// nothing to init
break;
case TypeTableEntryIdStruct:
@@ -149,7 +152,7 @@ static int bits_needed_for_unsigned(uint64_t x) {
}
}
-static TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
+TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
return get_int_type(g, false, bits_needed_for_unsigned(x));
}
@@ -165,12 +168,15 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
+ TypeTableEntry *canon_child_type = get_underlying_type(child_type);
+ assert(canon_child_type->id != TypeTableEntryIdInvalid);
+
bool zero_bits;
- if (child_type->size_in_bits == 0) {
- if (child_type->id == TypeTableEntryIdStruct) {
- zero_bits = child_type->data.structure.complete;
- } else if (child_type->id == TypeTableEntryIdEnum) {
- zero_bits = child_type->data.enumeration.complete;
+ if (canon_child_type->size_in_bits == 0) {
+ if (canon_child_type->id == TypeTableEntryIdStruct) {
+ zero_bits = canon_child_type->data.structure.complete;
+ } else if (canon_child_type->id == TypeTableEntryIdEnum) {
+ zero_bits = canon_child_type->data.enumeration.complete;
} else {
zero_bits = true;
}
@@ -196,7 +202,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
}
}
-static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
+TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
if (child_type->maybe_parent) {
TypeTableEntry *entry = child_type->maybe_parent;
return entry;
@@ -317,8 +323,7 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
}
}
-static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size)
-{
+TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size) {
auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
if (existing_entry) {
TypeTableEntry *entry = existing_entry->value;
@@ -417,147 +422,109 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c
}
}
-// If the node does not have a constant expression value with a metatype, generates an error
-// and returns invalid type. Otherwise, returns the type of the constant expression value.
-// Must be called after analyze_expression on the same node.
-static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
- if (node->type == NodeTypeSymbol && node->data.symbol_expr.override_type_entry) {
- return node->data.symbol_expr.override_type_entry;
- }
- Expr *expr = get_resolved_expr(node);
- assert(expr->type_entry);
- if (expr->type_entry->id == TypeTableEntryIdInvalid) {
- return g->builtin_types.entry_invalid;
- } else if (expr->type_entry->id == TypeTableEntryIdMetaType) {
- // OK
- } else {
- add_node_error(g, node, buf_sprintf("expected type, found expression"));
- return g->builtin_types.entry_invalid;
- }
+TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type) {
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdTypeDecl);
- ConstExprValue *const_val = &expr->const_val;
- if (!const_val->ok) {
- add_node_error(g, node, buf_sprintf("unable to resolve constant expression"));
- return g->builtin_types.entry_invalid;
- }
+ buf_init_from_str(&entry->name, name);
- return const_val->data.x_type;
-}
+ entry->type_ref = child_type->type_ref;
+ entry->type_ref = child_type->type_ref;
+ entry->di_type = child_type->di_type;
+ entry->size_in_bits = child_type->size_in_bits;
+ entry->align_in_bits = child_type->align_in_bits;
-// Calls analyze_expression on node, and then resolve_type.
-static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- AstNode *node)
-{
- AstNode **node_ptr = node->parent_field;
- analyze_expression(g, import, context, nullptr, *node_ptr);
- return resolve_type(g, *node_ptr);
-}
+ entry->data.type_decl.child_type = child_type;
-static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node, bool is_naked)
-{
- assert(node->type == NodeTypeFnProto);
- AstNodeFnProto *fn_proto = &node->data.fn_proto;
+ if (child_type->id == TypeTableEntryIdTypeDecl) {
+ entry->data.type_decl.canonical_type = child_type->data.type_decl.canonical_type;
+ } else {
+ entry->data.type_decl.canonical_type = child_type;
+ }
- if (fn_proto->skip) {
- return g->builtin_types.entry_invalid;
+ return entry;
+}
+
+// accepts ownership of fn_type_id memory
+TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id) {
+ auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
+ if (table_entry) {
+ return table_entry->value;
}
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
- fn_type->data.fn.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
- fn_type->data.fn.is_naked = is_naked;
- fn_type->data.fn.calling_convention = fn_proto->is_extern ? LLVMCCallConv : LLVMFastCallConv;
+ fn_type->data.fn.fn_type_id = fn_type_id;
+ fn_type->data.fn.calling_convention = fn_type_id.is_extern ? LLVMCCallConv : LLVMFastCallConv;
- int src_param_count = node->data.fn_proto.params.length;
fn_type->size_in_bits = g->pointer_size_bytes * 8;
fn_type->align_in_bits = g->pointer_size_bytes * 8;
- fn_type->data.fn.src_param_count = src_param_count;
- fn_type->data.fn.param_types = allocate<TypeTableEntry*>(src_param_count);
- // first, analyze the parameters and return type in order they appear in
- // source code in order for error messages to be in the best order.
+ // populate the name of the type
buf_resize(&fn_type->name, 0);
- const char *extern_str = fn_type->data.fn.is_extern ? "extern " : "";
- const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";
+ const char *extern_str = fn_type_id.is_extern ? "extern " : "";
+ const char *naked_str = fn_type_id.is_naked ? "naked " : "";
buf_appendf(&fn_type->name, "%s%sfn(", extern_str, naked_str);
- for (int i = 0; i < src_param_count; i += 1) {
- AstNode *child = node->data.fn_proto.params.at(i);
- assert(child->type == NodeTypeParamDecl);
- TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
- child->data.param_decl.type);
- fn_type->data.fn.param_types[i] = type_entry;
+ for (int i = 0; i < fn_type_id.param_count; i += 1) {
+ FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
+ TypeTableEntry *param_type = param_info->type;
const char *comma = (i == 0) ? "" : ", ";
- buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->name));
+ const char *noalias_str = param_info->is_noalias ? "noalias " : "";
+ buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(¶m_type->name));
}
- TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
- node->data.fn_proto.return_type);
- fn_type->data.fn.src_return_type = return_type;
- if (return_type->id == TypeTableEntryIdInvalid) {
- fn_proto->skip = true;
- }
- fn_type->data.fn.is_var_args = fn_proto->is_var_args;
- if (fn_proto->is_var_args) {
- const char *comma = (src_param_count == 0) ? "" : ", ";
+ if (fn_type_id.is_var_args) {
+ const char *comma = (fn_type_id.param_count == 0) ? "" : ", ";
buf_appendf(&fn_type->name, "%s...", comma);
}
buf_appendf(&fn_type->name, ")");
- if (return_type->id != TypeTableEntryIdVoid) {
- buf_appendf(&fn_type->name, " -> %s", buf_ptr(&return_type->name));
+ if (fn_type_id.return_type->id != TypeTableEntryIdVoid) {
+ buf_appendf(&fn_type->name, " -> %s", buf_ptr(&fn_type_id.return_type->name));
}
// next, loop over the parameters again and compute debug information
// and codegen information
- bool first_arg_return = !fn_proto->skip && handle_is_ptr(return_type);
+ bool first_arg_return = handle_is_ptr(fn_type_id.return_type);
// +1 for maybe making the first argument the return value
- LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + src_param_count);
+ LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + fn_type_id.param_count);
// +1 because 0 is the return type and +1 for maybe making first arg ret val
- LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + src_param_count);
- param_di_types[0] = return_type->di_type;
+ LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + fn_type_id.param_count);
+ param_di_types[0] = fn_type_id.return_type->di_type;
int gen_param_index = 0;
TypeTableEntry *gen_return_type;
if (first_arg_return) {
- TypeTableEntry *gen_type = get_pointer_to_type(g, return_type, false);
+ TypeTableEntry *gen_type = get_pointer_to_type(g, fn_type_id.return_type, false);
gen_param_types[gen_param_index] = gen_type->type_ref;
gen_param_index += 1;
// after the gen_param_index += 1 because 0 is the return type
param_di_types[gen_param_index] = gen_type->di_type;
gen_return_type = g->builtin_types.entry_void;
- } else if (return_type->size_in_bits == 0) {
+ } else if (fn_type_id.return_type->size_in_bits == 0) {
gen_return_type = g->builtin_types.entry_void;
} else {
- gen_return_type = return_type;
+ gen_return_type = fn_type_id.return_type;
}
fn_type->data.fn.gen_return_type = gen_return_type;
- for (int i = 0; i < src_param_count; i += 1) {
- AstNode *child = node->data.fn_proto.params.at(i);
- assert(child->type == NodeTypeParamDecl);
- TypeTableEntry *type_entry = fn_type->data.fn.param_types[i];
-
- if (type_entry->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, child->data.param_decl.type,
- buf_sprintf("parameter of type 'unreachable' not allowed"));
- fn_proto->skip = true;
- } else if (type_entry->id == TypeTableEntryIdInvalid) {
- fn_proto->skip = true;
- }
- child->data.param_decl.src_index = i;
- child->data.param_decl.gen_index = -1;
+ fn_type->data.fn.gen_param_info = allocate<FnGenParamInfo>(fn_type_id.param_count);
+ for (int i = 0; i < fn_type_id.param_count; i += 1) {
+ FnTypeParamInfo *src_param_info = &fn_type->data.fn.fn_type_id.param_info[i];
+ TypeTableEntry *type_entry = src_param_info->type;
+ FnGenParamInfo *gen_param_info = &fn_type->data.fn.gen_param_info[i];
- if (!fn_proto->skip && type_entry->size_in_bits > 0) {
+ gen_param_info->src_index = i;
+ gen_param_info->gen_index = -1;
+ if (type_entry->size_in_bits > 0) {
TypeTableEntry *gen_type;
if (handle_is_ptr(type_entry)) {
gen_type = get_pointer_to_type(g, type_entry, true);
- child->data.param_decl.is_byval = true;
+ gen_param_info->is_byval = true;
} else {
gen_type = type_entry;
}
gen_param_types[gen_param_index] = gen_type->type_ref;
- child->data.param_decl.gen_index = gen_param_index;
+ gen_param_info->gen_index = gen_param_index;
gen_param_index += 1;
@@ -568,24 +535,168 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
fn_type->data.fn.gen_param_count = gen_param_index;
+ fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
+ gen_param_types, gen_param_index, fn_type_id.is_var_args);
+ fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
+ LLVMZigDIFile *di_file = nullptr; // TODO if we get a crash maybe this is the culprit
+ fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, di_file,
+ param_di_types, gen_param_index + 1, 0);
+
+ g->fn_type_table.put(fn_type_id, fn_type);
+
+ return fn_type;
+}
+
+static TypeTableEntryId container_to_type(ContainerKind kind) {
+ switch (kind) {
+ case ContainerKindStruct:
+ return TypeTableEntryIdStruct;
+ case ContainerKindEnum:
+ return TypeTableEntryIdEnum;
+ }
+ zig_unreachable();
+}
+
+TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
+ ContainerKind kind, AstNode *decl_node, const char *name)
+{
+ TypeTableEntryId type_id = container_to_type(kind);
+ TypeTableEntry *entry = new_type_table_entry(type_id);
+
+ switch (kind) {
+ case ContainerKindStruct:
+ entry->data.structure.decl_node = decl_node;
+ break;
+ case ContainerKindEnum:
+ entry->data.enumeration.decl_node = decl_node;
+ break;
+ }
+
+ unsigned line = decl_node ? decl_node->line : 0;
+
+ entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
+ entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
+ LLVMZigTag_DW_structure_type(), name,
+ LLVMZigFileToScope(import->di_file), import->di_file, line + 1);
+
+ buf_init_from_str(&entry->name, name);
+
+ return entry;
+}
+
+
+TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry) {
+ if (type_entry->id == TypeTableEntryIdTypeDecl) {
+ return type_entry->data.type_decl.canonical_type;
+ } else {
+ return type_entry;
+ }
+}
+
+// If the node does not have a constant expression value with a metatype, generates an error
+// and returns invalid type. Otherwise, returns the type of the constant expression value.
+// Must be called after analyze_expression on the same node.
+static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
+ if (node->type == NodeTypeSymbol && node->data.symbol_expr.override_type_entry) {
+ return node->data.symbol_expr.override_type_entry;
+ }
+ Expr *expr = get_resolved_expr(node);
+ assert(expr->type_entry);
+ if (expr->type_entry->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ } else if (expr->type_entry->id == TypeTableEntryIdMetaType) {
+ // OK
+ } else {
+ add_node_error(g, node, buf_sprintf("expected type, found expression"));
+ return g->builtin_types.entry_invalid;
+ }
+
+ ConstExprValue *const_val = &expr->const_val;
+ if (!const_val->ok) {
+ add_node_error(g, node, buf_sprintf("unable to resolve constant expression"));
+ return g->builtin_types.entry_invalid;
+ }
+
+ return const_val->data.x_type;
+}
+
+// Calls analyze_expression on node, and then resolve_type.
+static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ AstNode *node)
+{
+ AstNode **node_ptr = node->parent_field;
+ analyze_expression(g, import, context, nullptr, *node_ptr);
+ return resolve_type(g, *node_ptr);
+}
+
+static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ TypeTableEntry *expected_type, AstNode *node, bool is_naked)
+{
+ assert(node->type == NodeTypeFnProto);
+ AstNodeFnProto *fn_proto = &node->data.fn_proto;
+
if (fn_proto->skip) {
return g->builtin_types.entry_invalid;
}
- auto table_entry = import->fn_type_table.maybe_get(&fn_type->name);
- if (table_entry) {
- return table_entry->value;
- } else {
- fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
- gen_param_types, gen_param_index, fn_type->data.fn.is_var_args);
- fn_type->type_ref = LLVMPointerType(fn_type->data.fn.raw_type_ref, 0);
- fn_type->di_type = LLVMZigCreateSubroutineType(g->dbuilder, import->di_file,
- param_di_types, gen_param_index + 1, 0);
+ FnTypeId fn_type_id;
+ fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
+ fn_type_id.is_naked = is_naked;
+ fn_type_id.param_count = node->data.fn_proto.params.length;
+ fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);
+ fn_type_id.is_var_args = fn_proto->is_var_args;
+ fn_type_id.return_type = analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type);
+
+ if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) {
+ fn_proto->skip = true;
+ }
- import->fn_type_table.put(&fn_type->name, fn_type);
+ for (int i = 0; i < fn_type_id.param_count; i += 1) {
+ AstNode *child = node->data.fn_proto.params.at(i);
+ assert(child->type == NodeTypeParamDecl);
+ TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
+ child->data.param_decl.type);
+ switch (type_entry->id) {
+ case TypeTableEntryIdInvalid:
+ fn_proto->skip = true;
+ break;
+ case TypeTableEntryIdNumLitFloat:
+ case TypeTableEntryIdNumLitInt:
+ case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdMetaType:
+ case TypeTableEntryIdUnreachable:
+ fn_proto->skip = true;
+ add_node_error(g, child->data.param_decl.type,
+ buf_sprintf("parameter of type '%s' not allowed'", buf_ptr(&type_entry->name)));
+ break;
+ case TypeTableEntryIdVoid:
+ case TypeTableEntryIdBool:
+ case TypeTableEntryIdInt:
+ case TypeTableEntryIdFloat:
+ case TypeTableEntryIdPointer:
+ case TypeTableEntryIdArray:
+ case TypeTableEntryIdStruct:
+ case TypeTableEntryIdMaybe:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
+ case TypeTableEntryIdEnum:
+ case TypeTableEntryIdFn:
+ case TypeTableEntryIdTypeDecl:
+ break;
+ }
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ fn_proto->skip = true;
+ }
+ FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
+ param_info->type = type_entry;
+ param_info->is_noalias = child->data.param_decl.is_noalias;
+ }
- return fn_type;
+ if (fn_proto->skip) {
+ return g->builtin_types.entry_invalid;
}
+
+ return get_fn_type(g, fn_type_id);
}
@@ -640,14 +751,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
if (fn_table_entry->is_inline) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute);
}
- if (fn_type->data.fn.is_naked) {
+ if (fn_type->data.fn.fn_type_id.is_naked) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute);
}
LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage);
- if (fn_type->data.fn.src_return_type->id == TypeTableEntryIdUnreachable) {
+ if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdUnreachable) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
}
LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
@@ -691,6 +802,7 @@ static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_
}
static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *enum_type) {
+ // if you change this logic you likely must also change similar logic in parseh.cpp
assert(enum_type->id == TypeTableEntryIdEnum);
AstNode *decl_node = enum_type->data.enumeration.decl_node;
@@ -853,6 +965,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
}
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type) {
+ // if you change the logic of this function likely you must make a similar change in
+ // parseh.cpp
assert(struct_type->id == TypeTableEntryIdStruct);
AstNode *decl_node = struct_type->data.structure.decl_node;
@@ -1104,15 +1218,12 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *parent_import, A
ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
child_import->fn_table.init(32);
- child_import->fn_type_table.init(32);
child_import->c_import_node = node;
ZigList<ErrorMsg *> errors = {0};
int err;
- if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g->clang_argv, g->clang_argv_len,
- buf_ptr(g->libc_include_path), false, &g->next_node_index)))
- {
+ if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) {
zig_panic("unable to parse h file: %s\n", err_str(err));
}
@@ -1175,6 +1286,27 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
nullptr, node);
g->global_vars.append(var);
+ break;
+ }
+ case NodeTypeTypeDecl:
+ {
+ AstNode *type_node = node->data.type_decl.child_type;
+ Buf *decl_name = &node->data.type_decl.symbol;
+
+ TypeTableEntry *typedecl_type;
+ if (node->data.type_decl.override_type) {
+ typedecl_type = node->data.type_decl.override_type;
+ } else {
+ TypeTableEntry *child_type = analyze_type_expr(g, import, import->block_context, type_node);
+ if (child_type->id == TypeTableEntryIdInvalid) {
+ typedecl_type = child_type;
+ } else {
+ typedecl_type = get_typedecl_type(g, buf_ptr(decl_name), child_type);
+ }
+ }
+
+ import->block_context->type_table.put(decl_name, typedecl_type);
+
break;
}
case NodeTypeErrorValueDecl:
@@ -1224,6 +1356,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeContainerInitExpr:
case NodeTypeArrayType:
case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
zig_unreachable();
}
@@ -1278,8 +1411,10 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
case TypeTableEntryIdEnum:
case TypeTableEntryIdFn:
return true;
+
+ case TypeTableEntryIdTypeDecl:
+ zig_unreachable();
}
- zig_unreachable();
}
static void add_global_const_expr(CodeGen *g, Expr *expr) {
@@ -1376,25 +1511,30 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable
if (expected_type->id == TypeTableEntryIdFn &&
actual_type->id == TypeTableEntryIdFn)
{
- if (expected_type->data.fn.is_extern != actual_type->data.fn.is_extern) {
+ if (expected_type->data.fn.fn_type_id.is_extern != actual_type->data.fn.fn_type_id.is_extern) {
return false;
}
- if (expected_type->data.fn.is_naked != actual_type->data.fn.is_naked) {
+ if (expected_type->data.fn.fn_type_id.is_naked != actual_type->data.fn.fn_type_id.is_naked) {
return false;
}
- if (!types_match_const_cast_only(expected_type->data.fn.src_return_type,
- actual_type->data.fn.src_return_type))
+ if (!types_match_const_cast_only(expected_type->data.fn.fn_type_id.return_type,
+ actual_type->data.fn.fn_type_id.return_type))
{
return false;
}
- if (expected_type->data.fn.src_param_count != actual_type->data.fn.src_param_count) {
+ if (expected_type->data.fn.fn_type_id.param_count != actual_type->data.fn.fn_type_id.param_count) {
return false;
}
- for (int i = 0; i < expected_type->data.fn.src_param_count; i += 1) {
+ for (int i = 0; i < expected_type->data.fn.fn_type_id.param_count; i += 1) {
// note it's reversed for parameters
- if (types_match_const_cast_only(actual_type->data.fn.param_types[i],
- expected_type->data.fn.param_types[i]))
- {
+ FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
+ FnTypeParamInfo *expected_param_info = &expected_type->data.fn.fn_type_id.param_info[i];
+
+ if (!types_match_const_cast_only(actual_param_info->type, expected_param_info->type)) {
+ return false;
+ }
+
+ if (expected_param_info->is_noalias != actual_param_info->is_noalias) {
return false;
}
}
@@ -3610,6 +3750,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdFn:
+ case TypeTableEntryIdTypeDecl:
return resolve_expr_const_val_as_type(g, node, type_entry);
}
}
@@ -3664,14 +3805,14 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
assert(node->type == NodeTypeFnCallExpr);
// count parameters
- int src_param_count = fn_type->data.fn.src_param_count;
+ int src_param_count = fn_type->data.fn.fn_type_id.param_count;
int actual_param_count = node->data.fn_call_expr.params.length;
if (struct_type) {
actual_param_count += 1;
}
- if (fn_type->data.fn.is_var_args) {
+ if (fn_type->data.fn.fn_type_id.is_var_args) {
if (actual_param_count < src_param_count) {
add_node_error(g, node,
buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count));
@@ -3689,12 +3830,12 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
TypeTableEntry *expected_param_type = nullptr;
int fn_proto_i = i + (struct_type ? 1 : 0);
if (fn_proto_i < src_param_count) {
- expected_param_type = fn_type->data.fn.param_types[fn_proto_i];
+ expected_param_type = fn_type->data.fn.fn_type_id.param_info[fn_proto_i].type;
}
analyze_expression(g, import, context, expected_param_type, child);
}
- TypeTableEntry *return_type = fn_type->data.fn.src_return_type;
+ TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
if (return_type->id == TypeTableEntryIdInvalid) {
return return_type;
@@ -4304,6 +4445,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeErrorType:
return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);
break;
+ case NodeTypeTypeLiteral:
+ return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_type);
+ break;
case NodeTypeSwitchExpr:
return_type = analyze_switch_expr(g, import, context, expected_type, node);
break;
@@ -4322,6 +4466,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeStructField:
case NodeTypeStructValueField:
case NodeTypeErrorValueDecl:
+ case NodeTypeTypeDecl:
zig_unreachable();
}
assert(return_type);
@@ -4354,8 +4499,9 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
BlockContext *context = node->data.fn_def.block_context;
+ FnTableEntry *fn_table_entry = fn_proto_node->data.fn_proto.fn_table_entry;
+ TypeTableEntry *fn_type = fn_table_entry->type_entry;
AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
- bool is_exported = (fn_proto->visib_mod == VisibModExport);
for (int i = 0; i < fn_proto->params.length; i += 1) {
AstNode *param_decl_node = fn_proto->params.at(i);
assert(param_decl_node->type == NodeTypeParamDecl);
@@ -4369,9 +4515,9 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
buf_sprintf("noalias on non-pointer parameter"));
}
- if (is_exported && type->id == TypeTableEntryIdStruct) {
+ if (fn_type->data.fn.fn_type_id.is_extern && type->id == TypeTableEntryIdStruct) {
add_node_error(g, param_decl_node,
- buf_sprintf("byvalue struct parameters not yet supported on exported functions"));
+ buf_sprintf("byvalue struct parameters not yet supported on extern functions"));
}
if (buf_len(¶m_decl->name) == 0) {
@@ -4382,16 +4528,15 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
var->src_arg_index = i;
param_decl_node->data.param_decl.variable = var;
- var->gen_arg_index = param_decl_node->data.param_decl.gen_index;
+ var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
}
- TypeTableEntry *expected_type = unwrapped_node_type(fn_proto->return_type);
+ TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;
TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body);
node->data.fn_def.implicit_return_type = block_return_type;
{
- FnTableEntry *fn_table_entry = fn_proto_node->data.fn_proto.fn_table_entry;
auto it = fn_table_entry->label_table.entry_iterator();
for (;;) {
auto *entry = it.next();
@@ -4427,6 +4572,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeVariableDeclaration:
case NodeTypeErrorValueDecl:
case NodeTypeFnProto:
+ case NodeTypeTypeDecl:
// already took care of these
break;
case NodeTypeDirective:
@@ -4466,6 +4612,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeContainerInitExpr:
case NodeTypeArrayType:
case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
zig_unreachable();
}
}
@@ -4485,10 +4632,14 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeContinue:
case NodeTypeErrorValueDecl:
case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
// no dependencies on other top level declarations
break;
case NodeTypeSymbol:
{
+ if (node->data.symbol_expr.override_type_entry) {
+ break;
+ }
Buf *name = &node->data.symbol_expr.symbol;
auto table_entry = g->primitive_type_table.maybe_get(name);
if (!table_entry) {
@@ -4627,6 +4778,9 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeParamDecl:
collect_expr_decl_deps(g, import, node->data.param_decl.type, decl_node);
break;
+ case NodeTypeTypeDecl:
+ collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);
+ break;
case NodeTypeVariableDeclaration:
case NodeTypeRootExportDecl:
case NodeTypeFnDef:
@@ -4642,16 +4796,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
}
}
-static TypeTableEntryId container_to_type(ContainerKind kind) {
- switch (kind) {
- case ContainerKindStruct:
- return TypeTableEntryIdStruct;
- case ContainerKindEnum:
- return TypeTableEntryIdEnum;
- }
- zig_unreachable();
-}
-
static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeRoot:
@@ -4669,28 +4813,16 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
}
if (table_entry) {
node->data.struct_decl.type_entry = table_entry->value;
- add_node_error(g, node,
- buf_sprintf("redefinition of '%s'", buf_ptr(name)));
+ add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
} else {
- TypeTableEntryId type_id = container_to_type(node->data.struct_decl.kind);
- TypeTableEntry *entry = new_type_table_entry(type_id);
- switch (node->data.struct_decl.kind) {
- case ContainerKindStruct:
- entry->data.structure.decl_node = node;
- break;
- case ContainerKindEnum:
- entry->data.enumeration.decl_node = node;
- break;
+ TypeTableEntry *entry;
+ if (node->data.struct_decl.type_entry) {
+ entry = node->data.struct_decl.type_entry;
+ } else {
+ entry = get_partial_container_type(g, import,
+ node->data.struct_decl.kind, node, buf_ptr(name));
}
- entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(name));
- entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
- LLVMZigTag_DW_structure_type(), buf_ptr(name),
- LLVMZigFileToScope(import->di_file), import->di_file, node->line + 1);
-
- buf_init_from_buf(&entry->name, name);
- // put off adding the debug type until we do the full struct body
- // this type is incomplete until we do another pass
import->block_context->type_table.put(&entry->name, entry);
node->data.struct_decl.type_entry = entry;
@@ -4761,6 +4893,23 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
}
break;
}
+ case NodeTypeTypeDecl:
+ {
+ // determine which other top level declarations this variable declaration depends on.
+ TopLevelDecl *decl_node = &node->data.type_decl.top_level_decl;
+ decl_node->deps.init(1);
+ collect_expr_decl_deps(g, import, node, decl_node);
+
+ Buf *name = &node->data.type_decl.symbol;
+ decl_node->name = name;
+ decl_node->import = import;
+ if (decl_node->deps.size() > 0) {
+ g->unresolved_top_level_decls.put(name, node);
+ } else {
+ resolve_top_level_decl(g, import, node);
+ }
+ break;
+ }
case NodeTypeFnProto:
{
// if the name is missing, we immediately announce an error
@@ -4848,6 +4997,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeStructValueField:
case NodeTypeArrayType:
case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
zig_unreachable();
}
}
@@ -5063,6 +5213,8 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.array_type.resolved_expr;
case NodeTypeErrorType:
return &node->data.error_type.resolved_expr;
+ case NodeTypeTypeLiteral:
+ return &node->data.type_literal.resolved_expr;
case NodeTypeSwitchExpr:
return &node->data.switch_expr.resolved_expr;
case NodeTypeFnProto:
@@ -5081,6 +5233,7 @@ Expr *get_resolved_expr(AstNode *node) {
case NodeTypeStructField:
case NodeTypeStructValueField:
case NodeTypeErrorValueDecl:
+ case NodeTypeTypeDecl:
zig_unreachable();
}
zig_unreachable();
@@ -5098,6 +5251,8 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
return &node->data.error_value_decl.top_level_decl;
case NodeTypeCImport:
return &node->data.c_import.top_level_decl;
+ case NodeTypeTypeDecl:
+ return &node->data.type_decl.top_level_decl;
case NodeTypeNumberLiteral:
case NodeTypeReturnExpr:
case NodeTypeBinOpExpr:
@@ -5138,6 +5293,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeStructValueField:
case NodeTypeArrayType:
case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
zig_unreachable();
}
zig_unreachable();
@@ -5178,6 +5334,14 @@ TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {
return *get_int_type_ptr(g, is_signed, size_in_bits);
}
+TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) {
+ return &g->builtin_types.entry_c_int[c_int_type];
+}
+
+TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type) {
+ return *get_c_int_type_ptr(g, c_int_type);
+}
+
bool handle_is_ptr(TypeTableEntry *type_entry) {
switch (type_entry->id) {
case TypeTableEntryIdInvalid:
@@ -5204,6 +5368,8 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
return type_entry->data.enumeration.gen_field_count != 0;
case TypeTableEntryIdMaybe:
return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer;
+ case TypeTableEntryIdTypeDecl:
+ return handle_is_ptr(type_entry->data.type_decl.canonical_type);
}
zig_unreachable();
}
@@ -5226,3 +5392,48 @@ void find_libc_path(CodeGen *g) {
}
}
+static uint32_t hash_ptr(void *ptr) {
+ uint64_t x = (uint64_t)(uintptr_t)(ptr);
+ uint32_t a = x >> 32;
+ uint32_t b = x & 0xffffffff;
+ return a ^ b;
+}
+
+uint32_t fn_type_id_hash(FnTypeId id) {
+ uint32_t result = 0;
+ result += id.is_extern ? 3349388391 : 0;
+ result += id.is_naked ? 608688877 : 0;
+ result += id.is_var_args ? 1931444534 : 0;
+ result += hash_ptr(id.return_type);
+ result += id.param_count;
+ for (int i = 0; i < id.param_count; i += 1) {
+ FnTypeParamInfo *info = &id.param_info[i];
+ result += info->is_noalias ? 892356923 : 0;
+ result += hash_ptr(info->type);
+ }
+ return result;
+}
+
+bool fn_type_id_eql(FnTypeId a, FnTypeId b) {
+ if (a.is_extern != b.is_extern ||
+ a.is_naked != b.is_naked ||
+ a.return_type != b.return_type ||
+ a.is_var_args != b.is_var_args ||
+ a.param_count != b.param_count)
+ {
+ return false;
+ }
+ for (int i = 0; i < a.param_count; i += 1) {
+ FnTypeParamInfo *a_param_info = &a.param_info[i];
+ FnTypeParamInfo *b_param_info = &b.param_info[i];
+
+ if (a_param_info->type != b_param_info->type) {
+ return false;
+ }
+
+ if (a_param_info->is_noalias != b_param_info->is_noalias) {
+ return false;
+ }
+ }
+ return true;
+}
src/analyze.hpp
@@ -22,7 +22,18 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
bool is_node_void_expr(AstNode *node);
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
+TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
+TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
+TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type);
+TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId fn_type_id);
+TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type);
+TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size);
+TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
+ ContainerKind kind, AstNode *decl_node, const char *name);
+TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
bool handle_is_ptr(TypeTableEntry *type_entry);
void find_libc_path(CodeGen *g);
+TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry);
+
#endif
src/ast_render.cpp
@@ -119,6 +119,8 @@ static const char *node_type_str(NodeType node_type) {
return "ReturnExpr";
case NodeTypeVariableDeclaration:
return "VariableDeclaration";
+ case NodeTypeTypeDecl:
+ return "TypeDecl";
case NodeTypeErrorValueDecl:
return "ErrorValueDecl";
case NodeTypeNumberLiteral:
@@ -179,6 +181,8 @@ static const char *node_type_str(NodeType node_type) {
return "ArrayType";
case NodeTypeErrorType:
return "ErrorType";
+ case NodeTypeTypeLiteral:
+ return "TypeLiteral";
}
}
@@ -260,6 +264,13 @@ void ast_print(FILE *f, AstNode *node, int indent) {
ast_print(f, node->data.variable_declaration.expr, indent + 2);
break;
}
+ case NodeTypeTypeDecl:
+ {
+ Buf *name_buf = &node->data.type_decl.symbol;
+ fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
+ ast_print(f, node->data.type_decl.child_type, indent + 2);
+ break;
+ }
case NodeTypeErrorValueDecl:
{
Buf *name_buf = &node->data.error_value_decl.name;
@@ -478,6 +489,9 @@ void ast_print(FILE *f, AstNode *node, int indent) {
case NodeTypeErrorType:
fprintf(f, "%s\n", node_type_str(node->type));
break;
+ case NodeTypeTypeLiteral:
+ fprintf(f, "%s\n", node_type_str(node->type));
+ break;
}
}
@@ -494,7 +508,14 @@ 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");
+ if (node->type == NodeTypeSymbol) {
+ if (node->data.symbol_expr.override_type_entry) {
+ return node->data.symbol_expr.override_type_entry->id == TypeTableEntryIdVoid;
+ } else if (buf_eql_str(&node->data.symbol_expr.symbol, "void")) {
+ return true;
+ }
+ }
+ return false;
}
static bool is_printable(uint8_t c) {
@@ -515,6 +536,7 @@ static void render_node(AstRender *ar, AstNode *node) {
if (child->type == NodeTypeImport ||
child->type == NodeTypeVariableDeclaration ||
+ child->type == NodeTypeTypeDecl ||
child->type == NodeTypeErrorValueDecl ||
child->type == NodeTypeFnProto)
{
@@ -588,6 +610,14 @@ static void render_node(AstRender *ar, AstNode *node) {
}
break;
}
+ case NodeTypeTypeDecl:
+ {
+ const char *pub_str = visib_mod_string(node->data.type_decl.visib_mod);
+ const char *var_name = buf_ptr(&node->data.type_decl.symbol);
+ fprintf(ar->f, "%stype %s = ", pub_str, var_name);
+ render_node(ar, node->data.type_decl.child_type);
+ break;
+ }
case NodeTypeErrorValueDecl:
zig_panic("TODO");
case NodeTypeBinOpExpr:
@@ -617,7 +647,14 @@ static void render_node(AstRender *ar, AstNode *node) {
break;
}
case NodeTypeSymbol:
- fprintf(ar->f, "%s", buf_ptr(&node->data.symbol_expr.symbol));
+ {
+ TypeTableEntry *override_type = node->data.symbol_expr.override_type_entry;
+ if (override_type) {
+ fprintf(ar->f, "%s", buf_ptr(&override_type->name));
+ } else {
+ fprintf(ar->f, "%s", buf_ptr(&node->data.symbol_expr.symbol));
+ }
+ }
break;
case NodeTypePrefixOpExpr:
{
@@ -719,7 +756,11 @@ static void render_node(AstRender *ar, AstNode *node) {
break;
}
case NodeTypeErrorType:
- zig_panic("TODO");
+ fprintf(ar->f, "error");
+ break;
+ case NodeTypeTypeLiteral:
+ fprintf(ar->f, "type");
+ break;
}
}
src/codegen.cpp
@@ -13,11 +13,13 @@
#include "error.hpp"
#include "analyze.hpp"
#include "errmsg.hpp"
+#include "parseh.hpp"
#include "ast_render.hpp"
#include <stdio.h>
#include <errno.h>
+
CodeGen *codegen_create(Buf *root_source_dir) {
CodeGen *g = allocate<CodeGen>(1);
g->link_table.init(32);
@@ -25,6 +27,7 @@ CodeGen *codegen_create(Buf *root_source_dir) {
g->builtin_fn_table.init(32);
g->primitive_type_table.init(32);
g->unresolved_top_level_decls.init(32);
+ g->fn_type_table.init(32);
g->build_type = CodeGenBuildTypeDebug;
g->root_source_dir = root_source_dir;
g->next_error_index = 1;
@@ -530,12 +533,12 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
fn_type = get_expr_type(fn_ref_expr);
}
- TypeTableEntry *src_return_type = fn_type->data.fn.src_return_type;
+ TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
int fn_call_param_count = node->data.fn_call_expr.params.length;
bool first_arg_ret = handle_is_ptr(src_return_type);
int actual_param_count = fn_call_param_count + (struct_type ? 1 : 0) + (first_arg_ret ? 1 : 0);
- bool is_var_args = fn_type->data.fn.is_var_args;
+ bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
// don't really include void values
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
@@ -1460,7 +1463,7 @@ static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
}
static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value) {
- TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.src_return_type;
+ TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
if (handle_is_ptr(return_type)) {
assert(g->cur_ret_ptr);
gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type);
@@ -1503,7 +1506,7 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
LLVMPositionBuilderAtEnd(g->builder, return_block);
- TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.src_return_type;
+ TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
if (return_type->id == TypeTableEntryIdPureError) {
gen_return(g, node, err_val);
} else if (return_type->id == TypeTableEntryIdErrorUnion) {
@@ -2296,6 +2299,9 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeCharLiteral:
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
+ case NodeTypeErrorType:
+ case NodeTypeTypeLiteral:
+ case NodeTypeArrayType:
// caught by constant expression eval codegen
zig_unreachable();
case NodeTypeRoot:
@@ -2310,11 +2316,10 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
- case NodeTypeArrayType:
- case NodeTypeErrorType:
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeErrorValueDecl:
+ case NodeTypeTypeDecl:
zig_unreachable();
}
zig_unreachable();
@@ -2341,6 +2346,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
}
switch (type_entry->id) {
+ case TypeTableEntryIdTypeDecl:
+ return gen_const_val(g, type_entry->data.type_decl.canonical_type, const_val);
case TypeTableEntryIdInt:
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
case TypeTableEntryIdPureError:
@@ -2557,7 +2564,9 @@ static void do_code_gen(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
- if (handle_is_ptr(fn_table_entry->type_entry->data.fn.src_return_type)) {
+ TypeTableEntry *fn_type = fn_table_entry->type_entry;
+
+ if (handle_is_ptr(fn_type->data.fn.fn_type_id.return_type)) {
LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
}
@@ -2567,7 +2576,9 @@ static void do_code_gen(CodeGen *g) {
AstNode *param_node = fn_proto->params.at(param_decl_i);
assert(param_node->type == NodeTypeParamDecl);
- int gen_index = param_node->data.param_decl.gen_index;
+ FnGenParamInfo *info = &fn_type->data.fn.gen_param_info[param_decl_i];
+ int gen_index = info->gen_index;
+ bool is_byval = info->is_byval;
if (gen_index < 0) {
continue;
@@ -2587,7 +2598,7 @@ static void do_code_gen(CodeGen *g) {
// when https://github.com/andrewrk/zig/issues/82 is fixed, add
// non null attribute here
}
- if (param_node->data.param_decl.is_byval) {
+ if (is_byval) {
LLVMAddAttribute(argument_val, LLVMByValAttribute);
}
}
@@ -2601,7 +2612,7 @@ static void do_code_gen(CodeGen *g) {
AstNode *fn_def_node = fn_table_entry->fn_def_node;
LLVMValueRef fn = fn_table_entry->fn_value;
g->cur_fn = fn_table_entry;
- if (handle_is_ptr(fn_table_entry->type_entry->data.fn.src_return_type)) {
+ if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
g->cur_ret_ptr = LLVMGetParam(fn, 0);
} else {
g->cur_ret_ptr = nullptr;
@@ -2685,7 +2696,9 @@ static void do_code_gen(CodeGen *g) {
AstNode *param_decl = fn_proto->params.at(param_i);
assert(param_decl->type == NodeTypeParamDecl);
- if (param_decl->data.param_decl.gen_index < 0) {
+ FnGenParamInfo *info = &fn_table_entry->type_entry->data.fn.gen_param_info[param_i];
+
+ if (info->gen_index < 0) {
continue;
}
@@ -2724,17 +2737,6 @@ static const int int_sizes_in_bits[] = {
64,
};
-enum CIntType {
- CIntTypeShort,
- CIntTypeUShort,
- CIntTypeInt,
- CIntTypeUInt,
- CIntTypeLong,
- CIntTypeULong,
- CIntTypeLongLong,
- CIntTypeULongLong,
-};
-
struct CIntTypeInfo {
CIntType id;
const char *name;
@@ -2840,6 +2842,8 @@ static void define_builtin_types(CodeGen *g) {
is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
entry->data.integral.is_signed = is_signed;
g->primitive_type_table.put(&entry->name, entry);
+
+ get_c_int_type_ptr(g, info->id)[0] = entry;
}
{
@@ -3093,6 +3097,42 @@ static void init(CodeGen *g, Buf *source_path) {
}
+void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {
+ find_libc_path(g);
+ Buf *full_path = buf_alloc();
+ os_path_join(src_dirname, src_basename, full_path);
+
+ ImportTableEntry *import = allocate<ImportTableEntry>(1);
+ import->source_code = source_code;
+ import->path = full_path;
+ import->fn_table.init(32);
+ g->root_import = import;
+
+ init(g, full_path);
+
+ import->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
+
+ ZigList<ErrorMsg *> errors = {0};
+ int err = parse_h_buf(import, &errors, source_code, g, nullptr);
+ if (err) {
+ fprintf(stderr, "unable to parse .h file: %s\n", err_str(err));
+ exit(1);
+ }
+
+ if (errors.length > 0) {
+ for (int i = 0; i < errors.length; i += 1) {
+ ErrorMsg *err_msg = errors.at(i);
+ print_err_msg(err_msg, g->err_color);
+ }
+ exit(1);
+ }
+}
+
+void codegen_render_ast(CodeGen *g, FILE *f, int indent_size) {
+ ast_render(stdout, g->root_import->root, 4);
+}
+
+
static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
char *dot1 = strstr(buf_ptr(buf), ".");
if (!dot1)
@@ -3156,7 +3196,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
import_entry->line_offsets = tokenization.line_offsets;
import_entry->path = full_path;
import_entry->fn_table.init(32);
- import_entry->fn_type_table.init(32);
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
&g->next_node_index);
src/codegen.hpp
@@ -11,6 +11,8 @@
#include "parser.hpp"
#include "errmsg.hpp"
+#include <stdio.h>
+
CodeGen *codegen_create(Buf *root_source_dir);
void codegen_set_clang_argv(CodeGen *codegen, const char **args, int len);
@@ -27,4 +29,7 @@ void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Bu
void codegen_link(CodeGen *g, const char *out_file);
+void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code);
+void codegen_render_ast(CodeGen *g, FILE *f, int indent_size);
+
#endif
src/main.cpp
@@ -10,8 +10,6 @@
#include "codegen.hpp"
#include "os.hpp"
#include "error.hpp"
-#include "parseh.hpp"
-#include "ast_render.hpp"
#include <stdio.h>
@@ -38,40 +36,41 @@ static int usage(const char *arg0) {
return EXIT_FAILURE;
}
-static int version(const char *arg0, int argc, char **argv) {
- printf("%s\n", ZIG_VERSION_STRING);
- return EXIT_SUCCESS;
-}
-
-struct Build {
- const char *in_file;
- const char *out_file;
- bool release;
- bool strip;
- bool is_static;
- OutType out_type;
- const char *out_name;
- bool verbose;
- ErrColor color;
- const char *libc_path;
- ZigList<const char *> clang_argv;
+enum Cmd {
+ CmdInvalid,
+ CmdBuild,
+ CmdVersion,
+ CmdParseH,
};
-static int build(const char *arg0, int argc, char **argv) {
+int main(int argc, char **argv) {
+ char *arg0 = argv[0];
+ Cmd cmd = CmdInvalid;
+ const char *in_file = nullptr;
+ const char *out_file = nullptr;
+ bool release = false;
+ bool strip = false;
+ bool is_static = false;
+ OutType out_type = OutTypeUnknown;
+ const char *out_name = nullptr;
+ bool verbose = false;
+ ErrColor color = ErrColorAuto;
+ const char *libc_path = nullptr;
+ ZigList<const char *> clang_argv = {0};
int err;
- Build b = {0};
- for (int i = 0; i < argc; i += 1) {
+ for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
+
if (arg[0] == '-') {
if (strcmp(arg, "--release") == 0) {
- b.release = true;
+ release = true;
} else if (strcmp(arg, "--strip") == 0) {
- b.strip = true;
+ strip = true;
} else if (strcmp(arg, "--static") == 0) {
- b.is_static = true;
+ is_static = true;
} else if (strcmp(arg, "--verbose") == 0) {
- b.verbose = true;
+ verbose = true;
} else if (i + 1 >= argc) {
return usage(arg0);
} else {
@@ -79,190 +78,128 @@ static int build(const char *arg0, int argc, char **argv) {
if (i >= argc) {
return usage(arg0);
} else if (strcmp(arg, "--output") == 0) {
- b.out_file = argv[i];
+ out_file = argv[i];
} else if (strcmp(arg, "--export") == 0) {
if (strcmp(argv[i], "exe") == 0) {
- b.out_type = OutTypeExe;
+ out_type = OutTypeExe;
} else if (strcmp(argv[i], "lib") == 0) {
- b.out_type = OutTypeLib;
+ out_type = OutTypeLib;
} else if (strcmp(argv[i], "obj") == 0) {
- b.out_type = OutTypeObj;
+ out_type = OutTypeObj;
} else {
return usage(arg0);
}
} else if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) {
- b.color = ErrColorAuto;
+ color = ErrColorAuto;
} else if (strcmp(argv[i], "on") == 0) {
- b.color = ErrColorOn;
+ color = ErrColorOn;
} else if (strcmp(argv[i], "off") == 0) {
- b.color = ErrColorOff;
+ color = ErrColorOff;
} else {
return usage(arg0);
}
} else if (strcmp(arg, "--name") == 0) {
- b.out_name = argv[i];
+ out_name = argv[i];
} else if (strcmp(arg, "--libc-path") == 0) {
- b.libc_path = argv[i];
+ libc_path = argv[i];
} else if (strcmp(arg, "-isystem") == 0) {
- b.clang_argv.append("-isystem");
- b.clang_argv.append(argv[i]);
+ clang_argv.append("-isystem");
+ clang_argv.append(argv[i]);
} else if (strcmp(arg, "-dirafter") == 0) {
- b.clang_argv.append("-dirafter");
- b.clang_argv.append(argv[i]);
+ clang_argv.append("-dirafter");
+ clang_argv.append(argv[i]);
} else {
return usage(arg0);
}
}
- } else if (!b.in_file) {
- b.in_file = arg;
- } else {
- return usage(arg0);
- }
- }
-
- if (!b.in_file)
- return usage(arg0);
-
- Buf in_file_buf = BUF_INIT;
- buf_init_from_str(&in_file_buf, b.in_file);
-
- Buf root_source_dir = BUF_INIT;
- Buf root_source_code = BUF_INIT;
- Buf root_source_name = BUF_INIT;
- if (buf_eql_str(&in_file_buf, "-")) {
- os_get_cwd(&root_source_dir);
- if ((err = os_fetch_file(stdin, &root_source_code))) {
- fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
- return 1;
- }
- buf_init_from_str(&root_source_name, "");
- } else {
- os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
- if ((err = os_fetch_file_path(buf_create_from_str(b.in_file), &root_source_code))) {
- fprintf(stderr, "unable to open '%s': %s\n", b.in_file, err_str(err));
- return 1;
- }
- }
-
- CodeGen *g = codegen_create(&root_source_dir);
- codegen_set_build_type(g, b.release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
- codegen_set_clang_argv(g, b.clang_argv.items, b.clang_argv.length);
- codegen_set_strip(g, b.strip);
- codegen_set_is_static(g, b.is_static);
- if (b.out_type != OutTypeUnknown)
- codegen_set_out_type(g, b.out_type);
- if (b.out_name)
- codegen_set_out_name(g, buf_create_from_str(b.out_name));
- if (b.libc_path)
- codegen_set_libc_path(g, buf_create_from_str(b.libc_path));
- codegen_set_verbose(g, b.verbose);
- codegen_set_errmsg_color(g, b.color);
- codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
- codegen_link(g, b.out_file);
-
- return 0;
-}
-
-static int parseh(const char *arg0, int argc, char **argv) {
- char *in_file = nullptr;
- ZigList<const char *> clang_argv = {0};
- ErrColor color = ErrColorAuto;
- bool warnings_on = false;
- for (int i = 0; i < argc; i += 1) {
- char *arg = argv[i];
- if (arg[0] == '-') {
- if (arg[1] == 'I') {
- clang_argv.append(arg);
- } else if (strcmp(arg, "-isystem") == 0) {
- if (i + 1 >= argc) {
- return usage(arg0);
- }
- i += 1;
- clang_argv.append("-isystem");
- clang_argv.append(argv[i]);
- } else if (strcmp(arg, "--color") == 0) {
- if (i + 1 >= argc) {
- return usage(arg0);
- }
- i += 1;
- if (strcmp(argv[i], "auto") == 0) {
- color = ErrColorAuto;
- } else if (strcmp(argv[i], "on") == 0) {
- color = ErrColorOn;
- } else if (strcmp(argv[i], "off") == 0) {
- color = ErrColorOff;
- } else {
- return usage(arg0);
- }
- } else if (strcmp(arg, "--c-import-warnings") == 0) {
- warnings_on = true;
+ } else if (cmd == CmdInvalid) {
+ if (strcmp(arg, "build") == 0) {
+ cmd = CmdBuild;
+ } else if (strcmp(arg, "version") == 0) {
+ cmd = CmdVersion;
+ } else if (strcmp(arg, "parseh") == 0) {
+ cmd = CmdParseH;
} else {
- fprintf(stderr, "unrecognized argument: %s", arg);
+ fprintf(stderr, "Unrecognized command: %s\n", arg);
return usage(arg0);
}
- } else if (!in_file) {
- in_file = arg;
} else {
- return usage(arg0);
- }
- }
- if (!in_file) {
- fprintf(stderr, "missing target argument");
- return usage(arg0);
- }
-
- clang_argv.append(in_file);
-
- Buf *libc_include_path = buf_alloc();
- os_path_join(buf_create_from_str(ZIG_LIBC_DIR), buf_create_from_str("include"), libc_include_path);
- clang_argv.append("-isystem");
- clang_argv.append(buf_ptr(libc_include_path));
-
- ImportTableEntry import = {0};
- ZigList<ErrorMsg *> errors = {0};
- uint32_t next_node_index = 0;
- int err = parse_h_file(&import, &errors, &clang_argv, warnings_on, &next_node_index);
-
- if (err) {
- fprintf(stderr, "unable to parse .h file: %s\n", err_str(err));
- return EXIT_FAILURE;
- }
-
- if (errors.length > 0) {
- for (int i = 0; i < errors.length; i += 1) {
- ErrorMsg *err_msg = errors.at(i);
- print_err_msg(err_msg, color);
+ switch (cmd) {
+ case CmdBuild:
+ case CmdParseH:
+ if (!in_file) {
+ in_file = arg;
+ } else {
+ return usage(arg0);
+ }
+ break;
+ case CmdVersion:
+ return usage(arg0);
+ case CmdInvalid:
+ zig_unreachable();
+ }
}
- return EXIT_FAILURE;
}
- ast_render(stdout, import.root, 4);
+ switch (cmd) {
+ case CmdBuild:
+ case CmdParseH:
+ {
+ if (!in_file)
+ return usage(arg0);
- return 0;
-}
+ Buf in_file_buf = BUF_INIT;
+ buf_init_from_str(&in_file_buf, in_file);
+
+ Buf root_source_dir = BUF_INIT;
+ Buf root_source_code = BUF_INIT;
+ Buf root_source_name = BUF_INIT;
+ if (buf_eql_str(&in_file_buf, "-")) {
+ os_get_cwd(&root_source_dir);
+ if ((err = os_fetch_file(stdin, &root_source_code))) {
+ fprintf(stderr, "unable to read stdin: %s\n", err_str(err));
+ return 1;
+ }
+ buf_init_from_str(&root_source_name, "");
+ } else {
+ os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
+ if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) {
+ fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err));
+ return 1;
+ }
+ }
-int main(int argc, char **argv) {
- char *arg0 = argv[0];
- int (*cmd)(const char *, int, char **) = nullptr;
- for (int i = 1; i < argc; i += 1) {
- char *arg = argv[i];
- if (arg[0] == '-' && arg[1] == '-') {
- return usage(arg0);
- } else {
- if (strcmp(arg, "build") == 0) {
- cmd = build;
- } else if (strcmp(arg, "version") == 0) {
- cmd = version;
- } else if (strcmp(arg, "parseh") == 0) {
- cmd = parseh;
+ CodeGen *g = codegen_create(&root_source_dir);
+ codegen_set_build_type(g, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
+ codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
+ codegen_set_strip(g, strip);
+ codegen_set_is_static(g, is_static);
+ if (out_type != OutTypeUnknown)
+ codegen_set_out_type(g, out_type);
+ if (out_name)
+ codegen_set_out_name(g, buf_create_from_str(out_name));
+ if (libc_path)
+ codegen_set_libc_path(g, buf_create_from_str(libc_path));
+ codegen_set_verbose(g, verbose);
+ codegen_set_errmsg_color(g, color);
+
+ if (cmd == CmdBuild) {
+ codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
+ codegen_link(g, out_file);
+ return EXIT_SUCCESS;
+ } else if (cmd == CmdParseH) {
+ codegen_parseh(g, &root_source_dir, &root_source_name, &root_source_code);
+ codegen_render_ast(g, stdout, 4);
+ return EXIT_SUCCESS;
} else {
- fprintf(stderr, "Unrecognized command: %s\n", arg);
- return usage(arg0);
+ zig_unreachable();
}
- return cmd(arg0, argc - i - 1, &argv[i + 1]);
}
+ case CmdVersion:
+ printf("%s\n", ZIG_VERSION_STRING);
+ return EXIT_SUCCESS;
+ case CmdInvalid:
+ return usage(arg0);
}
-
- return usage(arg0);
}
src/parseh.cpp
@@ -12,6 +12,7 @@
#include "parser.hpp"
#include "all_types.hpp"
#include "tokenizer.hpp"
+#include "analyze.hpp"
#include <clang/Frontend/ASTUnit.h>
#include <clang/Frontend/CompilerInstance.h>
@@ -30,22 +31,27 @@ struct Context {
ZigList<ErrorMsg *> *errors;
bool warnings_on;
VisibMod visib_mod;
- bool have_c_void_decl_node;
+ TypeTableEntry *c_void_type;
AstNode *root;
- 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 *, TypeTableEntry *, buf_hash, buf_eql_buf> global_type_table;
+ HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_value_table;
+ HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_type_table;
+ HashMap<Buf *, TypeTableEntry *, 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;
- uint32_t *next_node_index;
+ AstNode *source_node;
+
+ CodeGen *codegen;
};
-static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl);
-static AstNode *make_qual_type_node_with_table(Context *c, QualType qt, const Decl *decl,
- HashMap<Buf *, bool, buf_hash, buf_eql_buf> *type_table);
+static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl,
+ HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> *type_table);
+
+static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl);
+
__attribute__ ((format (printf, 3, 4)))
static void emit_warning(Context *c, const Decl *decl, const char *format, ...) {
@@ -77,8 +83,8 @@ static AstNode *create_node(Context *c, NodeType type) {
AstNode *node = allocate<AstNode>(1);
node->type = type;
node->owner = c->import;
- node->create_index = *c->next_node_index;
- *c->next_node_index += 1;
+ node->create_index = c->codegen->next_node_index;
+ c->codegen->next_node_index += 1;
return node;
}
@@ -178,61 +184,51 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) {
return create_prefix_node(c, PrefixOpNegation, num_lit_node);
}
-static AstNode *create_array_type_node(Context *c, AstNode *child_type_node, uint64_t size, bool is_const) {
- AstNode *node = create_node(c, NodeTypeArrayType);
- node->data.array_type.size = create_num_lit_unsigned(c, size);
- node->data.array_type.child_type = child_type_node;
- node->data.array_type.is_const = is_const;
+static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) {
+ AstNode *node = create_node(c, NodeTypeTypeDecl);
+ buf_init_from_str(&node->data.type_decl.symbol, name);
+ node->data.type_decl.visib_mod = c->visib_mod;
+ node->data.type_decl.directives = create_empty_directives(c);
+ node->data.type_decl.child_type = child_type_node;
normalize_parent_ptrs(node);
return node;
}
+static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) {
+ AstNode *node = create_node(c, NodeTypeSymbol);
+ node->data.symbol_expr.override_type_entry = type_entry;
+ 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, TypeTableEntry *type_decl) {
+ assert(type_decl);
-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);
+ AstNode *node = create_type_decl_node(c, buf_ptr(&type_decl->name),
+ make_type_node(c, type_decl->data.type_decl.child_type));
+ node->data.type_decl.override_type = type_decl;
- c->root_name_table.put(new_name, true);
+ c->global_type_table.put(&type_decl->name, type_decl);
c->root->data.root.top_level_decls.append(node);
return node;
}
-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->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 create_symbol_node(c, "c_void");
- } else {
- return type_node;
+static TypeTableEntry *get_c_void_type(Context *c) {
+ if (!c->c_void_type) {
+ c->c_void_type = get_typedecl_type(c->codegen, "c_void", c->codegen->builtin_types.entry_u8);
+ add_typedef_node(c, c->c_void_type);
}
-}
-
-static AstNode *pointer_to_type(Context *c, AstNode *type_node, bool is_const) {
- assert(type_node);
- PrefixOp op = is_const ? PrefixOpConstAddressOf : PrefixOpAddressOf;
- AstNode *child_node = create_prefix_node(c, op, convert_to_c_void(c, type_node));
- return create_prefix_node(c, PrefixOpMaybe, child_node);
-}
-static bool type_is_int(AstNode *type_node) {
- // TODO recurse through the type table
- return true;
+ return c->c_void_type;
}
-static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
- HashMap<Buf *, bool, buf_hash, buf_eql_buf> *type_table)
+static TypeTableEntry *resolve_type_with_table(Context *c, const Type *ty, const Decl *decl,
+ HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> *type_table)
{
switch (ty->getTypeClass()) {
case Type::Builtin:
@@ -240,35 +236,35 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
switch (builtin_ty->getKind()) {
case BuiltinType::Void:
- return create_symbol_node(c, "void");
+ return c->codegen->builtin_types.entry_void;
case BuiltinType::Bool:
- return create_symbol_node(c, "bool");
+ return c->codegen->builtin_types.entry_bool;
case BuiltinType::Char_U:
case BuiltinType::UChar:
case BuiltinType::Char_S:
- return create_symbol_node(c, "u8");
+ return c->codegen->builtin_types.entry_u8;
case BuiltinType::SChar:
- return create_symbol_node(c, "i8");
+ return c->codegen->builtin_types.entry_i8;
case BuiltinType::UShort:
- return create_symbol_node(c, "c_ushort");
+ return get_c_int_type(c->codegen, CIntTypeUShort);
case BuiltinType::UInt:
- return create_symbol_node(c, "c_uint");
+ return get_c_int_type(c->codegen, CIntTypeUInt);
case BuiltinType::ULong:
- return create_symbol_node(c, "c_ulong");
+ return get_c_int_type(c->codegen, CIntTypeULong);
case BuiltinType::ULongLong:
- return create_symbol_node(c, "c_ulonglong");
+ return get_c_int_type(c->codegen, CIntTypeULongLong);
case BuiltinType::Short:
- return create_symbol_node(c, "c_short");
+ return get_c_int_type(c->codegen, CIntTypeShort);
case BuiltinType::Int:
- return create_symbol_node(c, "c_int");
+ return get_c_int_type(c->codegen, CIntTypeInt);
case BuiltinType::Long:
- return create_symbol_node(c, "c_long");
+ return get_c_int_type(c->codegen, CIntTypeLong);
case BuiltinType::LongLong:
- return create_symbol_node(c, "c_longlong");
+ return get_c_int_type(c->codegen, CIntTypeLongLong);
case BuiltinType::Float:
- return create_symbol_node(c, "f32");
+ return c->codegen->builtin_types.entry_f32;
case BuiltinType::Double:
- return create_symbol_node(c, "f64");
+ return c->codegen->builtin_types.entry_f64;
case BuiltinType::LongDouble:
case BuiltinType::WChar_U:
case BuiltinType::Char16:
@@ -297,7 +293,7 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
case BuiltinType::BuiltinFn:
case BuiltinType::ARCUnbridgedCast:
emit_warning(c, decl, "missed a builtin type");
- return nullptr;
+ return c->codegen->builtin_types.entry_invalid;
}
break;
}
@@ -305,17 +301,26 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
{
const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
QualType child_qt = pointer_ty->getPointeeType();
- AstNode *type_node = make_qual_type_node(c, child_qt, decl);
- if (!type_node) {
- return nullptr;
+ TypeTableEntry *child_type = resolve_qual_type(c, child_qt, decl);
+ if (get_underlying_type(child_type)->id == TypeTableEntryIdInvalid) {
+ emit_warning(c, decl, "pointer to unresolved type");
+ return c->codegen->builtin_types.entry_invalid;
}
+
if (child_qt.getTypePtr()->getTypeClass() == Type::Paren) {
const ParenType *paren_type = static_cast<const ParenType *>(child_qt.getTypePtr());
if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) {
- return create_prefix_node(c, PrefixOpMaybe, type_node);
+ return get_maybe_type(c->codegen, child_type);
}
}
- return pointer_to_type(c, type_node, child_qt.isConstQualified());
+ bool is_const = child_qt.isConstQualified();
+
+ if (child_type->id == TypeTableEntryIdVoid) {
+ child_type = get_c_void_type(c);
+ }
+
+ TypeTableEntry *non_null_pointer_type = get_pointer_to_type(c->codegen, child_type, is_const);
+ return get_maybe_type(c->codegen, non_null_pointer_type);
}
case Type::Typedef:
{
@@ -323,32 +328,28 @@ static AstNode *make_type_node(Context *c, const Type *ty, const 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 create_symbol_node(c, "u8");
+ return c->codegen->builtin_types.entry_u8;
} else if (buf_eql_str(type_name, "int8_t")) {
- return create_symbol_node(c, "i8");
+ return c->codegen->builtin_types.entry_i8;
} else if (buf_eql_str(type_name, "uint16_t")) {
- return create_symbol_node(c, "u16");
+ return c->codegen->builtin_types.entry_u16;
} else if (buf_eql_str(type_name, "int16_t")) {
- return create_symbol_node(c, "i16");
+ return c->codegen->builtin_types.entry_i16;
} else if (buf_eql_str(type_name, "uint32_t")) {
- return create_symbol_node(c, "u32");
+ return c->codegen->builtin_types.entry_u32;
} else if (buf_eql_str(type_name, "int32_t")) {
- return create_symbol_node(c, "i32");
+ return c->codegen->builtin_types.entry_i32;
} else if (buf_eql_str(type_name, "uint64_t")) {
- return create_symbol_node(c, "u64");
+ return c->codegen->builtin_types.entry_u64;
} else if (buf_eql_str(type_name, "int64_t")) {
- return create_symbol_node(c, "i64");
+ return c->codegen->builtin_types.entry_i64;
} else if (buf_eql_str(type_name, "intptr_t")) {
- return create_symbol_node(c, "isize");
+ return c->codegen->builtin_types.entry_isize;
} else if (buf_eql_str(type_name, "uintptr_t")) {
- return create_symbol_node(c, "usize");
+ return c->codegen->builtin_types.entry_usize;
} else {
auto entry = type_table->maybe_get(type_name);
- if (entry) {
- return create_symbol_node(c, buf_ptr(type_name));
- } else {
- return nullptr;
- }
+ return entry ? entry->value : c->codegen->builtin_types.entry_invalid;
}
}
case Type::Elaborated:
@@ -356,10 +357,10 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
switch (elaborated_ty->getKeyword()) {
case ETK_Struct:
- return make_qual_type_node_with_table(c, elaborated_ty->getNamedType(),
+ return resolve_qual_type_with_table(c, elaborated_ty->getNamedType(),
decl, &c->struct_type_table);
case ETK_Enum:
- return make_qual_type_node_with_table(c, elaborated_ty->getNamedType(),
+ return resolve_qual_type_with_table(c, elaborated_ty->getNamedType(),
decl, &c->enum_type_table);
case ETK_Interface:
case ETK_Union:
@@ -367,35 +368,63 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
case ETK_Typename:
case ETK_None:
emit_warning(c, decl, "unsupported elaborated type");
- return nullptr;
+ return c->codegen->builtin_types.entry_invalid;
}
}
case Type::FunctionProto:
{
const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty);
- AstNode *node = create_node(c, NodeTypeFnProto);
- buf_resize(&node->data.fn_proto.name, 0);
- node->data.fn_proto.is_extern = true;
- node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic();
- node->data.fn_proto.return_type = make_qual_type_node(c, fn_proto_ty->getReturnType(), decl);
-
- if (!node->data.fn_proto.return_type) {
- return nullptr;
+
+ switch (fn_proto_ty->getCallConv()) {
+ case CC_C: // __attribute__((cdecl))
+ break;
+ case CC_X86StdCall: // __attribute__((stdcall))
+ case CC_X86FastCall: // __attribute__((fastcall))
+ case CC_X86ThisCall: // __attribute__((thiscall))
+ case CC_X86VectorCall: // __attribute__((vectorcall))
+ case CC_X86Pascal: // __attribute__((pascal))
+ case CC_X86_64Win64: // __attribute__((ms_abi))
+ case CC_X86_64SysV: // __attribute__((sysv_abi))
+ case CC_AAPCS: // __attribute__((pcs("aapcs")))
+ case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp")))
+ case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc))
+ case CC_SpirFunction: // default for OpenCL functions on SPIR target
+ case CC_SpirKernel: // inferred for OpenCL kernels on SPIR target
+ emit_warning(c, decl, "function type has non C calling convention");
+ return c->codegen->builtin_types.entry_invalid;
+ }
+
+ FnTypeId fn_type_id;
+ fn_type_id.is_naked = false;
+ fn_type_id.is_extern = true;
+ fn_type_id.is_var_args = fn_proto_ty->isVariadic();
+ fn_type_id.param_count = fn_proto_ty->getNumParams();
+
+
+ if (fn_proto_ty->getNoReturnAttr()) {
+ fn_type_id.return_type = c->codegen->builtin_types.entry_unreachable;
+ } else {
+ fn_type_id.return_type = resolve_qual_type(c, fn_proto_ty->getReturnType(), decl);
+ if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) {
+ return c->codegen->builtin_types.entry_invalid;
+ }
}
- int arg_count = fn_proto_ty->getNumParams();
- for (int i = 0; i < arg_count; i += 1) {
+ fn_type_id.param_info = allocate<FnTypeParamInfo>(fn_type_id.param_count);
+ for (int i = 0; i < fn_type_id.param_count; i += 1) {
QualType qt = fn_proto_ty->getParamType(i);
- bool is_noalias = qt.isRestrictQualified();
- AstNode *type_node = make_qual_type_node(c, qt, decl);
- if (!type_node) {
- return nullptr;
+ TypeTableEntry *param_type = resolve_qual_type(c, qt, decl);
+
+ if (param_type->id == TypeTableEntryIdInvalid) {
+ return c->codegen->builtin_types.entry_invalid;
}
- node->data.fn_proto.params.append(create_param_decl_node(c, "", type_node, is_noalias));
+
+ FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
+ param_info->type = param_type;
+ param_info->is_noalias = qt.isRestrictQualified();
}
- normalize_parent_ptrs(node);
- return node;
+ return get_fn_type(c->codegen, fn_type_id);
}
case Type::Record:
{
@@ -403,20 +432,15 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
Buf *record_name = buf_create_from_str(decl_name(record_ty->getDecl()));
if (buf_len(record_name) == 0) {
emit_warning(c, decl, "unhandled anonymous struct");
- return nullptr;
- } else if (type_table->maybe_get(record_name)) {
- const char *prefix_str;
- if (type_table == &c->enum_type_table) {
- prefix_str = "enum_";
- } else if (type_table == &c->struct_type_table) {
- prefix_str = "struct_";
- } else {
- prefix_str = "";
- }
- return create_symbol_node(c, buf_ptr(buf_sprintf("%s%s", prefix_str, buf_ptr(record_name))));
- } else {
- return nullptr;
+ return c->codegen->builtin_types.entry_invalid;
}
+
+ auto entry = type_table->maybe_get(record_name);
+ if (!entry) {
+ return c->codegen->builtin_types.entry_invalid;
+ }
+
+ return entry->value;
}
case Type::Enum:
{
@@ -424,32 +448,32 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
Buf *record_name = buf_create_from_str(decl_name(enum_ty->getDecl()));
if (buf_len(record_name) == 0) {
emit_warning(c, decl, "unhandled anonymous enum");
- return nullptr;
- } else if (type_table->maybe_get(record_name)) {
- const char *prefix_str;
- if (type_table == &c->enum_type_table) {
- prefix_str = "enum_";
- } else if (type_table == &c->struct_type_table) {
- prefix_str = "struct_";
- } else {
- prefix_str = "";
- }
- return create_symbol_node(c, buf_ptr(buf_sprintf("%s%s", prefix_str, buf_ptr(record_name))));
- } else {
- return nullptr;
+ return c->codegen->builtin_types.entry_invalid;
+ }
+
+ auto entry = type_table->maybe_get(record_name);
+ if (!entry) {
+ return c->codegen->builtin_types.entry_invalid;
}
+
+ return entry->value;
}
case Type::ConstantArray:
{
const ConstantArrayType *const_arr_ty = static_cast<const ConstantArrayType *>(ty);
- AstNode *child_type_node = make_qual_type_node(c, const_arr_ty->getElementType(), decl);
+ TypeTableEntry *child_type = resolve_qual_type(c, const_arr_ty->getElementType(), decl);
uint64_t size = const_arr_ty->getSize().getLimitedValue();
- return create_array_type_node(c, child_type_node, size, false);
+ return get_array_type(c->codegen, child_type, size);
}
case Type::Paren:
{
const ParenType *paren_ty = static_cast<const ParenType *>(ty);
- return make_qual_type_node(c, paren_ty->getInnerType(), decl);
+ return resolve_qual_type(c, paren_ty->getInnerType(), decl);
+ }
+ case Type::Decayed:
+ {
+ const DecayedType *decayed_ty = static_cast<const DecayedType *>(ty);
+ return resolve_qual_type(c, decayed_ty->getOriginalType(), decl);
}
case Type::BlockPointer:
case Type::LValueReference:
@@ -464,7 +488,6 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
case Type::FunctionNoProto:
case Type::UnresolvedUsing:
case Type::Adjusted:
- case Type::Decayed:
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Decltype:
@@ -485,68 +508,68 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
case Type::ObjCObjectPointer:
case Type::Atomic:
emit_warning(c, decl, "missed a '%s' type", ty->getTypeClassName());
- return nullptr;
+ return c->codegen->builtin_types.entry_invalid;
}
}
-static AstNode *make_qual_type_node_with_table(Context *c, QualType qt, const Decl *decl,
- HashMap<Buf *, bool, buf_hash, buf_eql_buf> *type_table)
+static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl,
+ HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> *type_table)
{
- return make_type_node(c, qt.getTypePtr(), decl, type_table);
+ return resolve_type_with_table(c, qt.getTypePtr(), decl, type_table);
}
-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_name_table);
+static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *decl) {
+ return resolve_qual_type_with_table(c, qt, decl, &c->global_type_table);
}
static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
- AstNode *node = create_node(c, NodeTypeFnProto);
- buf_init_from_str(&node->data.fn_proto.name, decl_name(fn_decl));
+ Buf fn_name = BUF_INIT;
+ buf_init_from_str(&fn_name, decl_name(fn_decl));
- auto fn_entry = c->fn_table.maybe_get(&node->data.fn_proto.name);
- if (fn_entry) {
+ if (c->fn_table.maybe_get(&fn_name)) {
// we already saw this function
return;
}
- node->data.fn_proto.is_extern = true;
+ TypeTableEntry *fn_type = resolve_qual_type(c, fn_decl->getType(), fn_decl);
+
+ if (fn_type->id == TypeTableEntryIdInvalid) {
+ emit_warning(c, fn_decl, "ignoring function '%s' - unable to resolve type", buf_ptr(&fn_name));
+ return;
+ }
+ assert(fn_type->id == TypeTableEntryIdFn);
+
+
+ AstNode *node = create_node(c, NodeTypeFnProto);
+ buf_init_from_buf(&node->data.fn_proto.name, &fn_name);
+
+ node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern;
node->data.fn_proto.visib_mod = c->visib_mod;
node->data.fn_proto.directives = create_empty_directives(c);
- node->data.fn_proto.is_var_args = fn_decl->isVariadic();
+ node->data.fn_proto.is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
+ node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
+
+ assert(!fn_type->data.fn.fn_type_id.is_naked);
- int arg_count = fn_decl->getNumParams();
+ int arg_count = fn_type->data.fn.fn_type_id.param_count;
+ Buf name_buf = BUF_INIT;
for (int i = 0; i < arg_count; i += 1) {
+ FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[i];
+ AstNode *type_node = make_type_node(c, param_info->type);
const ParmVarDecl *param = fn_decl->getParamDecl(i);
const char *name = decl_name(param);
if (strlen(name) == 0) {
- name = buf_ptr(buf_sprintf("arg%d", i));
+ buf_resize(&name_buf, 0);
+ buf_appendf(&name_buf, "arg%d", i);
+ name = buf_ptr(&name_buf);
}
- QualType qt = param->getOriginalType();
- bool is_noalias = qt.isRestrictQualified();
- AstNode *type_node = make_qual_type_node(c, qt, fn_decl);
- if (!type_node) {
- emit_warning(c, param, "skipping function %s, unresolved param type\n", name);
- return;
- }
-
- node->data.fn_proto.params.append(create_param_decl_node(c, name, type_node, is_noalias));
- }
- if (fn_decl->isNoReturn()) {
- 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(), fn_decl);
- }
-
- if (!node->data.fn_proto.return_type) {
- emit_warning(c, fn_decl, "skipping function %s, unresolved return type\n",
- buf_ptr(&node->data.fn_proto.name));
- return;
+ node->data.fn_proto.params.append(create_param_decl_node(c, name, type_node, param_info->is_noalias));
}
normalize_parent_ptrs(node);
- c->fn_table.put(&node->data.fn_proto.name, true);
+ c->fn_table.put(buf_create_from_buf(&fn_name), true);
c->root->data.root.top_level_decls.append(node);
}
@@ -573,7 +596,9 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl)
// use the name of this typedef
// TODO
- add_typedef_node(c, type_name, make_qual_type_node(c, child_qt, typedef_decl));
+ TypeTableEntry *child_type = resolve_qual_type(c, child_qt, typedef_decl);
+ TypeTableEntry *decl_type = get_typedecl_type(c->codegen, buf_ptr(type_name), child_type);
+ add_typedef_node(c, decl_type);
}
static void add_alias(Context *c, const char *new_name, const char *target_name) {
@@ -582,7 +607,14 @@ static void add_alias(Context *c, const char *new_name, const char *target_name)
}
static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
- Buf *bare_name = buf_create_from_str(decl_name(enum_decl));
+ const char *raw_name = decl_name(enum_decl);
+ // we have no interest in top level anonymous enums since they're
+ // not exposing anything.
+ if (raw_name[0] == 0) {
+ return;
+ }
+
+ Buf *bare_name = buf_create_from_str(raw_name);
Buf *full_type_name = buf_sprintf("enum_%s", buf_ptr(bare_name));
if (c->enum_type_table.maybe_get(bare_name)) {
@@ -590,97 +622,145 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
return;
}
- // eagerly put the name in the table, but we need to remember to remove it if it fails
- // boy it would be nice to have defer here wouldn't it
- c->enum_type_table.put(bare_name, true);
-
const EnumDecl *enum_def = enum_decl->getDefinition();
if (!enum_def) {
+ TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(full_type_name),
+ c->codegen->builtin_types.entry_u8);
+ c->enum_type_table.put(bare_name, typedecl_type);
+
// this is a type that we can point to but that's it, same as `struct Foo;`.
- add_typedef_node(c, full_type_name, create_symbol_node(c, "u8"));
+ add_typedef_node(c, typedecl_type);
add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
return;
}
- AstNode *node = create_node(c, NodeTypeStructDecl);
- buf_init_from_buf(&node->data.struct_decl.name, full_type_name);
-
- node->data.struct_decl.kind = ContainerKindEnum;
- node->data.struct_decl.visib_mod = VisibModExport;
- node->data.struct_decl.directives = create_empty_directives(c);
-
-
- ZigList<AstNode *> var_decls = {0};
- int i = 0;
+ // count and validate
+ uint32_t field_count = 0;
for (auto it = enum_def->enumerator_begin(),
it_end = enum_def->enumerator_end();
- it != it_end; ++it, i += 1)
+ it != it_end; ++it, field_count += 1)
{
const EnumConstantDecl *enum_const = *it;
if (enum_const->getInitExpr()) {
- c->enum_type_table.remove(bare_name);
emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name));
return;
}
- Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
+ }
+
+ TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import,
+ ContainerKindEnum, c->source_node, buf_ptr(full_type_name));
+
+ enum_type->data.enumeration.gen_field_count = 0;
+ enum_type->data.enumeration.complete = true;
- Buf field_name = BUF_INIT;
+ TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(c->codegen, field_count);
+ enum_type->align_in_bits = tag_type_entry->size_in_bits;
+ enum_type->size_in_bits = tag_type_entry->size_in_bits;
+ enum_type->data.enumeration.tag_type = tag_type_entry;
+ c->enum_type_table.put(bare_name, enum_type);
+ // make an alias without the "enum_" prefix. this will get emitted at the
+ // end if it doesn't conflict with anything else
+ add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
+
+ enum_type->data.enumeration.field_count = field_count;
+ enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
+ LLVMZigDIEnumerator **di_enumerators = allocate<LLVMZigDIEnumerator*>(field_count);
+
+ ZigList<AstNode *> var_decls = {0};
+ uint32_t 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;
+
+ Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
+ Buf *field_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);
+ field_name = slice;
} else {
- buf_resize(&field_name, 0);
- buf_appendf(&field_name, "_%s", buf_ptr(slice));
+ field_name = buf_sprintf("_%s", buf_ptr(slice));
}
} else {
- buf_init_from_buf(&field_name, enum_val_name);
+ field_name = enum_val_name;
}
- AstNode *field_node = create_struct_field_node(c, buf_ptr(&field_name), create_symbol_node(c, "void"));
- node->data.struct_decl.fields.append(field_node);
+ TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
+ type_enum_field->name = field_name;
+ type_enum_field->type_entry = c->codegen->builtin_types.entry_void;
+ type_enum_field->value = i;
+
+ di_enumerators[i] = LLVMZigCreateDebugEnumerator(c->codegen->dbuilder, buf_ptr(type_enum_field->name), i);
+
// 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));
+ // at this point we can rely on the enum emitting successfully
+ 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);
var_decls.append(var_node);
- c->root_name_table.put(enum_val_name, true);
+ c->global_value_table.put(enum_val_name, enum_type);
}
- normalize_parent_ptrs(node);
- c->root->data.root.top_level_decls.append(node);
+ // create llvm type for root struct
+ enum_type->type_ref = tag_type_entry->type_ref;
+
+ // create debug type for tag
+ unsigned line = c->source_node ? (c->source_node->line + 1) : 0;
+ LLVMZigDIType *tag_di_type = LLVMZigCreateDebugEnumerationType(c->codegen->dbuilder,
+ LLVMZigFileToScope(c->import->di_file), buf_ptr(bare_name),
+ c->import->di_file, line,
+ tag_type_entry->size_in_bits, tag_type_entry->align_in_bits, di_enumerators, field_count,
+ tag_type_entry->di_type, "");
+
+ LLVMZigReplaceTemporary(c->codegen->dbuilder, enum_type->di_type, tag_di_type);
+ enum_type->di_type = tag_di_type;
+
+ //////////
+
+ // now create top level decl for the type
+ AstNode *enum_node = create_node(c, NodeTypeStructDecl);
+ buf_init_from_buf(&enum_node->data.struct_decl.name, full_type_name);
+ enum_node->data.struct_decl.kind = ContainerKindEnum;
+ enum_node->data.struct_decl.visib_mod = VisibModExport;
+ enum_node->data.struct_decl.directives = create_empty_directives(c);
+ enum_node->data.struct_decl.type_entry = enum_type;
+
+ for (uint32_t i = 0; i < field_count; i += 1) {
+ TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
+ AstNode *type_node = make_type_node(c, type_enum_field->type_entry);
+ AstNode *field_node = create_struct_field_node(c, buf_ptr(type_enum_field->name), type_node);
+ enum_node->data.struct_decl.fields.append(field_node);
+ }
+
+ normalize_parent_ptrs(enum_node);
+ c->root->data.root.top_level_decls.append(enum_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
- add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
}
static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
const char *raw_name = decl_name(record_decl);
+ // we have no interest in top level anonymous structs since they're
+ // not exposing anything.
if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) {
return;
}
- Buf *bare_name = buf_create_from_str(raw_name);
-
if (!record_decl->isStruct()) {
- emit_warning(c, record_decl, "skipping record %s, not a struct", buf_ptr(bare_name));
- return;
- }
-
- if (buf_len(bare_name) == 0) {
- emit_warning(c, record_decl, "skipping anonymous struct");
+ emit_warning(c, record_decl, "skipping record %s, not a struct", raw_name);
return;
}
+ Buf *bare_name = buf_create_from_str(raw_name);
Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name));
if (c->struct_type_table.maybe_get(bare_name)) {
@@ -688,55 +768,127 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
return;
}
- // eagerly put the name in the table, but we need to remember to remove it if it fails
- // boy it would be nice to have defer here wouldn't it
- c->struct_type_table.put(bare_name, true);
-
-
RecordDecl *record_def = record_decl->getDefinition();
if (!record_def) {
+ TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(full_type_name),
+ c->codegen->builtin_types.entry_u8);
+ c->struct_type_table.put(bare_name, typedecl_type);
+
// this is a type that we can point to but that's it, such as `struct Foo;`.
- add_typedef_node(c, full_type_name, create_symbol_node(c, "u8"));
+ add_typedef_node(c, typedecl_type);
add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
return;
}
- AstNode *node = create_node(c, NodeTypeStructDecl);
- buf_init_from_buf(&node->data.struct_decl.name, full_type_name);
+ TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import,
+ ContainerKindStruct, c->source_node, buf_ptr(full_type_name));
- node->data.struct_decl.kind = ContainerKindStruct;
- node->data.struct_decl.visib_mod = VisibModExport;
- node->data.struct_decl.directives = create_empty_directives(c);
+ c->struct_type_table.put(bare_name, struct_type);
+ // make an alias without the "struct_" prefix. this will get emitted at the
+ // end if it doesn't conflict with anything else
+ add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
+ // count fields and validate
+ uint32_t field_count = 0;
for (auto it = record_def->field_begin(),
it_end = record_def->field_end();
- it != it_end; ++it)
+ it != it_end; ++it, field_count += 1)
{
const FieldDecl *field_decl = *it;
if (field_decl->isBitField()) {
- c->struct_type_table.remove(bare_name);
emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name));
return;
}
+ }
+
+ struct_type->data.structure.src_field_count = field_count;
+ struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
+
+ // we possibly allocate too much here since gen_field_count can be lower than field_count.
+ // the only problem is potential wasted space though.
+ LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
+ LLVMZigDIType **di_element_types = allocate<LLVMZigDIType*>(field_count);
+
+ uint64_t total_size_in_bits = 0;
+ uint64_t first_field_align_in_bits = 0;
+ uint64_t offset_in_bits = 0;
+
+ uint32_t i = 0;
+ unsigned line = c->source_node ? c->source_node->line : 0;
+ for (auto it = record_def->field_begin(),
+ it_end = record_def->field_end();
+ it != it_end; ++it, i += 1)
+ {
+ const FieldDecl *field_decl = *it;
+
+ TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
+ type_struct_field->name = buf_create_from_str(decl_name(field_decl));
+ type_struct_field->src_index = i;
+ type_struct_field->gen_index = i;
+ type_struct_field->type_entry = resolve_qual_type(c, field_decl->getType(), field_decl);
- AstNode *type_node = make_qual_type_node(c, field_decl->getType(), field_decl);
- if (!type_node) {
- c->struct_type_table.remove(bare_name);
- emit_warning(c, field_decl, "skipping struct %s - unhandled type\n", buf_ptr(bare_name));
+ if (type_struct_field->type_entry->id == TypeTableEntryIdInvalid) {
+ emit_warning(c, field_decl, "skipping struct %s - unresolved type\n", buf_ptr(bare_name));
return;
}
- AstNode *field_node = create_struct_field_node(c, decl_name(field_decl), type_node);
- node->data.struct_decl.fields.append(field_node);
+ di_element_types[i] = LLVMZigCreateDebugMemberType(c->codegen->dbuilder,
+ LLVMZigTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
+ c->import->di_file, line + 1,
+ type_struct_field->type_entry->size_in_bits,
+ type_struct_field->type_entry->align_in_bits,
+ offset_in_bits, 0, type_struct_field->type_entry->di_type);
+
+ element_types[i] = type_struct_field->type_entry->type_ref;
+ assert(di_element_types[i]);
+ assert(element_types[i]);
+
+ total_size_in_bits += type_struct_field->type_entry->size_in_bits;
+ if (first_field_align_in_bits == 0) {
+ first_field_align_in_bits = type_struct_field->type_entry->align_in_bits;
+ }
+ offset_in_bits += type_struct_field->type_entry->size_in_bits;
+
}
+ struct_type->data.structure.embedded_in_current = false;
- normalize_parent_ptrs(node);
- c->root->data.root.top_level_decls.append(node);
+ struct_type->data.structure.gen_field_count = field_count;
+ struct_type->data.structure.complete = true;
- // make an alias without the "struct_" prefix. this will get emitted at the
- // end if it doesn't conflict with anything else
- add_alias(c, buf_ptr(bare_name), buf_ptr(full_type_name));
+ LLVMStructSetBody(struct_type->type_ref, element_types, field_count, false);
+
+ struct_type->align_in_bits = first_field_align_in_bits;
+ struct_type->size_in_bits = total_size_in_bits;
+
+ LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(c->codegen->dbuilder,
+ LLVMZigFileToScope(c->import->di_file),
+ buf_ptr(full_type_name),
+ c->import->di_file, line + 1, struct_type->size_in_bits, struct_type->align_in_bits, 0,
+ nullptr, di_element_types, field_count, 0, nullptr, "");
+
+ LLVMZigReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type);
+ struct_type->di_type = replacement_di_type;
+
+ //////
+
+ // now create a top level decl node for the type
+ AstNode *struct_node = create_node(c, NodeTypeStructDecl);
+ buf_init_from_buf(&struct_node->data.struct_decl.name, full_type_name);
+ struct_node->data.struct_decl.kind = ContainerKindStruct;
+ struct_node->data.struct_decl.visib_mod = VisibModExport;
+ struct_node->data.struct_decl.directives = create_empty_directives(c);
+ struct_node->data.struct_decl.type_entry = struct_type;
+
+ for (uint32_t i = 0; i < field_count; i += 1) {
+ TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
+ AstNode *type_node = make_type_node(c, type_struct_field->type_entry);
+ AstNode *field_node = create_struct_field_node(c, buf_ptr(type_struct_field->name), type_node);
+ struct_node->data.struct_decl.fields.append(field_node);
+ }
+
+ normalize_parent_ptrs(struct_node);
+ c->root->data.root.top_level_decls.append(struct_node);
}
static void visit_var_decl(Context *c, const VarDecl *var_decl) {
@@ -754,8 +906,8 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
}
QualType qt = var_decl->getType();
- AstNode *type_node = make_qual_type_node(c, qt, var_decl);
- if (!type_node) {
+ TypeTableEntry *var_type = resolve_qual_type(c, qt, var_decl);
+ if (var_type->id == TypeTableEntryIdInvalid) {
emit_warning(c, var_decl, "ignoring variable '%s' - unresolved type\n", buf_ptr(name));
return;
}
@@ -778,7 +930,8 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
switch (ap_value->getKind()) {
case APValue::Int:
{
- if (!type_is_int(type_node)) {
+ TypeTableEntry *canon_type = get_underlying_type(var_type);
+ if (canon_type->id != TypeTableEntryIdInt) {
emit_warning(c, var_decl,
"ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name));
return;
@@ -819,17 +972,19 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) {
return;
}
+ AstNode *type_node = make_type_node(c, var_type);
AstNode *var_node = create_typed_var_decl_node(c, true, buf_ptr(name), type_node, init_node);
c->root->data.root.top_level_decls.append(var_node);
- c->root_name_table.put(name, true);
+ c->global_value_table.put(name, var_type);
return;
}
if (is_extern) {
+ AstNode *type_node = make_type_node(c, var_type);
AstNode *var_node = create_typed_var_decl_node(c, is_const, buf_ptr(name), type_node, nullptr);
var_node->data.variable_declaration.is_extern = true;
c->root->data.root.top_level_decls.append(var_node);
- c->root_name_table.put(name, true);
+ c->global_value_table.put(name, var_type);
return;
}
@@ -864,7 +1019,10 @@ static bool decl_visitor(void *context, const Decl *decl) {
}
static bool name_exists(Context *c, Buf *name) {
- if (c->root_name_table.maybe_get(name)) {
+ if (c->global_type_table.maybe_get(name)) {
+ return true;
+ }
+ if (c->global_value_table.maybe_get(name)) {
return true;
}
if (c->fn_table.maybe_get(name)) {
@@ -1001,6 +1159,11 @@ static void process_macro(Context *c, Buf *name, Buf *value) {
// maybe it's a symbol
if (is_simple_symbol(value)) {
+ // if it equals itself, ignore. for example, from stdio.h:
+ // #define stdin stdin
+ if (buf_eql_buf(name, value)) {
+ return;
+ }
c->macro_symbols.append({name, value});
}
}
@@ -1054,46 +1217,43 @@ static void process_preprocessor_entities(Context *c, ASTUnit &unit) {
}
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,
- uint32_t *next_node_index)
+ CodeGen *codegen, AstNode *source_node)
{
int err;
Buf tmp_file_path = BUF_INIT;
if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) {
return err;
}
- ZigList<const char *> clang_argv = {0};
- clang_argv.append(buf_ptr(&tmp_file_path));
-
- clang_argv.append("-isystem");
- clang_argv.append(libc_include_path);
-
- for (int i = 0; i < args_len; i += 1) {
- clang_argv.append(args[i]);
- }
- err = parse_h_file(import, errors, &clang_argv, warnings_on, next_node_index);
+ err = parse_h_file(import, errors, buf_ptr(&tmp_file_path), codegen, source_node);
os_delete_file(&tmp_file_path);
return err;
}
-int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors,
- ZigList<const char *> *clang_argv, bool warnings_on, uint32_t *next_node_index)
+int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,
+ CodeGen *codegen, AstNode *source_node)
{
Context context = {0};
Context *c = &context;
- c->warnings_on = warnings_on;
+ c->warnings_on = codegen->verbose;
c->import = import;
c->errors = errors;
c->visib_mod = VisibModPub;
- c->root_name_table.init(8);
+ c->global_type_table.init(8);
+ c->global_value_table.init(8);
c->enum_type_table.init(8);
c->struct_type_table.init(8);
c->fn_table.init(8);
c->macro_table.init(8);
- c->next_node_index = next_node_index;
+ c->codegen = codegen;
+ c->source_node = source_node;
+
+ ZigList<const char *> clang_argv = {0};
+
+ clang_argv.append("-x");
+ clang_argv.append("c");
char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS");
if (ZIG_PARSEH_CFLAGS) {
@@ -1103,28 +1263,37 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors,
while (space) {
if (space - start > 0) {
buf_init_from_mem(&tmp_buf, start, space - start);
- clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf)));
+ clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf)));
}
start = space + 1;
space = strstr(start, " ");
}
buf_init_from_str(&tmp_buf, start);
- clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf)));
+ clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf)));
}
- clang_argv->append("-isystem");
- clang_argv->append(ZIG_HEADERS_DIR);
+ clang_argv.append("-isystem");
+ clang_argv.append(ZIG_HEADERS_DIR);
+
+ clang_argv.append("-isystem");
+ clang_argv.append(buf_ptr(codegen->libc_include_path));
+
+ for (int i = 0; i < codegen->clang_argv_len; i += 1) {
+ clang_argv.append(codegen->clang_argv[i]);
+ }
// we don't need spell checking and it slows things down
- clang_argv->append("-fno-spell-checking");
+ clang_argv.append("-fno-spell-checking");
// this gives us access to preprocessing entities, presumably at
// the cost of performance
- clang_argv->append("-Xclang");
- clang_argv->append("-detailed-preprocessing-record");
+ clang_argv.append("-Xclang");
+ clang_argv.append("-detailed-preprocessing-record");
+
+ clang_argv.append(target_file);
- // to make the end argument work
- clang_argv->append(nullptr);
+ // to make the [start...end] argument work
+ clang_argv.append(nullptr);
IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
@@ -1138,7 +1307,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors,
const char *resources_path = ZIG_HEADERS_DIR;
std::unique_ptr<ASTUnit> err_unit;
std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine(
- &clang_argv->at(0), &clang_argv->last(),
+ &clang_argv.at(0), &clang_argv.last(),
pch_container_ops, diags, resources_path,
only_local_decls, capture_diagnostics, None, true, false, TU_Complete,
false, false, allow_pch_with_compiler_errors, skip_function_bodies,
src/parseh.hpp
@@ -11,10 +11,10 @@
#include "all_types.hpp"
-int parse_h_file(ImportTableEntry *out_import, ZigList<ErrorMsg *> *out_errs,
- ZigList<const char *> *clang_argv, bool warnings_on, uint32_t *next_node_index);
-int parse_h_buf(ImportTableEntry *out_import, ZigList<ErrorMsg *> *out_errs,
- Buf *source, const char **args, int args_len, const char *libc_include_path,
- bool warnings_on, uint32_t *next_node_index);
+int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,
+ CodeGen *codegen, AstNode *source_node);
+
+int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source,
+ CodeGen *codegen, AstNode *source_node);
#endif
src/parser.cpp
@@ -908,7 +908,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
/*
PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
-KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"
+KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
*/
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -954,6 +954,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token);
*token_index += 1;
return node;
+ } else if (token->id == TokenIdKeywordType) {
+ AstNode *node = ast_create_node(pc, NodeTypeTypeLiteral, token);
+ *token_index += 1;
+ return node;
} else if (token->id == TokenIdKeywordError) {
AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
*token_index += 1;
@@ -2470,7 +2474,34 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index,
}
/*
-TopLevelDecl : many(Directive) option(FnVisibleMod) (FnDef | ExternFnProto | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl | CImportDecl)
+TypeDecl = "type" "Symbol" "=" TypeExpr ";"
+*/
+static AstNode *ast_parse_type_decl(ParseContext *pc, int *token_index,
+ ZigList<AstNode*> *directives, VisibMod visib_mod)
+{
+ Token *first_token = &pc->tokens->at(*token_index);
+
+ if (first_token->id != TokenIdKeywordType) {
+ return nullptr;
+ }
+ *token_index += 1;
+
+ Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
+ ast_eat_token(pc, token_index, TokenIdEq);
+
+ AstNode *node = ast_create_node(pc, NodeTypeTypeDecl, first_token);
+ ast_buf_from_token(pc, name_tok, &node->data.type_decl.symbol);
+ node->data.type_decl.child_type = ast_parse_prefix_op_expr(pc, token_index, true);
+
+ node->data.type_decl.visib_mod = visib_mod;
+ node->data.type_decl.directives = directives;
+
+ normalize_parent_ptrs(node);
+ return node;
+}
+
+/*
+TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl)
*/
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) {
@@ -2545,6 +2576,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
continue;
}
+ AstNode *type_decl_node = ast_parse_type_decl(pc, token_index, directives, visib_mod);
+ if (type_decl_node) {
+ top_level_decls->append(type_decl_node);
+ continue;
+ }
+
if (directives->length > 0) {
ast_error(pc, directive_token, "invalid directive");
}
@@ -2631,9 +2668,16 @@ void normalize_parent_ptrs(AstNode *node) {
set_field(&node->data.return_expr.expr);
break;
case NodeTypeVariableDeclaration:
+ if (node->data.variable_declaration.directives) {
+ set_list_fields(node->data.variable_declaration.directives);
+ }
set_field(&node->data.variable_declaration.type);
set_field(&node->data.variable_declaration.expr);
break;
+ case NodeTypeTypeDecl:
+ set_list_fields(node->data.type_decl.directives);
+ set_field(&node->data.type_decl.child_type);
+ break;
case NodeTypeErrorValueDecl:
// none
break;
@@ -2772,5 +2816,8 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeErrorType:
// none
break;
+ case NodeTypeTypeLiteral:
+ // none
+ break;
}
}
src/tokenizer.cpp
@@ -101,7 +101,7 @@ 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"
+ "null", "noalias", "switch", "undefined", "error", "type"
};
bool is_zig_keyword(Buf *buf) {
@@ -271,6 +271,8 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordUndefined;
} else if (mem_eql_str(token_mem, token_len, "error")) {
t->cur_tok->id = TokenIdKeywordError;
+ } else if (mem_eql_str(token_mem, token_len, "type")) {
+ t->cur_tok->id = TokenIdKeywordType;
}
t->cur_tok = nullptr;
@@ -1084,6 +1086,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordSwitch: return "switch";
case TokenIdKeywordUndefined: return "undefined";
case TokenIdKeywordError: return "error";
+ case TokenIdKeywordType: return "type";
case TokenIdLParen: return "(";
case TokenIdRParen: return ")";
case TokenIdComma: return ",";
src/tokenizer.hpp
@@ -40,6 +40,7 @@ enum TokenId {
TokenIdKeywordSwitch,
TokenIdKeywordUndefined,
TokenIdKeywordError,
+ TokenIdKeywordType,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,
test/run_tests.cpp
@@ -115,7 +115,7 @@ static TestCase *add_parseh_case(const char *case_name, const char *source, int
test_case->compiler_args.append("parseh");
test_case->compiler_args.append(tmp_h_path);
- test_case->compiler_args.append("--c-import-warnings");
+ test_case->compiler_args.append("--verbose");
test_cases.append(test_case);
@@ -1689,7 +1689,7 @@ var a : i32 = 2;
add_compile_fail_case("byvalue struct on exported functions", R"SOURCE(
struct A { x : i32, }
export fn f(a : A) {}
- )SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue struct parameters not yet supported on exported functions");
+ )SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue struct parameters not yet supported on extern functions");
add_compile_fail_case("duplicate field in struct value expression", R"SOURCE(
struct A {
@@ -1929,7 +1929,7 @@ pub const Foo1 = enum_Foo._1;)OUTPUT",
add_parseh_case("restrict -> noalias", R"SOURCE(
void foo(void *restrict bar, void *restrict);
- )SOURCE", 1, R"OUTPUT(pub const c_void = u8;
+ )SOURCE", 1, R"OUTPUT(pub type c_void = u8;
pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);)OUTPUT");
add_parseh_case("simple struct", R"SOURCE(
@@ -1977,14 +1977,14 @@ struct Foo {
void (*derp)(struct Foo *foo);
};
)SOURCE", 2, R"OUTPUT(export struct struct_Foo {
- derp: ?extern fn (?&struct_Foo),
+ derp: ?extern fn(?&struct_Foo),
})OUTPUT", R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
add_parseh_case("struct prototype used in func", R"SOURCE(
struct Foo;
struct Foo *some_func(struct Foo *foo, int x);
- )SOURCE", 2, R"OUTPUT(pub const struct_Foo = u8;
+ )SOURCE", 2, R"OUTPUT(pub type struct_Foo = u8;
pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;)OUTPUT",
R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");