parseh understands types better and handles some situations better

See #88

Also, includes partial implementation of typedef top level declaration.
See #95

Also, fix function types. Previously the way we were deduping function type
pointers was incorrect.
This commit is contained in:
Andrew Kelley 2016-01-31 01:20:47 -07:00
parent 436e35516a
commit 3c2093fec6
14 changed files with 1204 additions and 684 deletions

View File

@ -5,15 +5,17 @@
``` ```
Root = many(TopLevelDecl) "EOF" 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 CImportDecl = "c_import" Block
TypeDecl = "type" "Symbol" "=" TypeExpr ";"
ErrorValueDecl = "error" "Symbol" ";" ErrorValueDecl = "error" "Symbol" ";"
GlobalVarDecl = VariableDeclaration ";" GlobalVarDecl = VariableDeclaration ";"
VariableDeclaration = ("var" | "const") "Symbol" option(":" PrefixOpExpression) "=" Expression VariableDeclaration = ("var" | "const") "Symbol" option(":" TypeExpr) "=" Expression
ContainerDecl = ("struct" | "enum") "Symbol" "{" many(StructMember) "}" ContainerDecl = ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
@ -27,7 +29,7 @@ RootExportDecl = "export" "Symbol" "String" ";"
ExternDecl = "extern" (FnProto | VariableDeclaration) ";" ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
FnProto = "fn" option("Symbol") ParamDeclList option("->" PrefixOpExpression) FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
Directive = "#" "Symbol" "(" "String" ")" Directive = "#" "Symbol" "(" "String" ")"
@ -37,7 +39,7 @@ FnDef = FnProto Block
ParamDeclList = "(" list(ParamDecl, ",") ")" ParamDeclList = "(" list(ParamDecl, ",") ")"
ParamDecl = option("noalias") option("Symbol" ":") PrefixOpExpression | "..." ParamDecl = option("noalias") option("Symbol" ":") TypeExpr | "..."
Block = "{" list(option(Statement), ";") "}" Block = "{" list(option(Statement), ";") "}"
@ -47,6 +49,8 @@ Label = "Symbol" ":"
Expression = BlockExpression | NonBlockExpression Expression = BlockExpression | NonBlockExpression
TypeExpr = PrefixOpExpression
NonBlockExpression = ReturnExpression | AssignmentExpression NonBlockExpression = ReturnExpression | AssignmentExpression
AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")" AsmExpression = "asm" option("volatile") "(" "String" option(AsmOutput) ")"
@ -55,7 +59,7 @@ AsmOutput = ":" list(AsmOutputItem, ",") option(AsmInput)
AsmInput = ":" list(AsmInputItem, ",") option(AsmClobbers) AsmInput = ":" list(AsmInputItem, ",") option(AsmClobbers)
AsmOutputItem = "[" "Symbol" "]" "String" "(" ("Symbol" | "->" PrefixOpExpression) ")" AsmOutputItem = "[" "Symbol" "]" "String" "(" ("Symbol" | "->" TypeExpr) ")"
AsmInputItem = "[" "Symbol" "]" "String" "(" Expression ")" AsmInputItem = "[" "Symbol" "]" "String" "(" Expression ")"
@ -91,7 +95,7 @@ IfExpression = IfVarExpression | IfBoolExpression
IfBoolExpression = "if" "(" Expression ")" Expression option(Else) 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 Else = "else" Expression
@ -117,7 +121,7 @@ AdditionOperator = "+" | "-" | "++"
MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression
CurlySuffixExpression = PrefixOpExpression option(ContainerInitExpression) CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
MultiplyOperator = "*" | "/" | "%" 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") 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" GotoExpression = "goto" "Symbol"
GroupedExpression = "(" Expression ")" GroupedExpression = "(" Expression ")"
KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | "type"
``` ```
## Operator Precedence ## Operator Precedence

View File

@ -124,6 +124,7 @@ enum NodeType {
NodeTypeDirective, NodeTypeDirective,
NodeTypeReturnExpr, NodeTypeReturnExpr,
NodeTypeVariableDeclaration, NodeTypeVariableDeclaration,
NodeTypeTypeDecl,
NodeTypeErrorValueDecl, NodeTypeErrorValueDecl,
NodeTypeBinOpExpr, NodeTypeBinOpExpr,
NodeTypeUnwrapErrorExpr, NodeTypeUnwrapErrorExpr,
@ -159,6 +160,7 @@ enum NodeType {
NodeTypeStructValueField, NodeTypeStructValueField,
NodeTypeArrayType, NodeTypeArrayType,
NodeTypeErrorType, NodeTypeErrorType,
NodeTypeTypeLiteral,
}; };
struct AstNodeRoot { struct AstNodeRoot {
@ -212,9 +214,6 @@ struct AstNodeParamDecl {
// populated by semantic analyzer // populated by semantic analyzer
VariableTableEntry *variable; VariableTableEntry *variable;
bool is_byval;
int src_index;
int gen_index;
}; };
struct AstNodeBlock { struct AstNodeBlock {
@ -256,6 +255,19 @@ struct AstNodeVariableDeclaration {
VariableTableEntry *variable; 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 { struct AstNodeErrorValueDecl {
Buf name; Buf name;
VisibMod visib_mod; VisibMod visib_mod;
@ -684,6 +696,11 @@ struct AstNodeErrorType {
Expr resolved_expr; Expr resolved_expr;
}; };
struct AstNodeTypeLiteral {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNode { struct AstNode {
enum NodeType type; enum NodeType type;
int line; int line;
@ -704,6 +721,7 @@ struct AstNode {
AstNodeBlock block; AstNodeBlock block;
AstNodeReturnExpr return_expr; AstNodeReturnExpr return_expr;
AstNodeVariableDeclaration variable_declaration; AstNodeVariableDeclaration variable_declaration;
AstNodeTypeDecl type_decl;
AstNodeErrorValueDecl error_value_decl; AstNodeErrorValueDecl error_value_decl;
AstNodeBinOpExpr bin_op_expr; AstNodeBinOpExpr bin_op_expr;
AstNodeUnwrapErrorExpr unwrap_err_expr; AstNodeUnwrapErrorExpr unwrap_err_expr;
@ -740,6 +758,7 @@ struct AstNode {
AstNodeContinueExpr continue_expr; AstNodeContinueExpr continue_expr;
AstNodeArrayType array_type; AstNodeArrayType array_type;
AstNodeErrorType error_type; AstNodeErrorType error_type;
AstNodeTypeLiteral type_literal;
} data; } data;
}; };
@ -755,6 +774,24 @@ struct AsmToken {
int end; 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 { struct TypeTableEntryPointer {
TypeTableEntry *child_type; TypeTableEntry *child_type;
bool is_const; bool is_const;
@ -820,17 +857,25 @@ struct TypeTableEntryEnum {
bool complete; bool complete;
}; };
struct FnGenParamInfo {
int src_index;
int gen_index;
bool is_byval;
};
struct TypeTableEntryFn { struct TypeTableEntryFn {
TypeTableEntry *src_return_type; FnTypeId fn_type_id;
TypeTableEntry *gen_return_type; TypeTableEntry *gen_return_type;
TypeTableEntry **param_types;
int src_param_count;
LLVMTypeRef raw_type_ref;
bool is_var_args;
int gen_param_count; int gen_param_count;
FnGenParamInfo *gen_param_info;
LLVMTypeRef raw_type_ref;
LLVMCallConv calling_convention; LLVMCallConv calling_convention;
bool is_extern; };
bool is_naked;
struct TypeTableEntryTypeDecl {
TypeTableEntry *child_type;
TypeTableEntry *canonical_type;
}; };
enum TypeTableEntryId { enum TypeTableEntryId {
@ -852,6 +897,7 @@ enum TypeTableEntryId {
TypeTableEntryIdPureError, TypeTableEntryIdPureError,
TypeTableEntryIdEnum, TypeTableEntryIdEnum,
TypeTableEntryIdFn, TypeTableEntryIdFn,
TypeTableEntryIdTypeDecl,
}; };
struct TypeTableEntry { struct TypeTableEntry {
@ -873,6 +919,7 @@ struct TypeTableEntry {
TypeTableEntryError error; TypeTableEntryError error;
TypeTableEntryEnum enumeration; TypeTableEntryEnum enumeration;
TypeTableEntryFn fn; TypeTableEntryFn fn;
TypeTableEntryTypeDecl type_decl;
} data; } data;
// use these fields to make sure we don't duplicate type table entries for the same type // 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 // reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> fn_type_table;
}; };
struct LabelTableEntry { struct LabelTableEntry {
@ -969,12 +1015,14 @@ struct CodeGen {
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table; HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_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<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; uint32_t next_unresolved_index;
struct { struct {
TypeTableEntry *entry_bool; TypeTableEntry *entry_bool;
TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64] TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
TypeTableEntry *entry_c_int[8];
TypeTableEntry *entry_u8; TypeTableEntry *entry_u8;
TypeTableEntry *entry_u16; TypeTableEntry *entry_u16;
TypeTableEntry *entry_u32; TypeTableEntry *entry_u32;
@ -1082,12 +1130,16 @@ struct BlockContext {
Buf *c_import_buf; Buf *c_import_buf;
}; };
struct ParseH { enum CIntType {
ZigList<ErrorMsg*> errors; CIntTypeShort,
ZigList<AstNode *> fn_list; CIntTypeUShort,
ZigList<AstNode *> struct_list; CIntTypeInt,
ZigList<AstNode *> var_list; CIntTypeUInt,
ZigList<AstNode *> incomplete_struct_list; CIntTypeLong,
CIntTypeULong,
CIntTypeLongLong,
CIntTypeULongLong,
}; };
#endif #endif

View File

@ -56,6 +56,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
case NodeTypeTypeDecl:
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
case NodeTypeStringLiteral: case NodeTypeStringLiteral:
@ -83,6 +84,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeSwitchProng: case NodeTypeSwitchProng:
case NodeTypeArrayType: case NodeTypeArrayType:
case NodeTypeErrorType: case NodeTypeErrorType:
case NodeTypeTypeLiteral:
case NodeTypeContainerInitExpr: case NodeTypeContainerInitExpr:
return node; return node;
} }
@ -123,6 +125,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError: case TypeTableEntryIdPureError:
case TypeTableEntryIdUndefLit: case TypeTableEntryIdUndefLit:
case TypeTableEntryIdTypeDecl:
// nothing to init // nothing to init
break; break;
case TypeTableEntryIdStruct: 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)); 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_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name)); 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; bool zero_bits;
if (child_type->size_in_bits == 0) { if (canon_child_type->size_in_bits == 0) {
if (child_type->id == TypeTableEntryIdStruct) { if (canon_child_type->id == TypeTableEntryIdStruct) {
zero_bits = child_type->data.structure.complete; zero_bits = canon_child_type->data.structure.complete;
} else if (child_type->id == TypeTableEntryIdEnum) { } else if (canon_child_type->id == TypeTableEntryIdEnum) {
zero_bits = child_type->data.enumeration.complete; zero_bits = canon_child_type->data.enumeration.complete;
} else { } else {
zero_bits = true; 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) { if (child_type->maybe_parent) {
TypeTableEntry *entry = child_type->maybe_parent; TypeTableEntry *entry = child_type->maybe_parent;
return entry; 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); auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
if (existing_entry) { if (existing_entry) {
TypeTableEntry *entry = existing_entry->value; TypeTableEntry *entry = existing_entry->value;
@ -417,6 +422,177 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c
} }
} }
TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdTypeDecl);
buf_init_from_str(&entry->name, name);
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;
entry->data.type_decl.child_type = child_type;
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;
}
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.fn_type_id = fn_type_id;
fn_type->data.fn.calling_convention = fn_type_id.is_extern ? LLVMCCallConv : LLVMFastCallConv;
fn_type->size_in_bits = g->pointer_size_bytes * 8;
fn_type->align_in_bits = g->pointer_size_bytes * 8;
// populate the name of the type
buf_resize(&fn_type->name, 0);
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 < 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) ? "" : ", ";
const char *noalias_str = param_info->is_noalias ? "noalias " : "";
buf_appendf(&fn_type->name, "%s%s%s", comma, noalias_str, buf_ptr(&param_type->name));
}
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 (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 = 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 + 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 + 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, 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 (fn_type_id.return_type->size_in_bits == 0) {
gen_return_type = g->builtin_types.entry_void;
} else {
gen_return_type = fn_type_id.return_type;
}
fn_type->data.fn.gen_return_type = gen_return_type;
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];
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);
gen_param_info->is_byval = true;
} else {
gen_type = type_entry;
}
gen_param_types[gen_param_index] = gen_type->type_ref;
gen_param_info->gen_index = gen_param_index;
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;
}
}
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 // 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. // and returns invalid type. Otherwise, returns the type of the constant expression value.
// Must be called after analyze_expression on the same node. // Must be called after analyze_expression on the same node.
@ -463,129 +639,64 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); FnTypeId fn_type_id;
fn_type->data.fn.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport); fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
fn_type->data.fn.is_naked = is_naked; fn_type_id.is_naked = is_naked;
fn_type->data.fn.calling_convention = fn_proto->is_extern ? LLVMCCallConv : LLVMFastCallConv; 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);
int src_param_count = node->data.fn_proto.params.length; if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) {
fn_type->size_in_bits = g->pointer_size_bytes * 8; fn_proto->skip = true;
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 for (int i = 0; i < fn_type_id.param_count; i += 1) {
// source code in order for error messages to be in the best order.
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 " : "";
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); AstNode *child = node->data.fn_proto.params.at(i);
assert(child->type == NodeTypeParamDecl); assert(child->type == NodeTypeParamDecl);
TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context, TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
child->data.param_decl.type); child->data.param_decl.type);
fn_type->data.fn.param_types[i] = type_entry; switch (type_entry->id) {
case TypeTableEntryIdInvalid:
const char *comma = (i == 0) ? "" : ", "; fn_proto->skip = true;
buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->name)); break;
} case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context, case TypeTableEntryIdUndefLit:
node->data.fn_proto.return_type); case TypeTableEntryIdMetaType:
fn_type->data.fn.src_return_type = return_type; case TypeTableEntryIdUnreachable:
if (return_type->id == TypeTableEntryIdInvalid) { fn_proto->skip = true;
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)));
fn_type->data.fn.is_var_args = fn_proto->is_var_args; break;
if (fn_proto->is_var_args) { case TypeTableEntryIdVoid:
const char *comma = (src_param_count == 0) ? "" : ", "; case TypeTableEntryIdBool:
buf_appendf(&fn_type->name, "%s...", comma); case TypeTableEntryIdInt:
} case TypeTableEntryIdFloat:
buf_appendf(&fn_type->name, ")"); case TypeTableEntryIdPointer:
if (return_type->id != TypeTableEntryIdVoid) { case TypeTableEntryIdArray:
buf_appendf(&fn_type->name, " -> %s", buf_ptr(&return_type->name)); case TypeTableEntryIdStruct:
} case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
// next, loop over the parameters again and compute debug information case TypeTableEntryIdEnum:
// and codegen information case TypeTableEntryIdFn:
bool first_arg_return = !fn_proto->skip && handle_is_ptr(return_type); case TypeTableEntryIdTypeDecl:
// +1 for maybe making the first argument the return value break;
LLVMTypeRef *gen_param_types = allocate<LLVMTypeRef>(1 + src_param_count); }
// +1 because 0 is the return type and +1 for maybe making first arg ret val if (type_entry->id == TypeTableEntryIdInvalid) {
LLVMZigDIType **param_di_types = allocate<LLVMZigDIType*>(2 + src_param_count);
param_di_types[0] = 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);
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) {
gen_return_type = g->builtin_types.entry_void;
} else {
gen_return_type = 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; fn_proto->skip = true;
} }
FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
child->data.param_decl.src_index = i; param_info->type = type_entry;
child->data.param_decl.gen_index = -1; param_info->is_noalias = child->data.param_decl.is_noalias;
if (!fn_proto->skip && 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;
} 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_index += 1;
// after the gen_param_index += 1 because 0 is the return type
param_di_types[gen_param_index] = gen_type->di_type;
}
} }
fn_type->data.fn.gen_param_count = gen_param_index;
if (fn_proto->skip) { if (fn_proto->skip) {
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
auto table_entry = import->fn_type_table.maybe_get(&fn_type->name); return get_fn_type(g, fn_type_id);
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);
import->fn_type_table.put(&fn_type->name, fn_type);
return fn_type;
}
} }
@ -640,14 +751,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
if (fn_table_entry->is_inline) { if (fn_table_entry->is_inline) {
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMAlwaysInlineAttribute); 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); LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNakedAttribute);
} }
LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ? LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
LLVMInternalLinkage : LLVMExternalLinkage); 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); LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
} }
LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention); 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) { 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); assert(enum_type->id == TypeTableEntryIdEnum);
AstNode *decl_node = enum_type->data.enumeration.decl_node; 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) { 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); assert(struct_type->id == TypeTableEntryIdStruct);
AstNode *decl_node = struct_type->data.structure.decl_node; 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); ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
child_import->fn_table.init(32); child_import->fn_table.init(32);
child_import->fn_type_table.init(32);
child_import->c_import_node = node; child_import->c_import_node = node;
ZigList<ErrorMsg *> errors = {0}; ZigList<ErrorMsg *> errors = {0};
int err; int err;
if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g->clang_argv, g->clang_argv_len, if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) {
buf_ptr(g->libc_include_path), false, &g->next_node_index)))
{
zig_panic("unable to parse h file: %s\n", err_str(err)); 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, VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
nullptr, node); nullptr, node);
g->global_vars.append(var); 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; break;
} }
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
@ -1224,6 +1356,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeContainerInitExpr: case NodeTypeContainerInitExpr:
case NodeTypeArrayType: case NodeTypeArrayType:
case NodeTypeErrorType: case NodeTypeErrorType:
case NodeTypeTypeLiteral:
zig_unreachable(); zig_unreachable();
} }
@ -1278,8 +1411,10 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
case TypeTableEntryIdEnum: case TypeTableEntryIdEnum:
case TypeTableEntryIdFn: case TypeTableEntryIdFn:
return true; return true;
case TypeTableEntryIdTypeDecl:
zig_unreachable();
} }
zig_unreachable();
} }
static void add_global_const_expr(CodeGen *g, Expr *expr) { 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 && if (expected_type->id == TypeTableEntryIdFn &&
actual_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; 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; return false;
} }
if (!types_match_const_cast_only(expected_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.src_return_type)) actual_type->data.fn.fn_type_id.return_type))
{ {
return false; 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; 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 // note it's reversed for parameters
if (types_match_const_cast_only(actual_type->data.fn.param_types[i], FnTypeParamInfo *actual_param_info = &actual_type->data.fn.fn_type_id.param_info[i];
expected_type->data.fn.param_types[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; return false;
} }
} }
@ -3610,6 +3750,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
case TypeTableEntryIdPureError: case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum: case TypeTableEntryIdEnum:
case TypeTableEntryIdFn: case TypeTableEntryIdFn:
case TypeTableEntryIdTypeDecl:
return resolve_expr_const_val_as_type(g, node, type_entry); 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); assert(node->type == NodeTypeFnCallExpr);
// count parameters // 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; int actual_param_count = node->data.fn_call_expr.params.length;
if (struct_type) { if (struct_type) {
actual_param_count += 1; 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) { if (actual_param_count < src_param_count) {
add_node_error(g, node, add_node_error(g, node,
buf_sprintf("expected at least %d arguments, got %d", src_param_count, actual_param_count)); 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; TypeTableEntry *expected_param_type = nullptr;
int fn_proto_i = i + (struct_type ? 1 : 0); int fn_proto_i = i + (struct_type ? 1 : 0);
if (fn_proto_i < src_param_count) { 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); 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) { if (return_type->id == TypeTableEntryIdInvalid) {
return return_type; return return_type;
@ -4304,6 +4445,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeErrorType: case NodeTypeErrorType:
return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error); return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);
break; break;
case NodeTypeTypeLiteral:
return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_type);
break;
case NodeTypeSwitchExpr: case NodeTypeSwitchExpr:
return_type = analyze_switch_expr(g, import, context, expected_type, node); return_type = analyze_switch_expr(g, import, context, expected_type, node);
break; break;
@ -4322,6 +4466,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
case NodeTypeTypeDecl:
zig_unreachable(); zig_unreachable();
} }
assert(return_type); 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; 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; 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) { for (int i = 0; i < fn_proto->params.length; i += 1) {
AstNode *param_decl_node = fn_proto->params.at(i); AstNode *param_decl_node = fn_proto->params.at(i);
assert(param_decl_node->type == NodeTypeParamDecl); 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")); 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, 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(&param_decl->name) == 0) { if (buf_len(&param_decl->name) == 0) {
@ -4382,16 +4528,15 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
var->src_arg_index = i; var->src_arg_index = i;
param_decl_node->data.param_decl.variable = var; 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); 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; 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(); auto it = fn_table_entry->label_table.entry_iterator();
for (;;) { for (;;) {
auto *entry = it.next(); auto *entry = it.next();
@ -4427,6 +4572,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
case NodeTypeFnProto: case NodeTypeFnProto:
case NodeTypeTypeDecl:
// already took care of these // already took care of these
break; break;
case NodeTypeDirective: case NodeTypeDirective:
@ -4466,6 +4612,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeContainerInitExpr: case NodeTypeContainerInitExpr:
case NodeTypeArrayType: case NodeTypeArrayType:
case NodeTypeErrorType: case NodeTypeErrorType:
case NodeTypeTypeLiteral:
zig_unreachable(); zig_unreachable();
} }
} }
@ -4485,10 +4632,14 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeContinue: case NodeTypeContinue:
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
case NodeTypeErrorType: case NodeTypeErrorType:
case NodeTypeTypeLiteral:
// no dependencies on other top level declarations // no dependencies on other top level declarations
break; break;
case NodeTypeSymbol: case NodeTypeSymbol:
{ {
if (node->data.symbol_expr.override_type_entry) {
break;
}
Buf *name = &node->data.symbol_expr.symbol; Buf *name = &node->data.symbol_expr.symbol;
auto table_entry = g->primitive_type_table.maybe_get(name); auto table_entry = g->primitive_type_table.maybe_get(name);
if (!table_entry) { if (!table_entry) {
@ -4627,6 +4778,9 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeParamDecl: case NodeTypeParamDecl:
collect_expr_decl_deps(g, import, node->data.param_decl.type, decl_node); collect_expr_decl_deps(g, import, node->data.param_decl.type, decl_node);
break; break;
case NodeTypeTypeDecl:
collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);
break;
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
case NodeTypeRootExportDecl: case NodeTypeRootExportDecl:
case NodeTypeFnDef: 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) { static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) { switch (node->type) {
case NodeTypeRoot: case NodeTypeRoot:
@ -4669,28 +4813,16 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
} }
if (table_entry) { if (table_entry) {
node->data.struct_decl.type_entry = table_entry->value; node->data.struct_decl.type_entry = table_entry->value;
add_node_error(g, node, add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
buf_sprintf("redefinition of '%s'", buf_ptr(name)));
} else { } else {
TypeTableEntryId type_id = container_to_type(node->data.struct_decl.kind); TypeTableEntry *entry;
TypeTableEntry *entry = new_type_table_entry(type_id); if (node->data.struct_decl.type_entry) {
switch (node->data.struct_decl.kind) { entry = node->data.struct_decl.type_entry;
case ContainerKindStruct: } else {
entry->data.structure.decl_node = node; entry = get_partial_container_type(g, import,
break; node->data.struct_decl.kind, node, buf_ptr(name));
case ContainerKindEnum:
entry->data.enumeration.decl_node = node;
break;
} }
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); import->block_context->type_table.put(&entry->name, entry);
node->data.struct_decl.type_entry = 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; 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: case NodeTypeFnProto:
{ {
// if the name is missing, we immediately announce an error // 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 NodeTypeStructValueField:
case NodeTypeArrayType: case NodeTypeArrayType:
case NodeTypeErrorType: case NodeTypeErrorType:
case NodeTypeTypeLiteral:
zig_unreachable(); zig_unreachable();
} }
} }
@ -5063,6 +5213,8 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.array_type.resolved_expr; return &node->data.array_type.resolved_expr;
case NodeTypeErrorType: case NodeTypeErrorType:
return &node->data.error_type.resolved_expr; return &node->data.error_type.resolved_expr;
case NodeTypeTypeLiteral:
return &node->data.type_literal.resolved_expr;
case NodeTypeSwitchExpr: case NodeTypeSwitchExpr:
return &node->data.switch_expr.resolved_expr; return &node->data.switch_expr.resolved_expr;
case NodeTypeFnProto: case NodeTypeFnProto:
@ -5081,6 +5233,7 @@ Expr *get_resolved_expr(AstNode *node) {
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
case NodeTypeTypeDecl:
zig_unreachable(); zig_unreachable();
} }
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; return &node->data.error_value_decl.top_level_decl;
case NodeTypeCImport: case NodeTypeCImport:
return &node->data.c_import.top_level_decl; return &node->data.c_import.top_level_decl;
case NodeTypeTypeDecl:
return &node->data.type_decl.top_level_decl;
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
@ -5138,6 +5293,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeArrayType: case NodeTypeArrayType:
case NodeTypeErrorType: case NodeTypeErrorType:
case NodeTypeTypeLiteral:
zig_unreachable(); zig_unreachable();
} }
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); 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) { bool handle_is_ptr(TypeTableEntry *type_entry) {
switch (type_entry->id) { switch (type_entry->id) {
case TypeTableEntryIdInvalid: case TypeTableEntryIdInvalid:
@ -5204,6 +5368,8 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
return type_entry->data.enumeration.gen_field_count != 0; return type_entry->data.enumeration.gen_field_count != 0;
case TypeTableEntryIdMaybe: case TypeTableEntryIdMaybe:
return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer; return type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer;
case TypeTableEntryIdTypeDecl:
return handle_is_ptr(type_entry->data.type_decl.canonical_type);
} }
zig_unreachable(); 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;
}

View File

@ -22,7 +22,18 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
bool is_node_void_expr(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_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_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); bool handle_is_ptr(TypeTableEntry *type_entry);
void find_libc_path(CodeGen *g); void find_libc_path(CodeGen *g);
TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry);
#endif #endif

View File

@ -119,6 +119,8 @@ static const char *node_type_str(NodeType node_type) {
return "ReturnExpr"; return "ReturnExpr";
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
return "VariableDeclaration"; return "VariableDeclaration";
case NodeTypeTypeDecl:
return "TypeDecl";
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
return "ErrorValueDecl"; return "ErrorValueDecl";
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
@ -179,6 +181,8 @@ static const char *node_type_str(NodeType node_type) {
return "ArrayType"; return "ArrayType";
case NodeTypeErrorType: case NodeTypeErrorType:
return "ErrorType"; 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); ast_print(f, node->data.variable_declaration.expr, indent + 2);
break; 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: case NodeTypeErrorValueDecl:
{ {
Buf *name_buf = &node->data.error_value_decl.name; Buf *name_buf = &node->data.error_value_decl.name;
@ -478,6 +489,9 @@ void ast_print(FILE *f, AstNode *node, int indent) {
case NodeTypeErrorType: case NodeTypeErrorType:
fprintf(f, "%s\n", node_type_str(node->type)); fprintf(f, "%s\n", node_type_str(node->type));
break; 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) { 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) { static bool is_printable(uint8_t c) {
@ -515,6 +536,7 @@ static void render_node(AstRender *ar, AstNode *node) {
if (child->type == NodeTypeImport || if (child->type == NodeTypeImport ||
child->type == NodeTypeVariableDeclaration || child->type == NodeTypeVariableDeclaration ||
child->type == NodeTypeTypeDecl ||
child->type == NodeTypeErrorValueDecl || child->type == NodeTypeErrorValueDecl ||
child->type == NodeTypeFnProto) child->type == NodeTypeFnProto)
{ {
@ -588,6 +610,14 @@ static void render_node(AstRender *ar, AstNode *node) {
} }
break; 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: case NodeTypeErrorValueDecl:
zig_panic("TODO"); zig_panic("TODO");
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
@ -617,7 +647,14 @@ static void render_node(AstRender *ar, AstNode *node) {
break; break;
} }
case NodeTypeSymbol: 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; break;
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
{ {
@ -719,7 +756,11 @@ static void render_node(AstRender *ar, AstNode *node) {
break; break;
} }
case NodeTypeErrorType: case NodeTypeErrorType:
zig_panic("TODO"); fprintf(ar->f, "error");
break;
case NodeTypeTypeLiteral:
fprintf(ar->f, "type");
break;
} }
} }

View File

@ -13,11 +13,13 @@
#include "error.hpp" #include "error.hpp"
#include "analyze.hpp" #include "analyze.hpp"
#include "errmsg.hpp" #include "errmsg.hpp"
#include "parseh.hpp"
#include "ast_render.hpp" #include "ast_render.hpp"
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
CodeGen *codegen_create(Buf *root_source_dir) { CodeGen *codegen_create(Buf *root_source_dir) {
CodeGen *g = allocate<CodeGen>(1); CodeGen *g = allocate<CodeGen>(1);
g->link_table.init(32); g->link_table.init(32);
@ -25,6 +27,7 @@ CodeGen *codegen_create(Buf *root_source_dir) {
g->builtin_fn_table.init(32); g->builtin_fn_table.init(32);
g->primitive_type_table.init(32); g->primitive_type_table.init(32);
g->unresolved_top_level_decls.init(32); g->unresolved_top_level_decls.init(32);
g->fn_type_table.init(32);
g->build_type = CodeGenBuildTypeDebug; g->build_type = CodeGenBuildTypeDebug;
g->root_source_dir = root_source_dir; g->root_source_dir = root_source_dir;
g->next_error_index = 1; 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); 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; int fn_call_param_count = node->data.fn_call_expr.params.length;
bool first_arg_ret = handle_is_ptr(src_return_type); 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); 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 // don't really include void values
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); 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) { 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)) { if (handle_is_ptr(return_type)) {
assert(g->cur_ret_ptr); assert(g->cur_ret_ptr);
gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type); 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); LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
LLVMPositionBuilderAtEnd(g->builder, 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) { if (return_type->id == TypeTableEntryIdPureError) {
gen_return(g, node, err_val); gen_return(g, node, err_val);
} else if (return_type->id == TypeTableEntryIdErrorUnion) { } else if (return_type->id == TypeTableEntryIdErrorUnion) {
@ -2296,6 +2299,9 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeCharLiteral: case NodeTypeCharLiteral:
case NodeTypeNullLiteral: case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral: case NodeTypeUndefinedLiteral:
case NodeTypeErrorType:
case NodeTypeTypeLiteral:
case NodeTypeArrayType:
// caught by constant expression eval codegen // caught by constant expression eval codegen
zig_unreachable(); zig_unreachable();
case NodeTypeRoot: case NodeTypeRoot:
@ -2310,11 +2316,10 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeStructDecl: case NodeTypeStructDecl:
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeArrayType:
case NodeTypeErrorType:
case NodeTypeSwitchProng: case NodeTypeSwitchProng:
case NodeTypeSwitchRange: case NodeTypeSwitchRange:
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
case NodeTypeTypeDecl:
zig_unreachable(); zig_unreachable();
} }
zig_unreachable(); zig_unreachable();
@ -2341,6 +2346,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
} }
switch (type_entry->id) { switch (type_entry->id) {
case TypeTableEntryIdTypeDecl:
return gen_const_val(g, type_entry->data.type_decl.canonical_type, const_val);
case TypeTableEntryIdInt: case TypeTableEntryIdInt:
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
case TypeTableEntryIdPureError: case TypeTableEntryIdPureError:
@ -2557,7 +2564,9 @@ static void do_code_gen(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto); assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; 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); LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
LLVMAddAttribute(first_arg, LLVMStructRetAttribute); 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); AstNode *param_node = fn_proto->params.at(param_decl_i);
assert(param_node->type == NodeTypeParamDecl); 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) { if (gen_index < 0) {
continue; continue;
@ -2587,7 +2598,7 @@ static void do_code_gen(CodeGen *g) {
// when https://github.com/andrewrk/zig/issues/82 is fixed, add // when https://github.com/andrewrk/zig/issues/82 is fixed, add
// non null attribute here // non null attribute here
} }
if (param_node->data.param_decl.is_byval) { if (is_byval) {
LLVMAddAttribute(argument_val, LLVMByValAttribute); 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; AstNode *fn_def_node = fn_table_entry->fn_def_node;
LLVMValueRef fn = fn_table_entry->fn_value; LLVMValueRef fn = fn_table_entry->fn_value;
g->cur_fn = fn_table_entry; 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); g->cur_ret_ptr = LLVMGetParam(fn, 0);
} else { } else {
g->cur_ret_ptr = nullptr; 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); AstNode *param_decl = fn_proto->params.at(param_i);
assert(param_decl->type == NodeTypeParamDecl); 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; continue;
} }
@ -2724,17 +2737,6 @@ static const int int_sizes_in_bits[] = {
64, 64,
}; };
enum CIntType {
CIntTypeShort,
CIntTypeUShort,
CIntTypeInt,
CIntTypeUInt,
CIntTypeLong,
CIntTypeULong,
CIntTypeLongLong,
CIntTypeULongLong,
};
struct CIntTypeInfo { struct CIntTypeInfo {
CIntType id; CIntType id;
const char *name; const char *name;
@ -2840,6 +2842,8 @@ static void define_builtin_types(CodeGen *g) {
is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned()); is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
entry->data.integral.is_signed = is_signed; entry->data.integral.is_signed = is_signed;
g->primitive_type_table.put(&entry->name, entry); 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) { static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
char *dot1 = strstr(buf_ptr(buf), "."); char *dot1 = strstr(buf_ptr(buf), ".");
if (!dot1) 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->line_offsets = tokenization.line_offsets;
import_entry->path = full_path; import_entry->path = full_path;
import_entry->fn_table.init(32); 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, import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
&g->next_node_index); &g->next_node_index);

View File

@ -11,6 +11,8 @@
#include "parser.hpp" #include "parser.hpp"
#include "errmsg.hpp" #include "errmsg.hpp"
#include <stdio.h>
CodeGen *codegen_create(Buf *root_source_dir); CodeGen *codegen_create(Buf *root_source_dir);
void codegen_set_clang_argv(CodeGen *codegen, const char **args, int len); 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_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 #endif

View File

@ -10,8 +10,6 @@
#include "codegen.hpp" #include "codegen.hpp"
#include "os.hpp" #include "os.hpp"
#include "error.hpp" #include "error.hpp"
#include "parseh.hpp"
#include "ast_render.hpp"
#include <stdio.h> #include <stdio.h>
@ -38,40 +36,41 @@ static int usage(const char *arg0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
static int version(const char *arg0, int argc, char **argv) { enum Cmd {
printf("%s\n", ZIG_VERSION_STRING); CmdInvalid,
return EXIT_SUCCESS; CmdBuild,
} CmdVersion,
CmdParseH,
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;
}; };
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; 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]; char *arg = argv[i];
if (arg[0] == '-') { if (arg[0] == '-') {
if (strcmp(arg, "--release") == 0) { if (strcmp(arg, "--release") == 0) {
b.release = true; release = true;
} else if (strcmp(arg, "--strip") == 0) { } else if (strcmp(arg, "--strip") == 0) {
b.strip = true; strip = true;
} else if (strcmp(arg, "--static") == 0) { } else if (strcmp(arg, "--static") == 0) {
b.is_static = true; is_static = true;
} else if (strcmp(arg, "--verbose") == 0) { } else if (strcmp(arg, "--verbose") == 0) {
b.verbose = true; verbose = true;
} else if (i + 1 >= argc) { } else if (i + 1 >= argc) {
return usage(arg0); return usage(arg0);
} else { } else {
@ -79,190 +78,128 @@ static int build(const char *arg0, int argc, char **argv) {
if (i >= argc) { if (i >= argc) {
return usage(arg0); return usage(arg0);
} else if (strcmp(arg, "--output") == 0) { } else if (strcmp(arg, "--output") == 0) {
b.out_file = argv[i]; out_file = argv[i];
} else if (strcmp(arg, "--export") == 0) { } else if (strcmp(arg, "--export") == 0) {
if (strcmp(argv[i], "exe") == 0) { if (strcmp(argv[i], "exe") == 0) {
b.out_type = OutTypeExe; out_type = OutTypeExe;
} else if (strcmp(argv[i], "lib") == 0) { } else if (strcmp(argv[i], "lib") == 0) {
b.out_type = OutTypeLib; out_type = OutTypeLib;
} else if (strcmp(argv[i], "obj") == 0) { } else if (strcmp(argv[i], "obj") == 0) {
b.out_type = OutTypeObj; out_type = OutTypeObj;
} else { } else {
return usage(arg0); return usage(arg0);
} }
} else if (strcmp(arg, "--color") == 0) { } else if (strcmp(arg, "--color") == 0) {
if (strcmp(argv[i], "auto") == 0) { if (strcmp(argv[i], "auto") == 0) {
b.color = ErrColorAuto; color = ErrColorAuto;
} else if (strcmp(argv[i], "on") == 0) { } else if (strcmp(argv[i], "on") == 0) {
b.color = ErrColorOn; color = ErrColorOn;
} else if (strcmp(argv[i], "off") == 0) { } else if (strcmp(argv[i], "off") == 0) {
b.color = ErrColorOff; color = ErrColorOff;
} else { } else {
return usage(arg0); return usage(arg0);
} }
} else if (strcmp(arg, "--name") == 0) { } else if (strcmp(arg, "--name") == 0) {
b.out_name = argv[i]; out_name = argv[i];
} else if (strcmp(arg, "--libc-path") == 0) { } else if (strcmp(arg, "--libc-path") == 0) {
b.libc_path = argv[i]; libc_path = argv[i];
} else if (strcmp(arg, "-isystem") == 0) { } else if (strcmp(arg, "-isystem") == 0) {
b.clang_argv.append("-isystem"); clang_argv.append("-isystem");
b.clang_argv.append(argv[i]); clang_argv.append(argv[i]);
} else if (strcmp(arg, "-dirafter") == 0) { } else if (strcmp(arg, "-dirafter") == 0) {
b.clang_argv.append("-dirafter"); clang_argv.append("-dirafter");
b.clang_argv.append(argv[i]); clang_argv.append(argv[i]);
} else { } else {
return usage(arg0); return usage(arg0);
} }
} }
} else if (!b.in_file) { } else if (cmd == CmdInvalid) {
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 {
fprintf(stderr, "unrecognized argument: %s", 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);
}
return EXIT_FAILURE;
}
ast_render(stdout, import.root, 4);
return 0;
}
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) { if (strcmp(arg, "build") == 0) {
cmd = build; cmd = CmdBuild;
} else if (strcmp(arg, "version") == 0) { } else if (strcmp(arg, "version") == 0) {
cmd = version; cmd = CmdVersion;
} else if (strcmp(arg, "parseh") == 0) { } else if (strcmp(arg, "parseh") == 0) {
cmd = parseh; cmd = CmdParseH;
} else { } else {
fprintf(stderr, "Unrecognized command: %s\n", arg); fprintf(stderr, "Unrecognized command: %s\n", arg);
return usage(arg0); return usage(arg0);
} }
return cmd(arg0, argc - i - 1, &argv[i + 1]); } else {
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 usage(arg0); switch (cmd) {
case CmdBuild:
case CmdParseH:
{
if (!in_file)
return usage(arg0);
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;
}
}
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 {
zig_unreachable();
}
}
case CmdVersion:
printf("%s\n", ZIG_VERSION_STRING);
return EXIT_SUCCESS;
case CmdInvalid:
return usage(arg0);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -11,10 +11,10 @@
#include "all_types.hpp" #include "all_types.hpp"
int parse_h_file(ImportTableEntry *out_import, ZigList<ErrorMsg *> *out_errs, int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file,
ZigList<const char *> *clang_argv, bool warnings_on, uint32_t *next_node_index); CodeGen *codegen, AstNode *source_node);
int parse_h_buf(ImportTableEntry *out_import, ZigList<ErrorMsg *> *out_errs,
Buf *source, const char **args, int args_len, const char *libc_include_path, int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source,
bool warnings_on, uint32_t *next_node_index); CodeGen *codegen, AstNode *source_node);
#endif #endif

View File

@ -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") 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) { static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index); 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); AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token);
*token_index += 1; *token_index += 1;
return node; 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) { } else if (token->id == TokenIdKeywordError) {
AstNode *node = ast_create_node(pc, NodeTypeErrorType, token); AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
*token_index += 1; *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) { static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) { for (;;) {
@ -2545,6 +2576,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
continue; 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) { if (directives->length > 0) {
ast_error(pc, directive_token, "invalid directive"); ast_error(pc, directive_token, "invalid directive");
} }
@ -2631,9 +2668,16 @@ void normalize_parent_ptrs(AstNode *node) {
set_field(&node->data.return_expr.expr); set_field(&node->data.return_expr.expr);
break; break;
case NodeTypeVariableDeclaration: 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.type);
set_field(&node->data.variable_declaration.expr); set_field(&node->data.variable_declaration.expr);
break; break;
case NodeTypeTypeDecl:
set_list_fields(node->data.type_decl.directives);
set_field(&node->data.type_decl.child_type);
break;
case NodeTypeErrorValueDecl: case NodeTypeErrorValueDecl:
// none // none
break; break;
@ -2772,5 +2816,8 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeErrorType: case NodeTypeErrorType:
// none // none
break; break;
case NodeTypeTypeLiteral:
// none
break;
} }
} }

View File

@ -101,7 +101,7 @@ const char * zig_keywords[] = {
"true", "false", "null", "fn", "return", "var", "const", "extern", "true", "false", "null", "fn", "return", "var", "const", "extern",
"pub", "export", "import", "c_import", "if", "else", "goto", "asm", "pub", "export", "import", "c_import", "if", "else", "goto", "asm",
"volatile", "struct", "enum", "while", "for", "continue", "break", "volatile", "struct", "enum", "while", "for", "continue", "break",
"null", "noalias", "switch", "undefined", "error" "null", "noalias", "switch", "undefined", "error", "type"
}; };
bool is_zig_keyword(Buf *buf) { bool is_zig_keyword(Buf *buf) {
@ -271,6 +271,8 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordUndefined; t->cur_tok->id = TokenIdKeywordUndefined;
} else if (mem_eql_str(token_mem, token_len, "error")) { } else if (mem_eql_str(token_mem, token_len, "error")) {
t->cur_tok->id = TokenIdKeywordError; t->cur_tok->id = TokenIdKeywordError;
} else if (mem_eql_str(token_mem, token_len, "type")) {
t->cur_tok->id = TokenIdKeywordType;
} }
t->cur_tok = nullptr; t->cur_tok = nullptr;
@ -1084,6 +1086,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordSwitch: return "switch"; case TokenIdKeywordSwitch: return "switch";
case TokenIdKeywordUndefined: return "undefined"; case TokenIdKeywordUndefined: return "undefined";
case TokenIdKeywordError: return "error"; case TokenIdKeywordError: return "error";
case TokenIdKeywordType: return "type";
case TokenIdLParen: return "("; case TokenIdLParen: return "(";
case TokenIdRParen: return ")"; case TokenIdRParen: return ")";
case TokenIdComma: return ","; case TokenIdComma: return ",";

View File

@ -40,6 +40,7 @@ enum TokenId {
TokenIdKeywordSwitch, TokenIdKeywordSwitch,
TokenIdKeywordUndefined, TokenIdKeywordUndefined,
TokenIdKeywordError, TokenIdKeywordError,
TokenIdKeywordType,
TokenIdLParen, TokenIdLParen,
TokenIdRParen, TokenIdRParen,
TokenIdComma, TokenIdComma,

View File

@ -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("parseh");
test_case->compiler_args.append(tmp_h_path); 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); test_cases.append(test_case);
@ -1689,7 +1689,7 @@ var a : i32 = 2;
add_compile_fail_case("byvalue struct on exported functions", R"SOURCE( add_compile_fail_case("byvalue struct on exported functions", R"SOURCE(
struct A { x : i32, } struct A { x : i32, }
export fn f(a : A) {} 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( add_compile_fail_case("duplicate field in struct value expression", R"SOURCE(
struct A { struct A {
@ -1929,7 +1929,7 @@ pub const Foo1 = enum_Foo._1;)OUTPUT",
add_parseh_case("restrict -> noalias", R"SOURCE( add_parseh_case("restrict -> noalias", R"SOURCE(
void foo(void *restrict bar, void *restrict); 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"); pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);)OUTPUT");
add_parseh_case("simple struct", R"SOURCE( add_parseh_case("simple struct", R"SOURCE(
@ -1977,14 +1977,14 @@ struct Foo {
void (*derp)(struct Foo *foo); void (*derp)(struct Foo *foo);
}; };
)SOURCE", 2, R"OUTPUT(export struct struct_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"); })OUTPUT", R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
add_parseh_case("struct prototype used in func", R"SOURCE( add_parseh_case("struct prototype used in func", R"SOURCE(
struct Foo; struct Foo;
struct Foo *some_func(struct Foo *foo, int x); 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", pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;)OUTPUT",
R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT"); R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");