zig/src/analyze.hpp

399 lines
11 KiB
C++
Raw Normal View History

2015-12-01 00:14:58 +08:00
/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef ZIG_ANALYZE_HPP
#define ZIG_ANALYZE_HPP
2015-12-09 05:15:34 +08:00
#include "codegen.hpp"
#include "hash_map.hpp"
#include "zig_llvm.hpp"
#include "errmsg.hpp"
2015-12-01 00:14:58 +08:00
2015-12-09 05:15:34 +08:00
struct FnTableEntry;
2015-12-04 01:56:17 +08:00
struct BlockContext;
2015-12-09 05:15:34 +08:00
struct TypeTableEntry;
2015-12-15 14:10:18 +08:00
struct VariableTableEntry;
struct CastNode;
2015-12-24 15:00:23 +08:00
struct StructValExprNode;
2015-12-09 05:15:34 +08:00
struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
bool is_restrict;
2015-12-09 05:15:34 +08:00
};
struct TypeTableEntryInt {
bool is_signed;
};
2015-12-09 05:47:17 +08:00
struct TypeTableEntryArray {
TypeTableEntry *child_type;
uint64_t len;
};
struct TypeStructField {
Buf *name;
TypeTableEntry *type_entry;
};
struct TypeTableEntryStruct {
2015-12-17 08:11:35 +08:00
AstNode *decl_node;
bool is_packed;
int field_count;
TypeStructField *fields;
uint64_t size_bytes;
2016-01-05 12:42:35 +08:00
bool is_invalid; // true if any fields are invalid
2016-01-06 16:28:58 +08:00
bool is_unknown_size_array;
2016-01-05 07:57:22 +08:00
// 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;
2015-12-09 05:47:17 +08:00
};
struct TypeTableEntryNumLit {
NumLit kind;
};
2015-12-27 06:43:40 +08:00
struct TypeTableEntryMaybe {
TypeTableEntry *child_type;
};
2015-12-09 05:15:34 +08:00
enum TypeTableEntryId {
TypeTableEntryIdInvalid,
TypeTableEntryIdVoid,
TypeTableEntryIdBool,
TypeTableEntryIdUnreachable,
TypeTableEntryIdInt,
TypeTableEntryIdFloat,
TypeTableEntryIdPointer,
TypeTableEntryIdArray,
TypeTableEntryIdStruct,
TypeTableEntryIdNumberLiteral,
2015-12-27 06:43:40 +08:00
TypeTableEntryIdMaybe,
2015-12-09 05:15:34 +08:00
};
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;
2015-12-09 05:47:17 +08:00
TypeTableEntryArray array;
TypeTableEntryStruct structure;
TypeTableEntryNumLit num_lit;
2015-12-27 06:43:40 +08:00
TypeTableEntryMaybe maybe;
2015-12-09 05:15:34 +08:00
} 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 - restrict
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - restrict
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
TypeTableEntry *maybe_parent;
2015-12-09 05:15:34 +08:00
};
struct ImportTableEntry {
AstNode *root;
Buf *path; // relative to root_source_dir
LLVMZigDIFile *di_file;
Buf *source_code;
ZigList<int> *line_offsets;
BlockContext *block_context;
2015-12-09 05:15:34 +08:00
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
2016-01-04 18:52:37 +08:00
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
2015-12-09 05:15:34 +08:00
};
struct LabelTableEntry {
AstNode *label_node;
LLVMBasicBlockRef basic_block;
bool used;
bool entered_from_fallthrough;
};
2015-12-11 06:34:38 +08:00
enum FnAttrId {
FnAttrIdNaked,
FnAttrIdAlwaysInline,
};
2015-12-09 05:15:34 +08:00
struct FnTableEntry {
LLVMValueRef fn_value;
AstNode *proto_node;
AstNode *fn_def_node;
bool is_extern;
bool internal_linkage;
unsigned calling_convention;
ImportTableEntry *import_entry;
2015-12-11 06:34:38 +08:00
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;
2015-12-09 05:15:34 +08:00
// reminder: hash tables must be initialized before use
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
};
enum BuiltinFnId {
BuiltinFnIdInvalid,
BuiltinFnIdArithmeticWithOverflow,
};
struct BuiltinFnEntry {
BuiltinFnId id;
Buf name;
int param_count;
TypeTableEntry *return_type;
TypeTableEntry **param_types;
LLVMValueRef fn_val;
};
2015-12-09 05:15:34 +08:00
struct CodeGen {
LLVMModuleRef module;
ZigList<ErrorMsg*> errors;
LLVMBuilderRef builder;
LLVMZigDIBuilder *dbuilder;
LLVMZigDICompileUnit *compile_unit;
ZigList<Buf *> lib_search_paths;
2015-12-09 05:15:34 +08:00
// 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;
2015-12-09 05:15:34 +08:00
struct {
TypeTableEntry *entry_bool;
TypeTableEntry *entry_u8;
2016-01-04 09:17:50 +08:00
TypeTableEntry *entry_u16;
2015-12-16 09:21:59 +08:00
TypeTableEntry *entry_u32;
TypeTableEntry *entry_u64;
2015-12-16 08:11:44 +08:00
TypeTableEntry *entry_i8;
2016-01-04 09:17:50 +08:00
TypeTableEntry *entry_i16;
2015-12-09 05:15:34 +08:00
TypeTableEntry *entry_i32;
TypeTableEntry *entry_i64;
2015-12-11 06:34:38 +08:00
TypeTableEntry *entry_isize;
TypeTableEntry *entry_usize;
2015-12-09 05:15:34 +08:00
TypeTableEntry *entry_f32;
TypeTableEntry *entry_f64;
TypeTableEntry *entry_c_string_literal;
2015-12-09 05:15:34 +08:00
TypeTableEntry *entry_void;
TypeTableEntry *entry_unreachable;
TypeTableEntry *entry_invalid;
} builtin_types;
TypeTableEntry *num_lit_types[NumLitCount];
2015-12-09 05:15:34 +08:00
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;
2015-12-09 05:15:34 +08:00
CodeGenBuildType build_type;
LLVMTargetMachineRef target_machine;
LLVMZigDIFile *dummy_di_file;
2015-12-09 05:15:34 +08:00
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;
2015-12-15 14:10:18 +08:00
ZigList<VariableTableEntry *> global_vars;
2015-12-09 05:15:34 +08:00
OutType out_type;
FnTableEntry *cur_fn;
BlockContext *cur_block_context;
ZigList<LLVMBasicBlockRef> break_block_stack;
ZigList<LLVMBasicBlockRef> continue_block_stack;
2015-12-09 05:15:34 +08:00
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;
2016-01-04 18:31:57 +08:00
ImportTableEntry *bootstrap_import;
LLVMValueRef memcpy_fn_val;
2016-01-04 18:31:57 +08:00
bool error_during_imports;
2015-12-09 05:15:34 +08:00
};
2015-12-15 14:10:18 +08:00
struct VariableTableEntry {
2015-12-09 05:15:34 +08:00
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 {
2015-12-15 14:10:18 +08:00
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
FnTableEntry *fn_entry; // null at the module scope
BlockContext *parent; // null when this is the root
2015-12-15 14:10:18 +08:00
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
ZigList<CastNode *> cast_expr_alloca_list;
2015-12-24 15:00:23 +08:00
ZigList<StructValExprNode *> struct_val_expr_alloca_list;
AstNode *parent_loop_node;
AstNode *next_child_parent_loop_node;
2015-12-09 05:15:34 +08:00
LLVMZigDIScope *di_scope;
};
struct TypeNode {
TypeTableEntry *entry;
};
struct FnProtoNode {
FnTableEntry *fn_table_entry;
};
struct FnDefNode {
TypeTableEntry *implicit_return_type;
BlockContext *block_context;
bool skip;
};
struct AssignNode {
2015-12-15 14:10:18 +08:00
VariableTableEntry *var_entry;
2015-12-09 05:15:34 +08:00
};
struct BlockNode {
BlockContext *block_context;
};
struct StructDeclNode {
TypeTableEntry *type_entry;
};
struct FieldAccessNode {
int field_index;
TypeStructField *type_struct_field;
};
enum CastOp {
2016-01-02 15:06:06 +08:00
CastOpNothing,
CastOpPtrToInt,
CastOpIntWidenOrShorten,
2016-01-06 16:28:58 +08:00
CastOpToUnknownSizeArray,
2016-01-02 15:06:06 +08:00
CastOpMaybeWrap,
2016-01-02 18:38:45 +08:00
CastOpPointerReinterpret,
};
struct CastNode {
CastOp op;
2015-12-13 13:55:29 +08:00
// if op is CastOpArrayToString, this will be a pointer to
// the string struct on the stack
LLVMValueRef ptr;
2016-01-02 15:06:06 +08:00
TypeTableEntry *after_type;
AstNode *source_node;
};
2015-12-16 08:11:44 +08:00
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
2016-01-02 15:06:06 +08:00
CastNode implicit_cast; // happens first
CastNode implicit_maybe_cast; // happens second
2015-12-16 08:11:44 +08:00
};
struct NumberLiteralNode {
TypeTableEntry *resolved_type;
};
struct VarDeclNode {
TypeTableEntry *type;
};
2015-12-24 15:00:23 +08:00
struct StructValFieldNode {
int index;
};
struct StructValExprNode {
TypeTableEntry *type_entry;
LLVMValueRef ptr;
AstNode *source_node;
};
2016-01-02 15:06:06 +08:00
struct IfVarNode {
BlockContext *block_context;
};
struct ParamDeclNode {
VariableTableEntry *variable;
};
2016-01-04 18:31:57 +08:00
struct ImportNode {
ImportTableEntry *import;
};
struct WhileNode {
bool contains_break;
};
struct FnCallNode {
BuiltinFnEntry *builtin_fn;
};
2015-12-09 05:15:34 +08:00
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
2015-12-24 15:00:23 +08:00
StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
// note: I've been using this field on some non-struct val expressions too.
2015-12-24 15:00:23 +08:00
StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
2016-01-02 15:06:06 +08:00
IfVarNode if_var_node; // for NodeTypeStructValueExpr
ParamDeclNode param_decl_node; // for NodeTypeParamDecl
2016-01-04 18:31:57 +08:00
ImportNode import_node; // for NodeTypeUse
WhileNode while_node; // for NodeTypeWhileExpr
FnCallNode fn_call_node; // for NodeTypeFnCallExpr
2015-12-09 05:15:34 +08:00
} data;
ExprNode expr_node; // for all the expression nodes
};
2015-12-01 13:53:37 +08:00
void semantic_analyze(CodeGen *g);
2015-12-01 17:29:21 +08:00
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
2016-01-04 18:31:57 +08:00
void alloc_codegen_node(AstNode *node);
2015-12-09 05:15:34 +08:00
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_restrict);
2015-12-15 14:10:18 +08:00
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
2015-12-01 00:14:58 +08:00
#endif