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:
parent
436e35516a
commit
3c2093fec6
@ -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
|
||||||
|
@ -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
|
||||||
|
557
src/analyze.cpp
557
src/analyze.cpp
@ -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(¶m_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(¶m_decl->name) == 0) {
|
if (buf_len(¶m_decl->name) == 0) {
|
||||||
@ -4382,16 +4528,15 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
|
|||||||
var->src_arg_index = i;
|
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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
297
src/main.cpp
297
src/main.cpp
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
701
src/parseh.cpp
701
src/parseh.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 ",";
|
||||||
|
@ -40,6 +40,7 @@ enum TokenId {
|
|||||||
TokenIdKeywordSwitch,
|
TokenIdKeywordSwitch,
|
||||||
TokenIdKeywordUndefined,
|
TokenIdKeywordUndefined,
|
||||||
TokenIdKeywordError,
|
TokenIdKeywordError,
|
||||||
|
TokenIdKeywordType,
|
||||||
TokenIdLParen,
|
TokenIdLParen,
|
||||||
TokenIdRParen,
|
TokenIdRParen,
|
||||||
TokenIdComma,
|
TokenIdComma,
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user