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"
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

View File

@ -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

View File

@ -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,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
// and returns invalid type. Otherwise, returns the type of the constant expression value.
// 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;
}
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;
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);
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);
if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) {
fn_proto->skip = true;
}
// 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.
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) {
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);
fn_type->data.fn.param_types[i] = type_entry;
const char *comma = (i == 0) ? "" : ", ";
buf_appendf(&fn_type->name, "%s%s", comma, buf_ptr(&type_entry->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) ? "" : ", ";
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));
}
// 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);
// +1 for maybe making the first argument the return value
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
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) {
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;
}
child->data.param_decl.src_index = i;
child->data.param_decl.gen_index = -1;
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;
}
FnTypeParamInfo *param_info = &fn_type_id.param_info[i];
param_info->type = type_entry;
param_info->is_noalias = child->data.param_decl.is_noalias;
}
fn_type->data.fn.gen_param_count = gen_param_index;
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);
import->fn_type_table.put(&fn_type->name, fn_type);
return fn_type;
}
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(&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;
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;
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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 {
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 {
} else if (cmd == CmdInvalid) {
if (strcmp(arg, "build") == 0) {
cmd = build;
cmd = CmdBuild;
} else if (strcmp(arg, "version") == 0) {
cmd = version;
cmd = CmdVersion;
} else if (strcmp(arg, "parseh") == 0) {
cmd = parseh;
cmd = CmdParseH;
} else {
fprintf(stderr, "Unrecognized command: %s\n", arg);
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"
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

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")
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;
}
}

View File

@ -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 ",";

View File

@ -40,6 +40,7 @@ enum TokenId {
TokenIdKeywordSwitch,
TokenIdKeywordUndefined,
TokenIdKeywordError,
TokenIdKeywordType,
TokenIdLParen,
TokenIdRParen,
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(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");