refactor out the horrible beast that was codegen_node

master
Andrew Kelley 2016-01-10 15:13:39 -07:00
parent d4b8852d78
commit 3ef2f7058b
7 changed files with 1345 additions and 1103 deletions

928
src/all_types.hpp Normal file
View File

@ -0,0 +1,928 @@
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef ZIG_ALL_TYPES_HPP
#define ZIG_ALL_TYPES_HPP
#include "list.hpp"
#include "buffer.hpp"
#include "zig_llvm.hpp"
#include "hash_map.hpp"
#include "errmsg.hpp"
struct AstNode;
struct ImportTableEntry;
struct AsmToken;
struct FnTableEntry;
struct BlockContext;
struct TypeTableEntry;
struct VariableTableEntry;
struct Cast;
struct BuiltinFnEntry;
struct LabelTableEntry;
struct TypeStructField;
struct CodeGen;
enum OutType {
OutTypeUnknown,
OutTypeExe,
OutTypeLib,
OutTypeObj,
};
enum CodeGenBuildType {
CodeGenBuildTypeDebug,
CodeGenBuildTypeRelease,
};
enum CastOp {
CastOpNothing,
CastOpPtrToInt,
CastOpIntWidenOrShorten,
CastOpToUnknownSizeArray,
CastOpMaybeWrap,
CastOpPointerReinterpret,
};
struct Cast {
CastOp op;
// if op is CastOpArrayToString, this will be a pointer to
// the string struct on the stack
LLVMValueRef ptr;
TypeTableEntry *after_type;
AstNode *source_node;
};
struct Expr {
TypeTableEntry *type_entry;
// the context in which this expression is evaluated.
// for blocks, this points to the containing scope, not the block's own scope for its children.
BlockContext *block_context;
// may be null for no cast
Cast implicit_cast; // happens first
Cast implicit_maybe_cast; // happens second
};
struct NumLitCodeGen {
TypeTableEntry *resolved_type;
};
struct StructValExprCodeGen {
TypeTableEntry *type_entry;
LLVMValueRef ptr;
AstNode *source_node;
};
struct TopLevelDecl {
// reminder: hash tables must be initialized before use
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps;
Buf *name;
ImportTableEntry *import;
// set this flag temporarily to detect infinite loops
bool in_current_deps;
};
enum NodeType {
NodeTypeRoot,
NodeTypeRootExportDecl,
NodeTypeFnProto,
NodeTypeFnDef,
NodeTypeFnDecl,
NodeTypeParamDecl,
NodeTypeType,
NodeTypeBlock,
NodeTypeExternBlock,
NodeTypeDirective,
NodeTypeReturnExpr,
NodeTypeVariableDeclaration,
NodeTypeBinOpExpr,
NodeTypeCastExpr,
NodeTypeNumberLiteral,
NodeTypeStringLiteral,
NodeTypeCharLiteral,
NodeTypeUnreachable,
NodeTypeSymbol,
NodeTypePrefixOpExpr,
NodeTypeFnCallExpr,
NodeTypeArrayAccessExpr,
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypeUse,
NodeTypeVoid,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
NodeTypeIfBoolExpr,
NodeTypeIfVarExpr,
NodeTypeWhileExpr,
NodeTypeLabel,
NodeTypeGoto,
NodeTypeBreak,
NodeTypeContinue,
NodeTypeAsmExpr,
NodeTypeStructDecl,
NodeTypeStructField,
NodeTypeStructValueExpr,
NodeTypeStructValueField,
NodeTypeEnumDecl,
NodeTypeEnumField,
NodeTypeCompilerFnExpr,
NodeTypeCompilerFnType,
};
struct AstNodeRoot {
ZigList<AstNode *> top_level_decls;
};
enum VisibMod {
VisibModPrivate,
VisibModPub,
VisibModExport,
};
struct AstNodeFnProto {
ZigList<AstNode *> *directives;
VisibMod visib_mod;
Buf name;
ZigList<AstNode *> params;
AstNode *return_type;
bool is_var_args;
// populated by semantic analyzer:
// the extern block this fn proto is inside. can be null.
AstNode *extern_node;
// the struct decl node this fn proto is inside. can be null.
AstNode *struct_node;
// the function definition this fn proto is inside. can be null.
AstNode *fn_def_node;
FnTableEntry *fn_table_entry;
bool skip;
TopLevelDecl top_level_decl;
};
struct AstNodeFnDef {
AstNode *fn_proto;
AstNode *body;
// populated by semantic analyzer
TypeTableEntry *implicit_return_type;
BlockContext *block_context;
};
struct AstNodeFnDecl {
AstNode *fn_proto;
};
struct AstNodeParamDecl {
Buf name;
AstNode *type;
// populated by semantic analyzer
VariableTableEntry *variable;
};
enum AstNodeTypeType {
AstNodeTypeTypePrimitive,
AstNodeTypeTypePointer,
AstNodeTypeTypeArray,
AstNodeTypeTypeMaybe,
AstNodeTypeTypeCompilerExpr,
};
struct AstNodeType {
AstNodeTypeType type;
Buf primitive_name;
AstNode *child_type;
AstNode *array_size; // can be null
bool is_const;
bool is_noalias;
AstNode *compiler_expr;
// populated by semantic analyzer
TypeTableEntry *entry;
};
struct AstNodeBlock {
ZigList<AstNode *> statements;
// populated by semantic analyzer
BlockContext *block_context;
Expr resolved_expr;
};
struct AstNodeReturnExpr {
// might be null in case of return void;
AstNode *expr;
// populated by semantic analyzer:
Expr resolved_expr;
};
struct AstNodeVariableDeclaration {
Buf symbol;
bool is_const;
VisibMod visib_mod;
// one or both of type and expr will be non null
AstNode *type;
AstNode *expr;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
Expr resolved_expr;
};
enum BinOpType {
BinOpTypeInvalid,
BinOpTypeAssign,
BinOpTypeAssignTimes,
BinOpTypeAssignDiv,
BinOpTypeAssignMod,
BinOpTypeAssignPlus,
BinOpTypeAssignMinus,
BinOpTypeAssignBitShiftLeft,
BinOpTypeAssignBitShiftRight,
BinOpTypeAssignBitAnd,
BinOpTypeAssignBitXor,
BinOpTypeAssignBitOr,
BinOpTypeAssignBoolAnd,
BinOpTypeAssignBoolOr,
BinOpTypeBoolOr,
BinOpTypeBoolAnd,
BinOpTypeCmpEq,
BinOpTypeCmpNotEq,
BinOpTypeCmpLessThan,
BinOpTypeCmpGreaterThan,
BinOpTypeCmpLessOrEq,
BinOpTypeCmpGreaterOrEq,
BinOpTypeBinOr,
BinOpTypeBinXor,
BinOpTypeBinAnd,
BinOpTypeBitShiftLeft,
BinOpTypeBitShiftRight,
BinOpTypeAdd,
BinOpTypeSub,
BinOpTypeMult,
BinOpTypeDiv,
BinOpTypeMod,
BinOpTypeUnwrapMaybe,
};
struct AstNodeBinOpExpr {
AstNode *op1;
BinOpType bin_op;
AstNode *op2;
// populated by semantic analyzer:
// for when op is BinOpTypeAssign
VariableTableEntry *var_entry;
Expr resolved_expr;
};
struct AstNodeFnCallExpr {
AstNode *fn_ref_expr;
ZigList<AstNode *> params;
bool is_builtin;
// populated by semantic analyzer:
BuiltinFnEntry *builtin_fn;
Expr resolved_expr;
};
struct AstNodeArrayAccessExpr {
AstNode *array_ref_expr;
AstNode *subscript;
// populated by semantic analyzer:
Expr resolved_expr;
};
struct AstNodeSliceExpr {
AstNode *array_ref_expr;
AstNode *start;
AstNode *end;
bool is_const;
// populated by semantic analyzer:
Expr resolved_expr;
StructValExprCodeGen resolved_struct_val_expr;
};
struct AstNodeFieldAccessExpr {
AstNode *struct_expr;
Buf field_name;
// populated by semantic analyzer
int field_index;
TypeStructField *type_struct_field;
Expr resolved_expr;
};
struct AstNodeExternBlock {
ZigList<AstNode *> *directives;
ZigList<AstNode *> fn_decls;
};
struct AstNodeDirective {
Buf name;
Buf param;
};
struct AstNodeRootExportDecl {
Buf type;
Buf name;
ZigList<AstNode *> *directives;
};
struct AstNodeCastExpr {
AstNode *expr;
AstNode *type;
// populated by semantic analyzer
Cast cast;
Expr resolved_expr;
};
enum PrefixOp {
PrefixOpInvalid,
PrefixOpBoolNot,
PrefixOpBinNot,
PrefixOpNegation,
PrefixOpAddressOf,
PrefixOpConstAddressOf,
PrefixOpDereference,
};
struct AstNodePrefixOpExpr {
PrefixOp prefix_op;
AstNode *primary_expr;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeUse {
Buf path;
ZigList<AstNode *> *directives;
// populated by semantic analyzer
ImportTableEntry *import;
};
struct AstNodeIfBoolExpr {
AstNode *condition;
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeIfVarExpr {
AstNodeVariableDeclaration var_decl;
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
// populated by semantic analyzer
TypeTableEntry *type;
BlockContext *block_context;
Expr resolved_expr;
};
struct AstNodeWhileExpr {
AstNode *condition;
AstNode *body;
// populated by semantic analyzer
bool condition_always_true;
bool contains_break;
Expr resolved_expr;
};
struct AstNodeLabel {
Buf name;
// populated by semantic analyzer
LabelTableEntry *label_entry;
Expr resolved_expr;
};
struct AstNodeGoto {
Buf name;
// populated by semantic analyzer
LabelTableEntry *label_entry;
Expr resolved_expr;
};
struct AsmOutput {
Buf asm_symbolic_name;
Buf constraint;
Buf variable_name;
AstNode *return_type; // null unless "=r" and return
};
struct AsmInput {
Buf asm_symbolic_name;
Buf constraint;
AstNode *expr;
};
struct SrcPos {
int line;
int column;
};
struct AstNodeAsmExpr {
bool is_volatile;
Buf asm_template;
ZigList<SrcPos> offset_map;
ZigList<AsmToken> token_list;
ZigList<AsmOutput*> output_list;
ZigList<AsmInput*> input_list;
ZigList<Buf*> clobber_list;
// populated by semantic analyzer
int return_count;
Expr resolved_expr;
};
struct AstNodeStructDecl {
Buf name;
ZigList<AstNode *> fields;
ZigList<AstNode *> fns;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
// populated by semantic analyzer
TypeTableEntry *type_entry;
TopLevelDecl top_level_decl;
};
struct AstNodeStructField {
Buf name;
AstNode *type;
ZigList<AstNode *> *directives;
};
struct AstNodeEnumDecl {
Buf name;
ZigList<AstNode *> fields;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
};
struct AstNodeEnumField {
Buf name;
ZigList<AstNode *> fields; // length 0 means simple enum
AstNode *val_expr;
};
struct AstNodeStringLiteral {
Buf buf;
bool c;
// populated by semantic analyzer:
Expr resolved_expr;
};
struct AstNodeCharLiteral {
uint8_t value;
// populated by semantic analyzer:
Expr resolved_expr;
};
enum NumLit {
NumLitF32,
NumLitF64,
NumLitF128,
NumLitU8,
NumLitU16,
NumLitU32,
NumLitU64,
NumLitI8,
NumLitI16,
NumLitI32,
NumLitI64,
NumLitCount
};
struct AstNodeNumberLiteral {
NumLit kind;
// overflow is true if when parsing the number, we discovered it would not
// fit without losing data in a uint64_t, int64_t, or double
bool overflow;
union {
uint64_t x_uint;
int64_t x_int;
double x_float;
} data;
// populated by semantic analyzer
NumLitCodeGen codegen;
Expr resolved_expr;
};
struct AstNodeStructValueField {
Buf name;
AstNode *expr;
// populated by semantic analyzer
int index;
};
struct AstNodeStructValueExpr {
AstNode *type;
ZigList<AstNode *> fields;
// populated by semantic analyzer
StructValExprCodeGen codegen;
Expr resolved_expr;
};
struct AstNodeCompilerFnExpr {
Buf name;
AstNode *expr;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeCompilerFnType {
Buf name;
AstNode *type;
// populated by semantic analyzer
Expr resolved_expr;
NumLitCodeGen resolved_num_lit;
};
struct AstNodeNullLiteral {
// populated by semantic analyzer
StructValExprCodeGen resolved_struct_val_expr;
Expr resolved_expr;
};
struct AstNodeVoidExpr {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeUnreachableExpr {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeSymbolExpr {
Buf symbol;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeBoolLiteral {
bool value;
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeBreakExpr {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNodeContinueExpr {
// populated by semantic analyzer
Expr resolved_expr;
};
struct AstNode {
enum NodeType type;
int line;
int column;
uint32_t create_index; // for determinism purposes
ImportTableEntry *owner;
union {
AstNodeRoot root;
AstNodeRootExportDecl root_export_decl;
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
AstNodeType type;
AstNodeParamDecl param_decl;
AstNodeBlock block;
AstNodeReturnExpr return_expr;
AstNodeVariableDeclaration variable_declaration;
AstNodeBinOpExpr bin_op_expr;
AstNodeExternBlock extern_block;
AstNodeDirective directive;
AstNodeCastExpr cast_expr;
AstNodePrefixOpExpr prefix_op_expr;
AstNodeFnCallExpr fn_call_expr;
AstNodeArrayAccessExpr array_access_expr;
AstNodeSliceExpr slice_expr;
AstNodeUse use;
AstNodeIfBoolExpr if_bool_expr;
AstNodeIfVarExpr if_var_expr;
AstNodeWhileExpr while_expr;
AstNodeLabel label;
AstNodeGoto goto_expr;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodeStructDecl struct_decl;
AstNodeStructField struct_field;
AstNodeEnumDecl enum_decl;
AstNodeEnumField enum_field;
AstNodeStringLiteral string_literal;
AstNodeCharLiteral char_literal;
AstNodeNumberLiteral number_literal;
AstNodeStructValueExpr struct_val_expr;
AstNodeStructValueField struct_val_field;
AstNodeCompilerFnExpr compiler_fn_expr;
AstNodeCompilerFnType compiler_fn_type;
AstNodeNullLiteral null_literal;
AstNodeVoidExpr void_expr;
AstNodeUnreachableExpr unreachable_expr;
AstNodeSymbolExpr symbol_expr;
AstNodeBoolLiteral bool_literal;
AstNodeBreakExpr break_expr;
AstNodeContinueExpr continue_expr;
} data;
};
enum AsmTokenId {
AsmTokenIdTemplate,
AsmTokenIdPercent,
AsmTokenIdVar,
};
struct AsmToken {
enum AsmTokenId id;
int start;
int end;
};
struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_noalias;
};
struct TypeTableEntryInt {
bool is_signed;
};
struct TypeTableEntryArray {
TypeTableEntry *child_type;
uint64_t len;
};
struct TypeStructField {
Buf *name;
TypeTableEntry *type_entry;
};
struct TypeTableEntryStruct {
AstNode *decl_node;
bool is_packed;
int field_count;
TypeStructField *fields;
uint64_t size_bytes;
bool is_invalid; // true if any fields are invalid
bool is_unknown_size_array;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
// set this flag temporarily to detect infinite loops
bool embedded_in_current;
bool reported_infinite_err;
};
struct TypeTableEntryNumLit {
NumLit kind;
};
struct TypeTableEntryMaybe {
TypeTableEntry *child_type;
};
enum TypeTableEntryId {
TypeTableEntryIdInvalid,
TypeTableEntryIdVoid,
TypeTableEntryIdBool,
TypeTableEntryIdUnreachable,
TypeTableEntryIdInt,
TypeTableEntryIdFloat,
TypeTableEntryIdPointer,
TypeTableEntryIdArray,
TypeTableEntryIdStruct,
TypeTableEntryIdNumberLiteral,
TypeTableEntryIdMaybe,
};
struct TypeTableEntry {
TypeTableEntryId id;
LLVMTypeRef type_ref;
LLVMZigDIType *di_type;
uint64_t size_in_bits;
uint64_t align_in_bits;
Buf name;
union {
TypeTableEntryPointer pointer;
TypeTableEntryInt integral;
TypeTableEntryArray array;
TypeTableEntryStruct structure;
TypeTableEntryNumLit num_lit;
TypeTableEntryMaybe maybe;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
TypeTableEntry *maybe_parent;
};
struct ImporterInfo {
ImportTableEntry *import;
AstNode *source_node;
};
struct ImportTableEntry {
AstNode *root;
Buf *path; // relative to root_source_dir
LLVMZigDIFile *di_file;
Buf *source_code;
ZigList<int> *line_offsets;
BlockContext *block_context;
ZigList<ImporterInfo> importers;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
};
struct LabelTableEntry {
AstNode *label_node;
LLVMBasicBlockRef basic_block;
bool used;
bool entered_from_fallthrough;
};
enum FnAttrId {
FnAttrIdNaked,
FnAttrIdAlwaysInline,
};
struct FnTableEntry {
LLVMValueRef fn_value;
AstNode *proto_node;
AstNode *fn_def_node;
bool is_extern;
bool internal_linkage;
unsigned calling_convention;
ImportTableEntry *import_entry;
ZigList<FnAttrId> fn_attr_list;
// Required to be a pre-order traversal of the AST. (parents must come before children)
ZigList<BlockContext *> all_block_contexts;
TypeTableEntry *member_of_struct;
Buf symbol_name;
// reminder: hash tables must be initialized before use
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
};
enum BuiltinFnId {
BuiltinFnIdInvalid,
BuiltinFnIdArithmeticWithOverflow,
BuiltinFnIdMemcpy,
BuiltinFnIdMemset,
};
struct BuiltinFnEntry {
BuiltinFnId id;
Buf name;
int param_count;
TypeTableEntry *return_type;
TypeTableEntry **param_types;
LLVMValueRef fn_val;
};
struct CodeGen {
LLVMModuleRef module;
ZigList<ErrorMsg*> errors;
LLVMBuilderRef builder;
LLVMZigDIBuilder *dbuilder;
LLVMZigDICompileUnit *compile_unit;
ZigList<Buf *> lib_search_paths;
// reminder: hash tables must be initialized before use
HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_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 *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
uint32_t next_unresolved_index;
struct {
TypeTableEntry *entry_bool;
TypeTableEntry *entry_u8;
TypeTableEntry *entry_u16;
TypeTableEntry *entry_u32;
TypeTableEntry *entry_u64;
TypeTableEntry *entry_i8;
TypeTableEntry *entry_i16;
TypeTableEntry *entry_i32;
TypeTableEntry *entry_i64;
TypeTableEntry *entry_isize;
TypeTableEntry *entry_usize;
TypeTableEntry *entry_f32;
TypeTableEntry *entry_f64;
TypeTableEntry *entry_c_string_literal;
TypeTableEntry *entry_void;
TypeTableEntry *entry_unreachable;
TypeTableEntry *entry_invalid;
} builtin_types;
TypeTableEntry *num_lit_types[NumLitCount];
LLVMTargetDataRef target_data_ref;
unsigned pointer_size_bytes;
bool is_static;
bool strip_debug_symbols;
bool have_exported_main;
bool link_libc;
Buf *libc_path;
CodeGenBuildType build_type;
LLVMTargetMachineRef target_machine;
LLVMZigDIFile *dummy_di_file;
bool is_native_target;
Buf *root_source_dir;
Buf *root_out_name;
// The function definitions this module includes. There must be a corresponding
// fn_protos entry.
ZigList<FnTableEntry *> fn_defs;
// The function prototypes this module includes. In the case of external declarations,
// there will not be a corresponding fn_defs entry.
ZigList<FnTableEntry *> fn_protos;
ZigList<VariableTableEntry *> global_vars;
OutType out_type;
FnTableEntry *cur_fn;
BlockContext *cur_block_context;
ZigList<LLVMBasicBlockRef> break_block_stack;
ZigList<LLVMBasicBlockRef> continue_block_stack;
bool c_stdint_used;
AstNode *root_export_decl;
int version_major;
int version_minor;
int version_patch;
bool verbose;
ErrColor err_color;
ImportTableEntry *root_import;
ImportTableEntry *bootstrap_import;
LLVMValueRef memcpy_fn_val;
bool error_during_imports;
};
struct VariableTableEntry {
Buf name;
TypeTableEntry *type;
LLVMValueRef value_ref;
bool is_const;
bool is_ptr; // if true, value_ref is a pointer
AstNode *decl_node;
LLVMZigDILocalVariable *di_loc_var;
int arg_index;
};
struct BlockContext {
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
FnTableEntry *fn_entry; // null at the module scope
BlockContext *parent; // null when this is the root
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
ZigList<Cast *> cast_expr_alloca_list;
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
AstNode *parent_loop_node;
AstNode *next_child_parent_loop_node;
LLVMZigDIScope *di_scope;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -8,414 +8,16 @@
#ifndef ZIG_ANALYZE_HPP
#define ZIG_ANALYZE_HPP
#include "codegen.hpp"
#include "hash_map.hpp"
#include "zig_llvm.hpp"
#include "errmsg.hpp"
struct FnTableEntry;
struct BlockContext;
struct TypeTableEntry;
struct VariableTableEntry;
struct CastNode;
struct StructValExprNode;
struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_noalias;
};
struct TypeTableEntryInt {
bool is_signed;
};
struct TypeTableEntryArray {
TypeTableEntry *child_type;
uint64_t len;
};
struct TypeStructField {
Buf *name;
TypeTableEntry *type_entry;
};
struct TypeTableEntryStruct {
AstNode *decl_node;
bool is_packed;
int field_count;
TypeStructField *fields;
uint64_t size_bytes;
bool is_invalid; // true if any fields are invalid
bool is_unknown_size_array;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
// set this flag temporarily to detect infinite loops
bool embedded_in_current;
bool reported_infinite_err;
};
struct TypeTableEntryNumLit {
NumLit kind;
};
struct TypeTableEntryMaybe {
TypeTableEntry *child_type;
};
enum TypeTableEntryId {
TypeTableEntryIdInvalid,
TypeTableEntryIdVoid,
TypeTableEntryIdBool,
TypeTableEntryIdUnreachable,
TypeTableEntryIdInt,
TypeTableEntryIdFloat,
TypeTableEntryIdPointer,
TypeTableEntryIdArray,
TypeTableEntryIdStruct,
TypeTableEntryIdNumberLiteral,
TypeTableEntryIdMaybe,
};
struct TypeTableEntry {
TypeTableEntryId id;
LLVMTypeRef type_ref;
LLVMZigDIType *di_type;
uint64_t size_in_bits;
uint64_t align_in_bits;
Buf name;
union {
TypeTableEntryPointer pointer;
TypeTableEntryInt integral;
TypeTableEntryArray array;
TypeTableEntryStruct structure;
TypeTableEntryNumLit num_lit;
TypeTableEntryMaybe maybe;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
TypeTableEntry *maybe_parent;
};
struct ImporterInfo {
ImportTableEntry *import;
AstNode *source_node;
};
struct ImportTableEntry {
AstNode *root;
Buf *path; // relative to root_source_dir
LLVMZigDIFile *di_file;
Buf *source_code;
ZigList<int> *line_offsets;
BlockContext *block_context;
ZigList<ImporterInfo> importers;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
};
struct LabelTableEntry {
AstNode *label_node;
LLVMBasicBlockRef basic_block;
bool used;
bool entered_from_fallthrough;
};
enum FnAttrId {
FnAttrIdNaked,
FnAttrIdAlwaysInline,
};
struct FnTableEntry {
LLVMValueRef fn_value;
AstNode *proto_node;
AstNode *fn_def_node;
bool is_extern;
bool internal_linkage;
unsigned calling_convention;
ImportTableEntry *import_entry;
ZigList<FnAttrId> fn_attr_list;
// Required to be a pre-order traversal of the AST. (parents must come before children)
ZigList<BlockContext *> all_block_contexts;
TypeTableEntry *member_of_struct;
Buf symbol_name;
// reminder: hash tables must be initialized before use
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
};
enum BuiltinFnId {
BuiltinFnIdInvalid,
BuiltinFnIdArithmeticWithOverflow,
BuiltinFnIdMemcpy,
BuiltinFnIdMemset,
};
struct BuiltinFnEntry {
BuiltinFnId id;
Buf name;
int param_count;
TypeTableEntry *return_type;
TypeTableEntry **param_types;
LLVMValueRef fn_val;
};
struct CodeGen {
LLVMModuleRef module;
ZigList<ErrorMsg*> errors;
LLVMBuilderRef builder;
LLVMZigDIBuilder *dbuilder;
LLVMZigDICompileUnit *compile_unit;
ZigList<Buf *> lib_search_paths;
// reminder: hash tables must be initialized before use
HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_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 *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
uint32_t next_unresolved_index;
struct {
TypeTableEntry *entry_bool;
TypeTableEntry *entry_u8;
TypeTableEntry *entry_u16;
TypeTableEntry *entry_u32;
TypeTableEntry *entry_u64;
TypeTableEntry *entry_i8;
TypeTableEntry *entry_i16;
TypeTableEntry *entry_i32;
TypeTableEntry *entry_i64;
TypeTableEntry *entry_isize;
TypeTableEntry *entry_usize;
TypeTableEntry *entry_f32;
TypeTableEntry *entry_f64;
TypeTableEntry *entry_c_string_literal;
TypeTableEntry *entry_void;
TypeTableEntry *entry_unreachable;
TypeTableEntry *entry_invalid;
} builtin_types;
TypeTableEntry *num_lit_types[NumLitCount];
LLVMTargetDataRef target_data_ref;
unsigned pointer_size_bytes;
bool is_static;
bool strip_debug_symbols;
bool have_exported_main;
bool link_libc;
Buf *libc_path;
CodeGenBuildType build_type;
LLVMTargetMachineRef target_machine;
LLVMZigDIFile *dummy_di_file;
bool is_native_target;
Buf *root_source_dir;
Buf *root_out_name;
// The function definitions this module includes. There must be a corresponding
// fn_protos entry.
ZigList<FnTableEntry *> fn_defs;
// The function prototypes this module includes. In the case of external declarations,
// there will not be a corresponding fn_defs entry.
ZigList<FnTableEntry *> fn_protos;
ZigList<VariableTableEntry *> global_vars;
OutType out_type;
FnTableEntry *cur_fn;
BlockContext *cur_block_context;
ZigList<LLVMBasicBlockRef> break_block_stack;
ZigList<LLVMBasicBlockRef> continue_block_stack;
bool c_stdint_used;
AstNode *root_export_decl;
int version_major;
int version_minor;
int version_patch;
bool verbose;
ErrColor err_color;
ImportTableEntry *root_import;
ImportTableEntry *bootstrap_import;
LLVMValueRef memcpy_fn_val;
bool error_during_imports;
};
struct VariableTableEntry {
Buf name;
TypeTableEntry *type;
LLVMValueRef value_ref;
bool is_const;
bool is_ptr; // if true, value_ref is a pointer
AstNode *decl_node;
LLVMZigDILocalVariable *di_loc_var;
int arg_index;
};
struct BlockContext {
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
FnTableEntry *fn_entry; // null at the module scope
BlockContext *parent; // null when this is the root
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
ZigList<CastNode *> cast_expr_alloca_list;
ZigList<StructValExprNode *> struct_val_expr_alloca_list;
AstNode *parent_loop_node;
AstNode *next_child_parent_loop_node;
LLVMZigDIScope *di_scope;
};
struct TypeNode {
TypeTableEntry *entry;
};
struct FnProtoNode {
FnTableEntry *fn_table_entry;
bool skip;
};
struct FnDefNode {
TypeTableEntry *implicit_return_type;
BlockContext *block_context;
};
struct AssignNode {
VariableTableEntry *var_entry;
};
struct BlockNode {
BlockContext *block_context;
};
struct StructDeclNode {
TypeTableEntry *type_entry;
};
struct FieldAccessNode {
int field_index;
TypeStructField *type_struct_field;
};
enum CastOp {
CastOpNothing,
CastOpPtrToInt,
CastOpIntWidenOrShorten,
CastOpToUnknownSizeArray,
CastOpMaybeWrap,
CastOpPointerReinterpret,
};
struct CastNode {
CastOp op;
// if op is CastOpArrayToString, this will be a pointer to
// the string struct on the stack
LLVMValueRef ptr;
TypeTableEntry *after_type;
AstNode *source_node;
};
struct ExprNode {
TypeTableEntry *type_entry;
// the context in which this expression is evaluated.
// for blocks, this points to the containing scope, not the block's own scope for its children.
BlockContext *block_context;
// may be null for no cast
CastNode implicit_cast; // happens first
CastNode implicit_maybe_cast; // happens second
};
struct NumberLiteralNode {
TypeTableEntry *resolved_type;
};
struct VarDeclNode {
TypeTableEntry *type;
};
struct StructValFieldNode {
int index;
};
struct StructValExprNode {
TypeTableEntry *type_entry;
LLVMValueRef ptr;
AstNode *source_node;
};
struct IfVarNode {
BlockContext *block_context;
};
struct ParamDeclNode {
VariableTableEntry *variable;
};
struct ImportNode {
ImportTableEntry *import;
};
struct WhileNode {
bool condition_always_true;
bool contains_break;
};
struct FnCallNode {
BuiltinFnEntry *builtin_fn;
};
struct DeclNode {
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps;
Buf *name;
ImportTableEntry *import;
// set this flag temporarily to detect infinite loops
bool in_current_deps;
};
// TODO get rid of this structure and put the data directly in the appropriate AST node
struct CodeGenNode {
union {
TypeNode type_node; // for NodeTypeType
FnDefNode fn_def_node; // for NodeTypeFnDef
FnProtoNode fn_proto_node; // for NodeTypeFnProto
LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel
AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
BlockNode block_node; // for NodeTypeBlock
StructDeclNode struct_decl_node; // for NodeTypeStructDecl
FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
CastNode cast_node; // for NodeTypeCastExpr
// note: I've been using this field on some non-number literal nodes too.
NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
// note: I've been using this field on some non-struct val expressions too.
StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
IfVarNode if_var_node; // for NodeTypeStructValueExpr
ParamDeclNode param_decl_node; // for NodeTypeParamDecl
ImportNode import_node; // for NodeTypeUse
WhileNode while_node; // for NodeTypeWhileExpr
FnCallNode fn_call_node; // for NodeTypeFnCallExpr
} data;
ExprNode expr_node; // for all the expression nodes
DeclNode decl_node; // for all top level decls
};
#include "all_types.hpp"
void semantic_analyze(CodeGen *g);
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
void alloc_codegen_node(AstNode *node);
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias);
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
Expr *get_resolved_expr(AstNode *node);
NumLitCodeGen *get_resolved_num_lit(AstNode *node);
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
#endif

View File

@ -75,9 +75,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
assert(type_node->type == NodeTypeType);
assert(type_node->codegen_node);
assert(type_node->codegen_node->data.type_node.entry);
return type_node->codegen_node->data.type_node.entry;
return type_node->data.type.entry;
}
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
@ -138,15 +136,16 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
}
static TypeTableEntry *get_expr_type(AstNode *node) {
TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.after_type;
return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;
Expr *expr = get_resolved_expr(node);
TypeTableEntry *cast_type = expr->implicit_cast.after_type;
return cast_type ? cast_type : expr->type_entry;
}
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
assert(fn_ref_expr->type == NodeTypeSymbol);
BuiltinFnEntry *builtin_fn = node->codegen_node->data.fn_call_node.builtin_fn;
BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn;
switch (builtin_fn->id) {
case BuiltinFnIdInvalid:
@ -265,7 +264,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
// Assume that the expression evaluates to a simple name and return the buf
// TODO after we support function pointers we can make this generic
assert(fn_ref_expr->type == NodeTypeSymbol);
Buf *name = &fn_ref_expr->data.symbol;
Buf *name = &fn_ref_expr->data.symbol_expr.symbol;
struct_type = nullptr;
first_param_expr = nullptr;
@ -388,8 +387,8 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
LLVMValueRef struct_ptr;
if (struct_expr_node->type == NodeTypeSymbol) {
VariableTableEntry *var = find_variable(struct_expr_node->codegen_node->expr_node.block_context,
&struct_expr_node->data.symbol);
VariableTableEntry *var = find_variable(get_resolved_expr(struct_expr_node)->block_context,
&struct_expr_node->data.symbol_expr.symbol);
assert(var);
if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) {
@ -413,14 +412,12 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
assert(node->data.field_access_expr.field_index >= 0);
assert(codegen_field_access->field_index >= 0);
*out_type_entry = codegen_field_access->type_struct_field->type_entry;
*out_type_entry = node->data.field_access_expr.type_struct_field->type_entry;
add_debug_source_node(g, node);
return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
return LLVMBuildStructGEP(g->builder, struct_ptr, node->data.field_access_expr.field_index, "");
}
static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
@ -429,7 +426,7 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
AstNode *array_ref_node = node->data.slice_expr.array_ref_expr;
TypeTableEntry *array_type = get_expr_type(array_ref_node);
LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr;
LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr;
LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node);
if (array_type->id == TypeTableEntryIdArray) {
@ -545,8 +542,8 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
LLVMValueRef target_ref;
if (node->type == NodeTypeSymbol) {
VariableTableEntry *var = find_variable(expr_node->codegen_node->expr_node.block_context,
&node->data.symbol);
VariableTableEntry *var = find_variable(get_resolved_expr(expr_node)->block_context,
&node->data.symbol_expr.symbol);
assert(var);
// semantic checking ensures no variables are constant
assert(!var->is_const);
@ -630,7 +627,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
}
static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val,
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, CastNode *cast_node)
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node)
{
switch (cast_node->op) {
case CastOpNothing:
@ -705,7 +702,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
TypeTableEntry *wanted_type = get_expr_type(node);
CastNode *cast_node = &node->codegen_node->data.cast_node;
Cast *cast_node = &node->data.cast_expr.cast;
return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node);
@ -1218,7 +1215,7 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
assert(node->data.if_var_expr.var_decl.expr);
BlockContext *old_block_context = g->cur_block_context;
BlockContext *new_block_context = node->codegen_node->data.if_var_node.block_context;
BlockContext *new_block_context = node->data.if_var_expr.block_context;
LLVMValueRef init_val;
gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, new_block_context, true, &init_val);
@ -1242,7 +1239,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
assert(block_node->type == NodeTypeBlock);
BlockContext *old_block_context = g->cur_block_context;
g->cur_block_context = block_node->codegen_node->data.block_node.block_context;
g->cur_block_context = block_node->data.block.block_context;
LLVMValueRef return_value;
for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
@ -1347,7 +1344,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
if (!is_return) {
VariableTableEntry *variable = find_variable(
node->codegen_node->expr_node.block_context,
get_resolved_expr(node)->block_context,
&asm_output->variable_name);
assert(variable);
param_types[param_index] = LLVMTypeOf(variable->value_ref);
@ -1396,7 +1393,7 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
TypeTableEntry *type_entry = get_expr_type(node);
assert(type_entry->id == TypeTableEntryIdMaybe);
LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr;
LLVMValueRef tmp_struct_ptr = node->data.null_literal.resolved_struct_val_expr.ptr;
add_debug_source_node(g, node);
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
@ -1416,12 +1413,13 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
int field_count = type_entry->data.structure.field_count;
assert(field_count == node->data.struct_val_expr.fields.length);
StructValExprNode *struct_val_expr_node = &node->codegen_node->data.struct_val_expr_node;
StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen;
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
for (int i = 0; i < field_count; i += 1) {
AstNode *field_node = node->data.struct_val_expr.fields.at(i);
int index = field_node->codegen_node->data.struct_val_field_node.index;
assert(field_node->type == NodeTypeStructValueField);
int index = field_node->data.struct_val_field.index;
TypeStructField *type_struct_field = &type_entry->data.structure.fields[index];
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
@ -1439,8 +1437,8 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
assert(node->data.while_expr.condition);
assert(node->data.while_expr.body);
bool condition_always_true = node->codegen_node->data.while_node.condition_always_true;
bool contains_break = node->codegen_node->data.while_node.contains_break;
bool condition_always_true = node->data.while_expr.condition_always_true;
bool contains_break = node->data.while_expr.contains_break;
if (condition_always_true) {
// generate a forever loop
@ -1559,17 +1557,17 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
LLVMValueRef init_val;
return gen_var_decl_raw(g, node, &node->data.variable_declaration,
node->codegen_node->expr_node.block_context, false, &init_val);
get_resolved_expr(node)->block_context, false, &init_val);
}
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
NumberLiteralNode *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
{
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
assert(type_entry);
// override the expression type for number literals
source_node->codegen_node->expr_node.type_entry = type_entry;
get_resolved_expr(source_node)->type_entry = type_entry;
if (type_entry->id == TypeTableEntryIdInt) {
// here the union has int64_t and uint64_t and we purposefully read
@ -1594,7 +1592,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
Buf *name = &node->data.compiler_fn_type.name;
TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
if (buf_eql_str(name, "sizeof")) {
NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
AstNodeNumberLiteral num_lit_node;
num_lit_node.kind = type_entry->data.num_lit.kind;
num_lit_node.overflow = false;
@ -1632,7 +1630,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeNumberLiteral);
NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
assert(codegen_num_lit);
return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
@ -1664,7 +1662,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
case NodeTypeVoid:
return nullptr;
case NodeTypeBoolLiteral:
if (node->data.bool_literal)
if (node->data.bool_literal.value)
return LLVMConstAllOnes(LLVMInt1Type());
else
return LLVMConstNull(LLVMInt1Type());
@ -1696,8 +1694,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
case NodeTypeSymbol:
{
VariableTableEntry *variable = find_variable(
node->codegen_node->expr_node.block_context,
&node->data.symbol);
get_resolved_expr(node)->block_context,
&node->data.symbol_expr.symbol);
assert(variable);
if (variable->type->id == TypeTableEntryIdVoid) {
return nullptr;
@ -1721,14 +1719,14 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return gen_block(g, node, nullptr);
case NodeTypeGoto:
add_debug_source_node(g, node);
return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
return LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block);
case NodeTypeBreak:
return gen_break(g, node);
case NodeTypeContinue:
return gen_continue(g, node);
case NodeTypeLabel:
{
LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
LabelTableEntry *label_entry = node->data.label.label_entry;
assert(label_entry);
LLVMBasicBlockRef basic_block = label_entry->basic_block;
if (label_entry->entered_from_fallthrough) {
@ -1770,19 +1768,19 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
return val;
}
assert(node->codegen_node);
Expr *expr = get_resolved_expr(node);
TypeTableEntry *before_type = node->codegen_node->expr_node.type_entry;
TypeTableEntry *before_type = expr->type_entry;
if (before_type && before_type->id == TypeTableEntryIdUnreachable) {
return val;
}
CastNode *cast_node = &node->codegen_node->expr_node.implicit_cast;
Cast *cast_node = &expr->implicit_cast;
if (cast_node->after_type) {
val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node);
before_type = cast_node->after_type;
}
cast_node = &node->codegen_node->expr_node.implicit_maybe_cast;
cast_node = &expr->implicit_maybe_cast;
if (cast_node->after_type) {
val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node);
}
@ -1798,7 +1796,7 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {
continue;
Buf *name = &label_node->data.label.name;
label_node->codegen_node->data.label_entry->basic_block = LLVMAppendBasicBlock(
label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock(
g->cur_fn->fn_value, buf_ptr(name));
}
@ -1944,13 +1942,7 @@ static void do_code_gen(CodeGen *g) {
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry");
LLVMPositionBuilderAtEnd(g->builder, entry_block);
CodeGenNode *codegen_node = fn_def_node->codegen_node;
assert(codegen_node);
FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
assert(codegen_fn_def);
codegen_fn_def->block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
int non_void_param_count = count_non_void_params(g, &fn_proto->params);
assert(non_void_param_count == (int)LLVMCountParams(fn));
@ -1963,7 +1955,7 @@ static void do_code_gen(CodeGen *g) {
assert(param_decl->type == NodeTypeParamDecl);
if (is_param_decl_type_void(g, param_decl))
continue;
VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(&param_decl->data.param_decl.name);
VariableTableEntry *parameter_variable = fn_def_node->data.fn_def.block_context->variable_table.get(&param_decl->data.param_decl.name);
parameter_variable->value_ref = params[non_void_index];
non_void_index += 1;
}
@ -2019,14 +2011,14 @@ static void do_code_gen(CodeGen *g) {
// allocate structs which are the result of casts
for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {
CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i);
Cast *cast_node = block_context->cast_expr_alloca_list.at(cea_i);
add_debug_source_node(g, cast_node->source_node);
cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, "");
}
// allocate structs which are struct value expressions
for (int alloca_i = 0; alloca_i < block_context->struct_val_expr_alloca_list.length; alloca_i += 1) {
StructValExprNode *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i);
StructValExprCodeGen *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i);
add_debug_source_node(g, struct_val_expr_node->source_node);
struct_val_expr_node->ptr = LLVMBuildAlloca(g->builder,
struct_val_expr_node->type_entry->type_ref, "");
@ -2041,15 +2033,15 @@ static void do_code_gen(CodeGen *g) {
if (is_param_decl_type_void(g, param_decl))
continue;
VariableTableEntry *variable = param_decl->codegen_node->data.param_decl_node.variable;
VariableTableEntry *variable = param_decl->data.param_decl.variable;
LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(param_decl->line + 1, param_decl->column + 1,
codegen_fn_def->block_context->di_scope);
fn_def_node->data.fn_def.block_context->di_scope);
LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc,
entry_block);
}
TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
TypeTableEntry *implicit_return_type = fn_def_node->data.fn_def.implicit_return_type;
gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type);
}
@ -2549,8 +2541,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
Buf *import_code = buf_alloc();
bool found_it = false;
alloc_codegen_node(top_level_decl);
for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) {
Buf *search_path = g->lib_search_paths.at(path_i);
os_path_join(search_path, import_target_path, &full_path);
@ -2570,7 +2560,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
auto entry = g->import_table.maybe_get(abs_full_path);
if (entry) {
found_it = true;
top_level_decl->codegen_node->data.import_node.import = entry->value;
top_level_decl->data.use.import = entry->value;
} else {
if ((err = os_fetch_file_path(abs_full_path, import_code))) {
if (err == ErrorFileNotFound) {
@ -2582,7 +2572,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
goto done_looking_at_imports;
}
}
top_level_decl->codegen_node->data.import_node.import = codegen_add_code(g,
top_level_decl->data.use.import = codegen_add_code(g,
abs_full_path, search_path, &top_level_decl->data.use.path, import_code);
found_it = true;
}
@ -2682,9 +2672,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
assert(type_node->type == NodeTypeType);
assert(type_node->codegen_node);
TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry;
TypeTableEntry *type_entry = type_node->data.type.entry;
assert(type_entry);
if (type_entry == g->builtin_types.entry_u8) {

View File

@ -11,21 +11,8 @@
#include "parser.hpp"
#include "errmsg.hpp"
struct CodeGen;
enum OutType {
OutTypeUnknown,
OutTypeExe,
OutTypeLib,
OutTypeObj,
};
CodeGen *codegen_create(Buf *root_source_dir);
enum CodeGenBuildType {
CodeGenBuildTypeDebug,
CodeGenBuildTypeRelease,
};
void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);

View File

@ -356,8 +356,7 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "Unreachable\n");
break;
case NodeTypeSymbol:
fprintf(stderr, "Symbol %s\n",
buf_ptr(&node->data.symbol));
fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol));
break;
case NodeTypeUse:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));
@ -366,7 +365,8 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
case NodeTypeBoolLiteral:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");
fprintf(stderr, "%s '%s'\n", node_type_str(node->type),
node->data.bool_literal.value ? "true" : "false");
break;
case NodeTypeNullLiteral:
fprintf(stderr, "%s\n", node_type_str(node->type));
@ -401,7 +401,7 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
break;
case NodeTypeGoto:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.goto_expr.name));
break;
case NodeTypeBreak:
fprintf(stderr, "%s\n", node_type_str(node->type));
@ -1369,12 +1369,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
return node;
} else if (token->id == TokenIdKeywordTrue) {
AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token);
node->data.bool_literal = true;
node->data.bool_literal.value = true;
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordFalse) {
AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token);
node->data.bool_literal = false;
node->data.bool_literal.value = false;
*token_index += 1;
return node;
} else if (token->id == TokenIdKeywordNull) {
@ -1385,7 +1385,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
*token_index += 1;
Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok);
ast_buf_from_token(pc, name_tok, &name_node->data.symbol);
ast_buf_from_token(pc, name_tok, &name_node->data.symbol_expr.symbol);
AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
node->data.fn_call_expr.fn_ref_expr = name_node;
@ -1401,7 +1401,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
} else {
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
ast_buf_from_token(pc, token, &node->data.symbol);
ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
return node;
}
} else if (token->id == TokenIdKeywordGoto) {
@ -1412,7 +1412,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
*token_index += 1;
ast_expect_token(pc, dest_symbol, TokenIdSymbol);
ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name);
ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
return node;
} else if (token->id == TokenIdKeywordBreak) {
AstNode *node = ast_create_node(pc, NodeTypeBreak, token);

View File

@ -8,450 +8,10 @@
#ifndef ZIG_PARSER_HPP
#define ZIG_PARSER_HPP
#include "list.hpp"
#include "buffer.hpp"
#include "all_types.hpp"
#include "tokenizer.hpp"
#include "errmsg.hpp"
struct AstNode;
struct CodeGenNode;
struct ImportTableEntry;
struct AsmToken;
enum NodeType {
NodeTypeRoot,
NodeTypeRootExportDecl,
NodeTypeFnProto,
NodeTypeFnDef,
NodeTypeFnDecl,
NodeTypeParamDecl,
NodeTypeType,
NodeTypeBlock,
NodeTypeExternBlock,
NodeTypeDirective,
NodeTypeReturnExpr,
NodeTypeVariableDeclaration,
NodeTypeBinOpExpr,
NodeTypeCastExpr,
NodeTypeNumberLiteral,
NodeTypeStringLiteral,
NodeTypeCharLiteral,
NodeTypeUnreachable,
NodeTypeSymbol,
NodeTypePrefixOpExpr,
NodeTypeFnCallExpr,
NodeTypeArrayAccessExpr,
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypeUse,
NodeTypeVoid,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
NodeTypeIfBoolExpr,
NodeTypeIfVarExpr,
NodeTypeWhileExpr,
NodeTypeLabel,
NodeTypeGoto,
NodeTypeBreak,
NodeTypeContinue,
NodeTypeAsmExpr,
NodeTypeStructDecl,
NodeTypeStructField,
NodeTypeStructValueExpr,
NodeTypeStructValueField,
NodeTypeEnumDecl,
NodeTypeEnumField,
NodeTypeCompilerFnExpr,
NodeTypeCompilerFnType,
};
struct AstNodeRoot {
ZigList<AstNode *> top_level_decls;
};
enum VisibMod {
VisibModPrivate,
VisibModPub,
VisibModExport,
};
struct AstNodeFnProto {
ZigList<AstNode *> *directives;
VisibMod visib_mod;
Buf name;
ZigList<AstNode *> params;
AstNode *return_type;
bool is_var_args;
// the extern block this fn proto is inside. can be null.
// populated by semantic analyzer.
AstNode *extern_node;
// the struct decl node this fn proto is inside. can be null.
// populated by semantic analyzer.
AstNode *struct_node;
// the function definition this fn proto is inside. can be null.
// populated by semantic analyzer.
AstNode *fn_def_node;
};
struct AstNodeFnDef {
AstNode *fn_proto;
AstNode *body;
};
struct AstNodeFnDecl {
AstNode *fn_proto;
};
struct AstNodeParamDecl {
Buf name;
AstNode *type;
};
enum AstNodeTypeType {
AstNodeTypeTypePrimitive,
AstNodeTypeTypePointer,
AstNodeTypeTypeArray,
AstNodeTypeTypeMaybe,
AstNodeTypeTypeCompilerExpr,
};
struct AstNodeType {
AstNodeTypeType type;
Buf primitive_name;
AstNode *child_type;
AstNode *array_size; // can be null
bool is_const;
bool is_noalias;
AstNode *compiler_expr;
};
struct AstNodeBlock {
ZigList<AstNode *> statements;
};
struct AstNodeReturnExpr {
// might be null in case of return void;
AstNode *expr;
};
struct AstNodeVariableDeclaration {
Buf symbol;
bool is_const;
VisibMod visib_mod;
// one or both of type and expr will be non null
AstNode *type;
AstNode *expr;
};
enum BinOpType {
BinOpTypeInvalid,
BinOpTypeAssign,
BinOpTypeAssignTimes,
BinOpTypeAssignDiv,
BinOpTypeAssignMod,
BinOpTypeAssignPlus,
BinOpTypeAssignMinus,
BinOpTypeAssignBitShiftLeft,
BinOpTypeAssignBitShiftRight,
BinOpTypeAssignBitAnd,
BinOpTypeAssignBitXor,
BinOpTypeAssignBitOr,
BinOpTypeAssignBoolAnd,
BinOpTypeAssignBoolOr,
BinOpTypeBoolOr,
BinOpTypeBoolAnd,
BinOpTypeCmpEq,
BinOpTypeCmpNotEq,
BinOpTypeCmpLessThan,
BinOpTypeCmpGreaterThan,
BinOpTypeCmpLessOrEq,
BinOpTypeCmpGreaterOrEq,
BinOpTypeBinOr,
BinOpTypeBinXor,
BinOpTypeBinAnd,
BinOpTypeBitShiftLeft,
BinOpTypeBitShiftRight,
BinOpTypeAdd,
BinOpTypeSub,
BinOpTypeMult,
BinOpTypeDiv,
BinOpTypeMod,
BinOpTypeUnwrapMaybe,
};
struct AstNodeBinOpExpr {
AstNode *op1;
BinOpType bin_op;
AstNode *op2;
};
struct AstNodeFnCallExpr {
AstNode *fn_ref_expr;
ZigList<AstNode *> params;
bool is_builtin;
};
struct AstNodeArrayAccessExpr {
AstNode *array_ref_expr;
AstNode *subscript;
};
struct AstNodeSliceExpr {
AstNode *array_ref_expr;
AstNode *start;
AstNode *end;
bool is_const;
};
struct AstNodeFieldAccessExpr {
AstNode *struct_expr;
Buf field_name;
};
struct AstNodeExternBlock {
ZigList<AstNode *> *directives;
ZigList<AstNode *> fn_decls;
};
struct AstNodeDirective {
Buf name;
Buf param;
};
struct AstNodeRootExportDecl {
Buf type;
Buf name;
ZigList<AstNode *> *directives;
};
struct AstNodeCastExpr {
AstNode *expr;
AstNode *type;
};
enum PrefixOp {
PrefixOpInvalid,
PrefixOpBoolNot,
PrefixOpBinNot,
PrefixOpNegation,
PrefixOpAddressOf,
PrefixOpConstAddressOf,
PrefixOpDereference,
};
struct AstNodePrefixOpExpr {
PrefixOp prefix_op;
AstNode *primary_expr;
};
struct AstNodeUse {
Buf path;
ZigList<AstNode *> *directives;
};
struct AstNodeIfBoolExpr {
AstNode *condition;
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
};
struct AstNodeIfVarExpr {
AstNodeVariableDeclaration var_decl;
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
};
struct AstNodeWhileExpr {
AstNode *condition;
AstNode *body;
};
struct AstNodeLabel {
Buf name;
};
struct AstNodeGoto {
Buf name;
};
struct AsmOutput {
Buf asm_symbolic_name;
Buf constraint;
Buf variable_name;
AstNode *return_type; // null unless "=r" and return
};
struct AsmInput {
Buf asm_symbolic_name;
Buf constraint;
AstNode *expr;
};
struct SrcPos {
int line;
int column;
};
struct AstNodeAsmExpr {
bool is_volatile;
Buf asm_template;
ZigList<SrcPos> offset_map;
ZigList<AsmToken> token_list;
ZigList<AsmOutput*> output_list;
ZigList<AsmInput*> input_list;
ZigList<Buf*> clobber_list;
int return_count; // populated by analyze
};
struct AstNodeStructDecl {
Buf name;
ZigList<AstNode *> fields;
ZigList<AstNode *> fns;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
};
struct AstNodeStructField {
Buf name;
AstNode *type;
ZigList<AstNode *> *directives;
};
struct AstNodeEnumDecl {
Buf name;
ZigList<AstNode *> fields;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
};
struct AstNodeEnumField {
Buf name;
ZigList<AstNode *> fields; // length 0 means simple enum
AstNode *val_expr;
};
struct AstNodeStringLiteral {
Buf buf;
bool c;
};
struct AstNodeCharLiteral {
uint8_t value;
};
enum NumLit {
NumLitF32,
NumLitF64,
NumLitF128,
NumLitU8,
NumLitU16,
NumLitU32,
NumLitU64,
NumLitI8,
NumLitI16,
NumLitI32,
NumLitI64,
NumLitCount
};
struct AstNodeNumberLiteral {
NumLit kind;
// overflow is true if when parsing the number, we discovered it would not
// fit without losing data in a uint64_t, int64_t, or double
bool overflow;
union {
uint64_t x_uint;
int64_t x_int;
double x_float;
} data;
};
struct AstNodeStructValueField {
Buf name;
AstNode *expr;
};
struct AstNodeStructValueExpr {
AstNode *type;
ZigList<AstNode *> fields;
};
struct AstNodeCompilerFnExpr {
Buf name;
AstNode *expr;
};
struct AstNodeCompilerFnType {
Buf name;
AstNode *type;
};
struct AstNode {
enum NodeType type;
int line;
int column;
uint32_t create_index; // for determinism purposes
CodeGenNode *codegen_node;
ImportTableEntry *owner;
union {
AstNodeRoot root;
AstNodeRootExportDecl root_export_decl;
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
AstNodeType type;
AstNodeParamDecl param_decl;
AstNodeBlock block;
AstNodeReturnExpr return_expr;
AstNodeVariableDeclaration variable_declaration;
AstNodeBinOpExpr bin_op_expr;
AstNodeExternBlock extern_block;
AstNodeDirective directive;
AstNodeCastExpr cast_expr;
AstNodePrefixOpExpr prefix_op_expr;
AstNodeFnCallExpr fn_call_expr;
AstNodeArrayAccessExpr array_access_expr;
AstNodeSliceExpr slice_expr;
AstNodeUse use;
AstNodeIfBoolExpr if_bool_expr;
AstNodeIfVarExpr if_var_expr;
AstNodeWhileExpr while_expr;
AstNodeLabel label;
AstNodeGoto go_to;
AstNodeAsmExpr asm_expr;
AstNodeFieldAccessExpr field_access_expr;
AstNodeStructDecl struct_decl;
AstNodeStructField struct_field;
AstNodeEnumDecl enum_decl;
AstNodeEnumField enum_field;
AstNodeStringLiteral string_literal;
AstNodeCharLiteral char_literal;
AstNodeNumberLiteral number_literal;
AstNodeStructValueExpr struct_val_expr;
AstNodeStructValueField struct_val_field;
AstNodeCompilerFnExpr compiler_fn_expr;
AstNodeCompilerFnType compiler_fn_type;
Buf symbol;
bool bool_literal;
} data;
};
enum AsmTokenId {
AsmTokenIdTemplate,
AsmTokenIdPercent,
AsmTokenIdVar,
};
struct AsmToken {
enum AsmTokenId id;
int start;
int end;
};
__attribute__ ((format (printf, 2, 3)))
void ast_token_error(Token *token, const char *format, ...);