mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
3814 lines
90 KiB
C
3814 lines
90 KiB
C
// Copyright (c) 2019-2023 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by the GNU LGPLv3.0 license
|
|
// a copy of which can be found in the LICENSE file.
|
|
|
|
#include "../utils/common.h"
|
|
#include "../utils/lib.h"
|
|
#include "../build/build.h"
|
|
#include "compiler.h"
|
|
#include "enums.h"
|
|
#include "target.h"
|
|
#include "utils/malloc.h"
|
|
#include "subprocess.h"
|
|
#include <float.h>
|
|
|
|
typedef double Real;
|
|
typedef uint64_t ByteSize;
|
|
typedef uint32_t TypeSize;
|
|
typedef int32_t IndexDiff;
|
|
typedef int32_t ArrayIndex;
|
|
typedef uint16_t StructIndex;
|
|
typedef uint32_t AlignSize;
|
|
typedef int32_t ScopeId;
|
|
typedef uint32_t ArraySize;
|
|
typedef uint64_t BitSize;
|
|
typedef uint16_t FileId;
|
|
|
|
#define INT5_MAX 15
|
|
#define INT12_MAX 2047
|
|
#define INT20_MAX 524287
|
|
#define INT5_MIN -16
|
|
#define INT12_MIN -2048
|
|
#define INT20_MIN (-INT20_MAX-1)
|
|
#define UINT5_MAX 31
|
|
#define UINT12_MAX 4095
|
|
#define UINT20_MAX 1048575U
|
|
|
|
#define MAX_ARRAYINDEX INT32_MAX
|
|
#define MAX_FIXUPS 0xFFFFF
|
|
#define MAX_HASH_SIZE (512 * 1024 * 1024)
|
|
#define INVALID_SPAN ((SourceSpan){ .row = 0 })
|
|
#define MAX_SCOPE_DEPTH 0x100
|
|
#define MAX_STRING_BUFFER 0x10000
|
|
#define INITIAL_SYMBOL_MAP 0x10000
|
|
#define INITIAL_GENERIC_SYMBOL_MAP 0x1000
|
|
#define MAX_INCLUDE_DIRECTIVES 2048
|
|
#define MAX_MACRO_ITERATIONS 0xFFFFFF
|
|
#define MAX_PARAMS 255
|
|
#define MAX_BITSTRUCT 0x1000
|
|
#define MAX_MEMBERS ((StructIndex)1) << 15
|
|
#define MAX_ALIGNMENT ((ArrayIndex)(((uint64_t)2) << 28))
|
|
#define MAX_PRIORITY 0xFFFF
|
|
#define MAX_TYPE_SIZE UINT32_MAX
|
|
#define MAX_GLOBAL_DECL_STACK (65536)
|
|
#define MEMCMP_INLINE_REGS 8
|
|
#define UINT128_MAX ((Int128) { UINT64_MAX, UINT64_MAX })
|
|
#define INT128_MAX ((Int128) { INT64_MAX, UINT64_MAX })
|
|
#define INT128_MIN ((Int128) { (uint64_t)INT64_MIN, 0 })
|
|
#define STDIN_FILE_ID 0xFFFF
|
|
#define ABI_TYPE_EMPTY ((AbiType) { .type = NULL })
|
|
#define RANGE_EXTEND_PREV(x) do { (x)->span = extend_span_with_token((x)->span, c->prev_span); } while (0)
|
|
#define PRINT_ERROR_AT(_node, ...) print_error_at((_node)->span, __VA_ARGS__)
|
|
#define RETURN_PRINT_ERROR_AT(_val, _node, ...) do { print_error_at((_node)->span, __VA_ARGS__); return _val; } while (0)
|
|
#define PRINT_ERROR_HERE(...) print_error_at(c->span, __VA_ARGS__)
|
|
#define RETURN_PRINT_ERROR_HERE(...) do { print_error_at(c->span, __VA_ARGS__); return false; } while (0)
|
|
#define PRINT_ERROR_LAST(...) print_error_at(c->prev_span, __VA_ARGS__)
|
|
#define RETURN_PRINT_ERROR_LAST(...) do { print_error_at(c->prev_span, __VA_ARGS__); return false; } while (0)
|
|
#define SEMA_NOTE(_node, ...) sema_note_prev_at((_node)->span, __VA_ARGS__)
|
|
#define SEMA_DEPRECATED(_node, ...) do { if (!compiler.build.silence_deprecation) \
|
|
sema_note_prev_at((_node)->span, __VA_ARGS__); } while (0)
|
|
|
|
#define EXPAND_EXPR_STRING(str_) (str_)->const_expr.bytes.len, (str_)->const_expr.bytes.ptr
|
|
#define TABLE_MAX_LOAD 0.5
|
|
|
|
typedef struct Ast_ Ast;
|
|
typedef struct Decl_ Decl;
|
|
typedef struct TypeInfo_ TypeInfo;
|
|
typedef struct Expr_ Expr;
|
|
typedef struct Module_ Module;
|
|
typedef struct Type_ Type;
|
|
typedef Type CanonicalType;
|
|
typedef struct Signature_ Signature;
|
|
typedef struct ConstInitializer_ ConstInitializer;
|
|
typedef struct CompilationUnit_ CompilationUnit;
|
|
typedef unsigned AstId;
|
|
typedef unsigned ExprId;
|
|
typedef unsigned DeclId;
|
|
typedef unsigned TypeInfoId;
|
|
typedef struct SemaContext_ SemaContext;
|
|
|
|
typedef struct Int128_
|
|
{
|
|
uint64_t high;
|
|
uint64_t low;
|
|
} Int128;
|
|
|
|
typedef struct
|
|
{
|
|
Int128 i;
|
|
TypeKind type;
|
|
} Int;
|
|
|
|
typedef struct
|
|
{
|
|
Real f;
|
|
TypeKind type;
|
|
} Float;
|
|
|
|
struct ConstInitializer_
|
|
{
|
|
ConstInitType kind;
|
|
// Type, should always be flattened
|
|
Type *type;
|
|
union
|
|
{
|
|
ConstInitializer **init_struct;
|
|
Expr *init_value;
|
|
struct
|
|
{
|
|
ConstInitializer *element;
|
|
ArrayIndex index;
|
|
} init_union;
|
|
struct
|
|
{
|
|
ConstInitializer **elements;
|
|
} init_array;
|
|
ConstInitializer **init_array_full;
|
|
struct
|
|
{
|
|
ConstInitializer *element;
|
|
ArrayIndex index;
|
|
} init_array_value;
|
|
};
|
|
};
|
|
|
|
|
|
typedef struct
|
|
{
|
|
ConstKind const_kind : 8;
|
|
bool is_character : 1;
|
|
bool is_hex : 1;
|
|
union
|
|
{
|
|
Float fxx;
|
|
Int ixx;
|
|
uint64_t ptr;
|
|
bool b;
|
|
struct
|
|
{
|
|
const char *ptr;
|
|
ArraySize len;
|
|
} bytes;
|
|
Expr *expr_ref;
|
|
Decl *global_ref;
|
|
Decl *enum_err_val;
|
|
Type *typeid;
|
|
ConstInitializer *initializer;
|
|
ConstInitializer *slice_init;
|
|
Expr **untyped_list;
|
|
struct
|
|
{
|
|
AlignSize offset;
|
|
AlignSize align;
|
|
Decl *decl;
|
|
} member;
|
|
};
|
|
} ExprConst;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
FileId file_id;
|
|
const char *contents;
|
|
size_t content_len;
|
|
char *name;
|
|
char *dir_path;
|
|
const char *full_path;
|
|
} File;
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
FileId file_id;
|
|
unsigned char length;
|
|
unsigned char col;
|
|
uint32_t row;
|
|
};
|
|
uint64_t a;
|
|
} SourceSpan;
|
|
|
|
|
|
static_assert(sizeof(SourceSpan) == 8, "Expected 8 bytes");
|
|
|
|
typedef struct
|
|
{
|
|
const char *key;
|
|
void *value;
|
|
} SEntry;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t count;
|
|
uint32_t capacity;
|
|
uint32_t max_load;
|
|
SEntry *entries;
|
|
} STable;
|
|
|
|
typedef struct SEntry2_
|
|
{
|
|
void *key;
|
|
void *value;
|
|
struct SEntry2_ *next;
|
|
} HTEntry;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t mask;
|
|
HTEntry **entries;
|
|
} HTable;
|
|
|
|
|
|
typedef struct Path_
|
|
{
|
|
SourceSpan span;
|
|
const char *module;
|
|
uint32_t len;
|
|
} Path;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
unsigned bitsize : 8;
|
|
unsigned bytesize : 8;
|
|
unsigned abi_alignment : 8;
|
|
unsigned pref_alignment : 8;
|
|
} TypeBuiltin;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
Type *base;
|
|
ArraySize len;
|
|
} TypeArray;
|
|
|
|
typedef struct
|
|
{
|
|
bool nodiscard : 1;
|
|
bool maydiscard : 1;
|
|
bool is_pure : 1;
|
|
bool noreturn : 1;
|
|
bool always_const : 1;
|
|
} CalleeAttributes;
|
|
|
|
typedef struct
|
|
{
|
|
Decl *decl;
|
|
Signature *signature;
|
|
struct FunctionPrototype_ *prototype;
|
|
} TypeFunction;
|
|
|
|
struct Type_
|
|
{
|
|
TypeKind type_kind;
|
|
CanonicalType *canonical;
|
|
const char *name;
|
|
union
|
|
{
|
|
Type **type_cache;
|
|
Type *func_ptr;
|
|
};
|
|
union
|
|
{
|
|
void *backend_type;
|
|
struct
|
|
{
|
|
uint16_t tb_set;
|
|
uint16_t tb_type;
|
|
};
|
|
};
|
|
void *backend_typeid;
|
|
void *backend_debug_type;
|
|
union
|
|
{
|
|
// Error, Struct, Union, Typedef, Member, Bitstruct
|
|
Decl *decl;
|
|
// int, float, bool
|
|
TypeBuiltin builtin;
|
|
// Type[], Type[*], Type[123], Type[<123>] or Type<[123]>
|
|
TypeArray array;
|
|
// fn TypeR Type1(Type2, Type3, ...)
|
|
TypeFunction function;
|
|
// Type*
|
|
Type *pointer;
|
|
// Optional
|
|
Type *optional;
|
|
};
|
|
};
|
|
|
|
|
|
struct TypeInfo_
|
|
{
|
|
ResolveStatus resolve_status : 3;
|
|
TypeInfoKind kind : 6;
|
|
bool optional : 1;
|
|
bool in_def : 1;
|
|
TypeInfoCompressedKind subtype : 4;
|
|
Type *type;
|
|
SourceSpan span;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
const char *name;
|
|
Path *path;
|
|
} unresolved;
|
|
Expr *unresolved_type_expr;
|
|
struct
|
|
{
|
|
TypeInfo *base;
|
|
Expr *len;
|
|
} array;
|
|
TypeInfo *pointer;
|
|
struct
|
|
{
|
|
TypeInfo *base;
|
|
Expr **params;
|
|
} generic;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
Path *path;
|
|
const char *name;
|
|
SourceSpan span;
|
|
AttributeType attr_kind : 8;
|
|
bool is_custom : 1;
|
|
Expr **exprs;
|
|
} Attr;
|
|
|
|
typedef struct
|
|
{
|
|
Attr **tags;
|
|
const char *deprecated;
|
|
const char **links;
|
|
const char *section;
|
|
const char *wasm_module;
|
|
SourceSpan overload;
|
|
} ResolvedAttrData;
|
|
|
|
typedef struct
|
|
{
|
|
Path *path;
|
|
bool import_private_as_public;
|
|
bool is_non_recurse;
|
|
Module *module;
|
|
} ImportDecl;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *filename;
|
|
} IncludeDecl;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *filename;
|
|
Expr **args;
|
|
Expr *stdin_string;
|
|
} ExecDecl;
|
|
|
|
typedef struct
|
|
{
|
|
Decl **members;
|
|
DeclId parent;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
TypeSize size;
|
|
DeclId padded_decl_id;
|
|
StructIndex union_rep;
|
|
AlignSize padding : 16;
|
|
};
|
|
struct
|
|
{
|
|
TypeInfo *container_type;
|
|
bool msb0 : 1;
|
|
bool big_endian : 1;
|
|
bool little_endian : 1;
|
|
bool overlap : 1;
|
|
bool consecutive : 1;
|
|
};
|
|
};
|
|
} StructDecl;
|
|
|
|
|
|
|
|
typedef struct VarDecl_
|
|
{
|
|
TypeInfoId type_info;
|
|
uint16_t va_index;
|
|
VarDeclKind kind : 8;
|
|
bool shadow : 1;
|
|
bool vararg : 1;
|
|
bool is_static : 1;
|
|
bool is_read : 1;
|
|
bool not_null : 1;
|
|
bool out_param : 1;
|
|
bool in_param : 1;
|
|
bool is_written : 1;
|
|
bool is_addr : 1;
|
|
bool is_threadlocal : 1;
|
|
bool no_init : 1;
|
|
bool no_alias : 1;
|
|
bool bit_is_expr : 1;
|
|
union
|
|
{
|
|
Expr *init_expr;
|
|
Decl *alias;
|
|
};
|
|
union
|
|
{
|
|
int32_t index;
|
|
struct
|
|
{
|
|
SemaContext *context;
|
|
SourceSpan span;
|
|
} hash_var;
|
|
struct
|
|
{
|
|
void *backend_debug_ref;
|
|
union
|
|
{
|
|
// Variable
|
|
void *optional_ref;
|
|
int tb_optional_reg;
|
|
};
|
|
};
|
|
struct
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
Expr *start;
|
|
Expr *end;
|
|
};
|
|
struct
|
|
{
|
|
unsigned start_bit;
|
|
unsigned end_bit;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
} VarDecl;
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
Expr **args;
|
|
uint32_t ordinal;
|
|
DeclId parent;
|
|
} EnumConstantDecl;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
Decl** values;
|
|
Decl** parameters;
|
|
TypeInfo *type_info;
|
|
} EnumDecl;
|
|
|
|
struct Signature_
|
|
{
|
|
CalleeAttributes attrs;
|
|
bool is_macro : 1;
|
|
bool is_at_macro : 1;
|
|
bool is_safemacro : 1;
|
|
Variadic variadic : 3;
|
|
CallABI abi : 8;
|
|
unsigned vararg_index;
|
|
TypeInfoId rtype;
|
|
Decl** params;
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
TypeInfoId type_parent;
|
|
Signature signature;
|
|
AstId body;
|
|
AstId docs;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
bool attr_inline : 1;
|
|
bool attr_noinline : 1;
|
|
bool attr_extname : 1;
|
|
bool attr_naked : 1;
|
|
bool attr_benchmark : 1;
|
|
bool attr_test : 1;
|
|
bool attr_winmain : 1;
|
|
bool attr_optional : 1;
|
|
bool attr_init : 1;
|
|
bool attr_finalizer : 1;
|
|
bool attr_interface_method : 1;
|
|
bool attr_dynamic : 1;
|
|
bool attr_nosanitize_address : 1;
|
|
bool attr_nosanitize_memory : 1;
|
|
bool attr_nosanitize_thread : 1;
|
|
bool is_lambda : 1;
|
|
bool in_macro : 1;
|
|
union
|
|
{
|
|
uint32_t priority;
|
|
DeclId interface_method;
|
|
DeclId default_method;
|
|
Decl **generated_lambda;
|
|
Decl **lambda_ct_parameters;
|
|
};
|
|
};
|
|
struct
|
|
{
|
|
DeclId body_param;
|
|
CompilationUnit *unit;
|
|
};
|
|
};
|
|
} FuncDecl;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
Decl **params;
|
|
Attr **attrs;
|
|
} AttrDecl;
|
|
|
|
typedef struct
|
|
{
|
|
bool is_func : 1;
|
|
bool is_redef : 1;
|
|
union
|
|
{
|
|
Decl *decl;
|
|
TypeInfo *type_info;
|
|
};
|
|
} TypedefDecl;
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
Expr *alias_expr;
|
|
Decl *alias;
|
|
};
|
|
} DefineDecl;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
AstId defer;
|
|
bool next_target : 1;
|
|
union
|
|
{
|
|
void *break_target;
|
|
int tb_break_target;
|
|
};
|
|
void *continue_target;
|
|
AstId scope_defer;
|
|
AstId parent;
|
|
} LabelDecl;
|
|
|
|
typedef struct Decl_
|
|
{
|
|
const char *name;
|
|
const char *extname;
|
|
SourceSpan span;
|
|
DeclKind decl_kind : 7;
|
|
ResolveStatus resolve_status : 3;
|
|
Visibility visibility : 3;
|
|
bool has_tag : 1;
|
|
bool is_packed : 1;
|
|
bool is_extern : 1;
|
|
bool is_substruct : 1;
|
|
bool has_variable_array : 1;
|
|
bool is_value : 1;
|
|
bool is_autoimport : 1;
|
|
bool has_extname : 1;
|
|
bool is_external_visible : 1;
|
|
bool is_weak : 1;
|
|
bool is_maybe_unused : 1;
|
|
bool is_must_use : 1;
|
|
bool will_reflect : 1;
|
|
bool obfuscate : 1;
|
|
bool is_dynamic : 1;
|
|
bool is_synthetic : 1;
|
|
bool is_export : 1;
|
|
bool is_live : 1;
|
|
bool no_strip : 1;
|
|
bool is_cond : 1;
|
|
bool is_if : 1;
|
|
bool attr_nopadding : 1;
|
|
bool attr_compact : 1;
|
|
bool resolved_attributes : 1;
|
|
OperatorOverload operator : 4;
|
|
union
|
|
{
|
|
void *backend_ref;
|
|
int tb_register;
|
|
void *backend_value;
|
|
void *tb_symbol;
|
|
bool in_init;
|
|
};
|
|
AlignSize offset;
|
|
AlignSize padding;
|
|
AlignSize alignment;
|
|
struct CompilationUnit_ *unit;
|
|
union
|
|
{
|
|
Attr **attributes;
|
|
ResolvedAttrData *attrs_resolved;
|
|
};
|
|
Type *type;
|
|
union
|
|
{
|
|
Decl** decl_list;
|
|
struct
|
|
{
|
|
TypeInfo **interfaces;
|
|
Decl **methods;
|
|
union
|
|
{
|
|
// Enums and Fault
|
|
EnumDecl enums;
|
|
TypeInfo *distinct;
|
|
// Unions, Struct, Bitstruct use strukt
|
|
StructDecl strukt;
|
|
Decl **interface_methods;
|
|
};
|
|
};
|
|
AttrDecl attr_decl;
|
|
Decl** body_params;
|
|
Ast *ct_assert_decl;
|
|
Ast *ct_echo_decl;
|
|
Decl** ct_else_decl;
|
|
Decl** decls;
|
|
DefineDecl define_decl;
|
|
EnumConstantDecl enum_constant;
|
|
ExecDecl exec_decl;
|
|
Expr* expand_decl;
|
|
Signature fntype_decl;
|
|
FuncDecl func_decl;
|
|
ImportDecl import;
|
|
IncludeDecl include;
|
|
LabelDecl label;
|
|
TypedefDecl typedef_decl;
|
|
VarDecl var;
|
|
};
|
|
} Decl;
|
|
|
|
// static_assert(sizeof(void*) != 8 || sizeof(Decl) == 136, "Decl has unexpected size.");
|
|
|
|
typedef enum RangeType
|
|
{
|
|
RANGE_DYNAMIC,
|
|
RANGE_CONST_END,
|
|
RANGE_CONST_LEN,
|
|
RANGE_CONST_RANGE,
|
|
} RangeType;
|
|
|
|
typedef struct
|
|
{
|
|
ResolveStatus status : 3;
|
|
RangeType range_type;
|
|
bool start_from_end : 1;
|
|
bool end_from_end : 1;
|
|
bool is_len : 1;
|
|
bool is_range : 1;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
ExprId start;
|
|
union
|
|
{
|
|
ExprId end;
|
|
ArrayIndex const_end;
|
|
};
|
|
};
|
|
struct
|
|
{
|
|
ArrayIndex start_index;
|
|
ArrayIndex len_index;
|
|
};
|
|
};
|
|
} Range;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId cond;
|
|
ExprId then_expr; // May be null for elvis!
|
|
ExprId else_expr;
|
|
bool grouped : 1;
|
|
} ExprTernary;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId left;
|
|
ExprId right;
|
|
BinaryOp operator : 8;
|
|
bool grouped : 1;
|
|
} ExprBinary;
|
|
|
|
typedef struct
|
|
{
|
|
Expr* expr;
|
|
UnaryOp operator : 8;
|
|
bool no_wrap : 1;
|
|
} ExprUnary;
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
ExprId function;
|
|
DeclId func_ref;
|
|
};
|
|
ExprId macro_body;
|
|
bool is_type_method : 1;
|
|
bool is_pointer_call : 1;
|
|
bool attr_force_inline : 1;
|
|
bool attr_force_noinline : 1;
|
|
bool is_builtin : 1;
|
|
bool is_func_ref : 1;
|
|
bool attr_pure : 1;
|
|
bool no_return : 1;
|
|
bool is_dynamic_dispatch : 1;
|
|
bool has_optional_arg : 1;
|
|
bool must_use : 1;
|
|
bool is_optional_return : 1;
|
|
bool va_is_splat : 1;
|
|
Expr **arguments;
|
|
union {
|
|
Expr **varargs;
|
|
Expr *vasplat;
|
|
};
|
|
} ExprCall;
|
|
|
|
typedef struct
|
|
{
|
|
Ast *body;
|
|
Decl **body_arguments;
|
|
} ExprMacroBody;
|
|
|
|
typedef struct {
|
|
bool start_from_end : 1;
|
|
ExprId expr;
|
|
} SubscriptIndex;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId expr;
|
|
SubscriptIndex index;
|
|
} ExprSubscript;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId expr;
|
|
Range range;
|
|
} ExprSlice;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId expr;
|
|
DeclId method;
|
|
ExprId index;
|
|
} ExprSubscriptAssign;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId left;
|
|
ExprId right;
|
|
} ExprSliceAssign;
|
|
|
|
typedef struct
|
|
{
|
|
bool raw_offset : 1;
|
|
ExprId ptr;
|
|
ExprId offset;
|
|
} ExprPointerOffset;
|
|
|
|
typedef struct
|
|
{
|
|
BuiltinAccessKind kind : 8;
|
|
ExprId inner;
|
|
} ExprBuiltinAccess;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *filename;
|
|
Expr *len;
|
|
} ExprEmbedExpr;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId parent;
|
|
Expr **parmeters;
|
|
} ExprGenericIdent;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *parent;
|
|
union
|
|
{
|
|
Expr *child;
|
|
Decl *ref;
|
|
};
|
|
} ExprAccess;
|
|
|
|
typedef struct DesignatorElement_
|
|
{
|
|
DesignatorType kind : 4;
|
|
union
|
|
{
|
|
Expr *field_expr;
|
|
struct
|
|
{
|
|
Expr *index_expr;
|
|
Expr *index_end_expr;
|
|
};
|
|
};
|
|
ArrayIndex index;
|
|
ArrayIndex index_end;
|
|
} DesignatorElement;
|
|
|
|
typedef struct
|
|
{
|
|
DesignatorElement **path;
|
|
Expr *value;
|
|
} ExprDesignator;
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
SourceSpan name_span;
|
|
Expr *value;
|
|
} ExprNamedArgument;
|
|
|
|
typedef struct
|
|
{
|
|
Decl *type;
|
|
TypeProperty property;
|
|
} ExprTypeCall;
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
Path *path;
|
|
const char *ident;
|
|
bool is_const;
|
|
};
|
|
struct
|
|
{
|
|
Decl *decl;
|
|
bool was_ref;
|
|
};
|
|
};
|
|
} ExprIdentifier;
|
|
|
|
typedef struct
|
|
{
|
|
SourceSpan loc;
|
|
Expr *inner;
|
|
} ExprDefaultArg;
|
|
|
|
typedef struct
|
|
{
|
|
const char *identifier;
|
|
bool is_ref : 1;
|
|
bool is_rvalue : 1;
|
|
Decl *decl;
|
|
} ExprIdentifierRaw;
|
|
|
|
typedef struct
|
|
{
|
|
TokenType token_type;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
Expr *main_var;
|
|
DesignatorElement **flat_path;
|
|
};
|
|
struct
|
|
{
|
|
TypeInfoId type_from;
|
|
TypeInfoId type_to;
|
|
};
|
|
};
|
|
} ExprCtCall;
|
|
|
|
typedef struct
|
|
{
|
|
AsmArgKind kind : 8;
|
|
unsigned short index : 16;
|
|
AsmOffsetType offset_type : 6;
|
|
bool neg_offset : 1;
|
|
union
|
|
{
|
|
struct {
|
|
union
|
|
{
|
|
const char *name;
|
|
Decl *ident_decl;
|
|
};
|
|
bool copy_output : 1;
|
|
bool early_clobber : 1;
|
|
bool is_input : 1;
|
|
} ident;
|
|
ExprId expr_id;
|
|
struct {
|
|
ExprId base;
|
|
ExprId idx;
|
|
uint64_t offset;
|
|
};
|
|
struct {
|
|
uint64_t value;
|
|
unsigned bits;
|
|
bool is_neg;
|
|
};
|
|
union
|
|
{
|
|
const char *name;
|
|
AsmRegister *ref;
|
|
} reg;
|
|
};
|
|
} ExprAsmArg;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
TokenType type : 16;
|
|
ExprId arg;
|
|
} ExprCtArg;
|
|
|
|
typedef struct
|
|
{
|
|
bool is_and;
|
|
Expr** args;
|
|
} ExprCtAndOr;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
CastKind kind : 8;
|
|
ExprId expr;
|
|
TypeInfoId type_info;
|
|
} ExprCast;
|
|
|
|
typedef struct
|
|
{
|
|
Expr **values;
|
|
Decl **declarations;
|
|
AstId first_stmt;
|
|
} ExprBodyExpansion;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
void *block_return_exit;
|
|
void *block_optional_exit;
|
|
void *block_error_var;
|
|
void *block_return_out;
|
|
} BlockExit;
|
|
|
|
typedef struct
|
|
{
|
|
AstId first_stmt;
|
|
BlockExit **block_exit_ref;
|
|
} ExprFuncBlock;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
AstId first_stmt;
|
|
bool is_noreturn : 1;
|
|
bool is_must_use : 1;
|
|
bool is_optional_return : 1;
|
|
bool had_optional_arg : 1;
|
|
Decl **params;
|
|
Decl *macro;
|
|
BlockExit **block_exit;
|
|
} ExprMacroBlock;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *initializer;
|
|
TypeInfo *type_info;
|
|
} ExprCompoundLiteral;
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
SourceSpan span;
|
|
} Label;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *inner;
|
|
AstId cleanup;
|
|
BlockExit **in_block;
|
|
} ExprGuard;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
Expr *variable;
|
|
TypeInfo *type;
|
|
};
|
|
struct
|
|
{
|
|
Decl *decl;
|
|
Expr *lhs;
|
|
};
|
|
};
|
|
Expr **exprs;
|
|
} ExprCatchUnwrap;
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
Expr *variable;
|
|
TypeInfo *type;
|
|
Expr *init;
|
|
};
|
|
struct
|
|
{
|
|
bool assign_existing : 1;
|
|
Expr *optional;
|
|
union
|
|
{
|
|
Decl *decl;
|
|
Expr *lhs;
|
|
};
|
|
};
|
|
};
|
|
} ExprTryUnwrap;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
const char *ident;
|
|
BuiltinFunction builtin;
|
|
} ExprBuiltin;
|
|
|
|
typedef struct
|
|
{
|
|
bool is_assign : 1;
|
|
bool is_deref : 1;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
const char *new_ident;
|
|
SourceSpan span;
|
|
Expr *any_expr;
|
|
};
|
|
Decl *variable;
|
|
};
|
|
} ExprAnySwitch;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId parent;
|
|
TypeIdInfoKind kind;
|
|
} ExprTypeidInfo;
|
|
|
|
typedef struct
|
|
{
|
|
ExprId parent;
|
|
const char *swizzle;
|
|
} ExprSwizzle;
|
|
|
|
typedef struct
|
|
{
|
|
bool is_assign;
|
|
ExprId expr;
|
|
TypeInfoId type;
|
|
} ExprCastable;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *inner;
|
|
SemaContext *context;
|
|
} ExprOtherContext;
|
|
|
|
struct Expr_
|
|
{
|
|
Type *type;
|
|
SourceSpan span;
|
|
ExprKind expr_kind : 8;
|
|
ResolveStatus resolve_status : 4;
|
|
union {
|
|
ExprAccess access_expr; // 16
|
|
ExprAnySwitch any_switch; // 32
|
|
ExprBinary binary_expr; // 12
|
|
ExprBodyExpansion body_expansion_expr; // 24
|
|
ExprBuiltinAccess builtin_access_expr; // 8
|
|
ExprBuiltin builtin_expr; // 16
|
|
ExprCall call_expr; // 40
|
|
ExprCast cast_expr; // 12
|
|
ExprCatchUnwrap catch_unwrap_expr; // 24
|
|
Expr** cond_expr; // 8
|
|
ExprConst const_expr; // 32
|
|
ExprCtArg ct_arg_expr;
|
|
ExprCtAndOr ct_and_or_expr;
|
|
Expr** ct_concat;
|
|
ExprOtherContext expr_other_context;
|
|
ExprCastable castable_expr;
|
|
ExprCtCall ct_call_expr; // 24
|
|
ExprIdentifierRaw ct_ident_expr; // 24
|
|
Decl *decl_expr; // 8
|
|
Expr** designated_init_list; // 8
|
|
ExprDesignator designator_expr; // 16
|
|
ExprNamedArgument named_argument_expr;
|
|
ExprEmbedExpr embed_expr; // 16
|
|
Expr** exec_expr; // 8
|
|
ExprAsmArg expr_asm_arg; // 24
|
|
ExprFuncBlock expr_block; // 4
|
|
ExprCompoundLiteral expr_compound_literal; // 16
|
|
Expr** expression_list; // 8
|
|
ExprGenericIdent generic_ident_expr;
|
|
ExprDefaultArg default_arg_expr;
|
|
ExprIdentifierRaw hash_ident_expr; // 24
|
|
ExprIdentifier identifier_expr; // 24
|
|
Expr** initializer_list; // 8
|
|
Expr *inner_expr; // 8
|
|
Decl *lambda_expr; // 8
|
|
ExprMacroBlock macro_block; // 24
|
|
ExprMacroBody macro_body_expr; // 16
|
|
Decl *member_get_expr; // 8
|
|
OperatorOverload overload_expr; // 4
|
|
ExprPointerOffset pointer_offset_expr;
|
|
ExprGuard rethrow_expr; // 16
|
|
ExprSliceAssign slice_assign_expr; // 8
|
|
ExprSubscriptAssign subscript_assign_expr;
|
|
ExprSubscript subscript_expr; // 12
|
|
ExprSlice slice_expr;
|
|
ExprSwizzle swizzle_expr;
|
|
ExprTernary ternary_expr; // 16
|
|
BuiltinDefine benchmark_hook_expr;
|
|
ExprTypeCall type_call_expr;
|
|
BuiltinDefine test_hook_expr;
|
|
Expr** try_unwrap_chain_expr; // 8
|
|
ExprTryUnwrap try_unwrap_expr; // 24
|
|
TypeInfo *type_expr; // 8
|
|
TypeInfo *typeid_expr; // 8
|
|
ExprTypeidInfo typeid_info_expr; // 8
|
|
ExprUnary unary_expr; // 16
|
|
Range vasplat_expr;
|
|
};
|
|
};
|
|
|
|
static_assert(sizeof(void*) != 8 || sizeof(Expr) == 56, "Expr not expected size");
|
|
|
|
typedef struct
|
|
{
|
|
AstId first_stmt;
|
|
AstId parent_defer;
|
|
} AstCompoundStmt;
|
|
|
|
typedef struct
|
|
{
|
|
Expr *expr; // May be NULL
|
|
AstId cleanup;
|
|
AstId cleanup_fail;
|
|
BlockExit** block_exit_ref; // For block exits
|
|
} AstReturnStmt;
|
|
|
|
typedef struct
|
|
{
|
|
DeclId label;
|
|
bool has_break : 1;
|
|
bool no_exit : 1;
|
|
bool skip_first : 1;
|
|
bool if_chain : 1;
|
|
bool jump : 1;
|
|
} FlowCommon;
|
|
|
|
typedef struct
|
|
{
|
|
FlowCommon flow;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
ExprId cond;
|
|
AstId then_body;
|
|
AstId else_body;
|
|
};
|
|
struct
|
|
{
|
|
union
|
|
{
|
|
void *break_block;
|
|
int tb_break_block;
|
|
};
|
|
} codegen;
|
|
};
|
|
} AstIfStmt;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
ExprId expr;
|
|
ExprId to_expr;
|
|
Ast *body;
|
|
void *backend_block;
|
|
} AstCaseStmt;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
FlowCommon flow;
|
|
Ast **cases;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
ExprId cond;
|
|
AstId defer;
|
|
Ast *scope_defer;
|
|
};
|
|
struct
|
|
{
|
|
void *exit_block;
|
|
union
|
|
{
|
|
struct {
|
|
void *block;
|
|
void *var;
|
|
} retry;
|
|
struct {
|
|
uint16_t count;
|
|
int16_t min_index;
|
|
int16_t default_index;
|
|
void *jmptable;
|
|
} jump;
|
|
};
|
|
} codegen;
|
|
};
|
|
} AstSwitchStmt;
|
|
|
|
typedef struct
|
|
{
|
|
FlowCommon flow;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
ExprId cond;
|
|
ExprId incr;
|
|
ExprId init;
|
|
AstId body;
|
|
};
|
|
struct
|
|
{
|
|
void *continue_block;
|
|
void *exit_block;
|
|
} codegen;
|
|
};
|
|
} AstForStmt;
|
|
|
|
typedef struct
|
|
{
|
|
FlowCommon flow;
|
|
bool index_by_ref : 1;
|
|
bool value_by_ref : 1;
|
|
bool iterator : 1;
|
|
bool is_reverse : 1;
|
|
CastKind cast : 8;
|
|
ExprId enumeration;
|
|
AstId body;
|
|
DeclId index;
|
|
DeclId variable;
|
|
} AstForeachStmt;
|
|
|
|
typedef struct
|
|
{
|
|
AstId prev_defer;
|
|
AstId body; // Compound statement
|
|
void *scope;
|
|
bool is_try : 1;
|
|
bool is_catch : 1;
|
|
} AstDeferStmt;
|
|
|
|
typedef struct AstCtIfStmt_
|
|
{
|
|
Expr *expr;
|
|
AstId elif;
|
|
AstId then;
|
|
} AstCtIfStmt;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
ExprId cond;
|
|
Ast **body;
|
|
} AstCtSwitchStmt;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
DeclId index;
|
|
DeclId value;
|
|
AstId body;
|
|
ExprId expr;
|
|
} AstCtForeachStmt;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
bool is_label : 1;
|
|
bool is_resolved : 1;
|
|
AstId defers;
|
|
union
|
|
{
|
|
Label label;
|
|
AstId ast;
|
|
};
|
|
} AstContinueBreakStmt;
|
|
|
|
typedef struct
|
|
{
|
|
AstId defer_id;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
Label label;
|
|
ExprId expr;
|
|
bool is_default;
|
|
};
|
|
struct
|
|
{
|
|
AstId case_switch_stmt;
|
|
Expr *switch_expr;
|
|
};
|
|
};
|
|
} AstNextcaseStmt;
|
|
|
|
typedef struct
|
|
{
|
|
const char *instruction;
|
|
const char *variant;
|
|
Expr **args;
|
|
} AstAsmStmt;
|
|
|
|
typedef struct
|
|
{
|
|
Clobbers clobbers;
|
|
const char *asm_block;
|
|
AstId asm_stmt;
|
|
ExprAsmArg **output_vars;
|
|
ExprAsmArg **input;
|
|
} AsmInlineBlock;
|
|
|
|
typedef struct
|
|
{
|
|
bool is_volatile : 1;
|
|
bool is_inline : 1;
|
|
bool is_goto : 1;
|
|
bool is_string : 1;
|
|
union
|
|
{
|
|
AsmInlineBlock *block;
|
|
ExprId asm_string;
|
|
};
|
|
|
|
} AstAsmBlock;
|
|
|
|
typedef struct
|
|
{
|
|
bool is_ensure;
|
|
ExprId message;
|
|
ExprId expr;
|
|
Expr **args;
|
|
} AstAssertStmt;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
bool resolved;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
TypeInfo *type;
|
|
const char *ident;
|
|
};
|
|
Decl *decl;
|
|
};
|
|
} AstDocFault;
|
|
|
|
typedef struct AstDocDirective_
|
|
{
|
|
ContractKind kind : 4;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
const char *name;
|
|
SourceSpan span;
|
|
InOutModifier modifier : 4;
|
|
bool by_ref : 1;
|
|
} param;
|
|
Ast **faults;
|
|
struct
|
|
{
|
|
Expr *decl_exprs;
|
|
const char *comment;
|
|
const char *expr_string;
|
|
} contract;
|
|
struct
|
|
{
|
|
const char *directive_name;
|
|
const char *rest_of_line;
|
|
} generic;
|
|
};
|
|
} AstContractStmt;
|
|
|
|
typedef struct Ast_
|
|
{
|
|
SourceSpan span;
|
|
AstId next;
|
|
AstKind ast_kind : 8;
|
|
union
|
|
{
|
|
FlowCommon flow; // Shared struct
|
|
AstAsmBlock asm_block_stmt;
|
|
AstAsmStmt asm_stmt;
|
|
AstAssertStmt assert_stmt; // 16
|
|
AstCaseStmt case_stmt; // 32
|
|
AstCompoundStmt compound_stmt; // 12
|
|
AstContinueBreakStmt contbreak_stmt;// 24
|
|
AstContractStmt contract_stmt; // 32
|
|
AstDocFault contract_fault; // 24
|
|
AstId ct_else_stmt; // 4
|
|
AstCtForeachStmt ct_foreach_stmt; // 40
|
|
AstCtIfStmt ct_if_stmt; // 24
|
|
AstCtSwitchStmt ct_switch_stmt; // 16
|
|
Decl *declare_stmt; // 8
|
|
Decl **decls_stmt;
|
|
AstDeferStmt defer_stmt; // 8
|
|
Expr *expr_stmt; // 8
|
|
Expr *expand_stmt; // 8
|
|
AstForStmt for_stmt; // 32
|
|
AstForeachStmt foreach_stmt; // 40
|
|
AstIfStmt if_stmt; // 32
|
|
AstNextcaseStmt nextcase_stmt; // 32
|
|
AstReturnStmt return_stmt; // 16
|
|
AstSwitchStmt switch_stmt; // 40
|
|
Decl *var_stmt; // 8
|
|
};
|
|
} Ast;
|
|
|
|
|
|
static_assert(sizeof(void*) != 8 || sizeof(Ast) == 56, "Not expected Ast size");
|
|
|
|
typedef struct Module_
|
|
{
|
|
Path *name;
|
|
// Extname in case a module is renamed externally
|
|
const char *extname;
|
|
|
|
const char **parameters;
|
|
bool is_external : 1;
|
|
bool is_c_library : 1;
|
|
bool is_exported : 1;
|
|
bool is_generic : 1;
|
|
bool no_extprefix : 1;
|
|
AnalysisStage stage : 6;
|
|
|
|
AstId contracts;
|
|
Decl** private_method_extensions;
|
|
HTable symbols;
|
|
struct CompilationUnit_ **units;
|
|
Module *generic_module;
|
|
Module *parent_module;
|
|
Module *top_module;
|
|
Module **sub_modules;
|
|
Decl **benchmarks;
|
|
Decl **tests;
|
|
Decl **lambdas_to_evaluate;
|
|
const char *generic_suffix;
|
|
} Module;
|
|
|
|
|
|
|
|
typedef struct DynamicScope_
|
|
{
|
|
ScopeId scope_id;
|
|
bool allow_dead_code : 1;
|
|
bool jump_end : 1;
|
|
bool is_dead : 1;
|
|
ScopeFlags flags;
|
|
unsigned label_start;
|
|
unsigned current_local;
|
|
AstId defer_last;
|
|
AstId defer_start;
|
|
Ast *in_defer;
|
|
unsigned depth;
|
|
} DynamicScope;
|
|
|
|
|
|
typedef struct
|
|
{
|
|
const char *lex_start;
|
|
size_t lex_len;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
const char *string;
|
|
size_t strlen;
|
|
};
|
|
struct
|
|
{
|
|
Float value;
|
|
};
|
|
struct
|
|
{
|
|
bool is_base64 : 1;
|
|
uint64_t bytes_len : 63;
|
|
};
|
|
struct
|
|
{
|
|
Int128 char_value;
|
|
char width;
|
|
};
|
|
};
|
|
} TokenData;
|
|
|
|
typedef struct
|
|
{
|
|
struct ParseContext_ *context;
|
|
const char *file_begin;
|
|
const char *lexing_start;
|
|
const char *current;
|
|
uint32_t current_row;
|
|
uint32_t start_row;
|
|
const char *line_start;
|
|
const char *start_row_start;
|
|
File *file;
|
|
TokenData data;
|
|
SourceSpan tok_span;
|
|
TokenType token_type;
|
|
LexMode mode;
|
|
} Lexer;
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t count;
|
|
uint32_t capacity;
|
|
uint32_t max_load;
|
|
DeclId *entries;
|
|
} DeclTable;
|
|
|
|
struct CompilationUnit_
|
|
{
|
|
Module *module;
|
|
File *file;
|
|
Decl **imports;
|
|
Decl **types;
|
|
Decl **functions;
|
|
Decl **lambdas;
|
|
Decl **enums;
|
|
Decl **attributes;
|
|
Decl **faulttypes;
|
|
const char **links;
|
|
Visibility default_visibility;
|
|
Attr *if_attr;
|
|
bool export_by_default;
|
|
bool is_interface_file;
|
|
bool benchmark_by_default;
|
|
bool test_by_default;
|
|
Attr **attr_links;
|
|
Decl **generic_defines;
|
|
Decl **ct_asserts;
|
|
Decl **ct_echos;
|
|
Decl **ct_includes;
|
|
Decl **vars;
|
|
Decl **macros;
|
|
Decl **methods_to_register;
|
|
Decl **methods;
|
|
Decl **macro_methods;
|
|
Decl **global_decls;
|
|
Decl **global_cond_decls;
|
|
Decl *main_function;
|
|
HTable local_symbols;
|
|
int lambda_count;
|
|
Decl **local_method_extensions;
|
|
TypeInfo **check_type_variable_array;
|
|
struct
|
|
{
|
|
void *debug_file;
|
|
void *debug_compile_unit;
|
|
} llvm;
|
|
};
|
|
|
|
typedef struct ParseContext_
|
|
{
|
|
TokenData data;
|
|
TokenType tok;
|
|
SourceSpan span;
|
|
SourceSpan prev_span;
|
|
CompilationUnit *unit;
|
|
Lexer lexer;
|
|
} ParseContext;
|
|
|
|
typedef struct
|
|
{
|
|
CallEnvKind kind : 8;
|
|
bool ensures : 1;
|
|
bool pure : 1;
|
|
SourceSpan in_if_resolution;
|
|
Decl **opt_returns;
|
|
union
|
|
{
|
|
Decl *attr_declaration;
|
|
Decl *current_function;
|
|
};
|
|
} CallEnv;
|
|
|
|
typedef struct InliningSpan_
|
|
{
|
|
SourceSpan span;
|
|
struct InliningSpan_ *prev;
|
|
} InliningSpan;
|
|
|
|
struct SemaContext_
|
|
{
|
|
// Evaluated in this.
|
|
CompilationUnit *unit;
|
|
// Compiled in this unit.
|
|
CompilationUnit *compilation_unit;
|
|
CallEnv call_env;
|
|
Decl *current_macro;
|
|
InliningSpan *inlined_at;
|
|
ScopeId scope_id;
|
|
unsigned macro_call_depth;
|
|
Ast *break_target;
|
|
AstId break_defer;
|
|
Ast *continue_target;
|
|
AstId continue_defer;
|
|
AstId block_return_defer;
|
|
Ast *next_target;
|
|
Ast *next_switch;
|
|
AstId next_defer;
|
|
struct
|
|
{
|
|
uint32_t original_inline_line;
|
|
Module *original_module;
|
|
Decl **yield_params;
|
|
Ast *yield_body;
|
|
BlockExit** block_exit_ref;
|
|
Type *expected_block_type;
|
|
Ast **returns;
|
|
// Reusable returns cache.
|
|
Ast **returns_cache;
|
|
Expr **macro_varargs;
|
|
Decl **macro_params;
|
|
bool macro_has_ensures;
|
|
Decl** ct_locals;
|
|
};
|
|
Type *rtype;
|
|
SemaContext *yield_context;
|
|
Decl** locals;
|
|
DynamicScope active_scope;
|
|
Expr *return_expr;
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
union
|
|
{
|
|
Type *type;
|
|
uintptr_t int_bits_plus_1;
|
|
};
|
|
} AbiType;
|
|
|
|
typedef struct ABIArgInfo_
|
|
{
|
|
ArrayIndex param_index_start : 16;
|
|
ArrayIndex param_index_end : 16;
|
|
ABIKind kind : 6;
|
|
struct
|
|
{
|
|
bool by_reg : 1;
|
|
bool zeroext : 1;
|
|
bool signext : 1;
|
|
bool realign : 1;
|
|
bool by_val : 1;
|
|
} attributes;
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
AbiType lo;
|
|
AbiType hi;
|
|
} direct_pair;
|
|
struct
|
|
{
|
|
uint8_t offset_hi;
|
|
bool packed;
|
|
Type *lo;
|
|
Type *hi;
|
|
} coerce_expand;
|
|
Type *direct_coerce_type;
|
|
uint8_t direct_struct_expand;
|
|
struct
|
|
{
|
|
// We may request a certain alignment of the parameters.
|
|
AlignSize alignment;
|
|
Type *type;
|
|
} indirect;
|
|
};
|
|
|
|
} ABIArgInfo;
|
|
|
|
typedef struct FunctionPrototype_
|
|
{
|
|
CallABI call_abi : 4;
|
|
bool raw_variadic : 1;
|
|
bool use_win64 : 1;
|
|
bool is_optional : 1;
|
|
bool ret_by_ref : 1;
|
|
bool is_resolved : 1;
|
|
unsigned short vararg_index;
|
|
Type *rtype;
|
|
Type **param_types;
|
|
Decl **param_copy;
|
|
Type **varargs;
|
|
Type *ret_by_ref_type;
|
|
Type *abi_ret_type;
|
|
ABIArgInfo *ret_abi_info;
|
|
ABIArgInfo *ret_by_ref_abi_info;
|
|
ABIArgInfo **abi_args;
|
|
ABIArgInfo **abi_varargs;
|
|
Type *raw_type;
|
|
} FunctionPrototype;
|
|
|
|
typedef struct
|
|
{
|
|
Decl *ambiguous_other_decl;
|
|
Decl *private_decl;
|
|
Decl *maybe_decl;
|
|
Decl *found;
|
|
Path *path;
|
|
SourceSpan span;
|
|
const char *symbol;
|
|
Module *path_found;
|
|
bool suppress_error;
|
|
} NameResolve;
|
|
|
|
typedef struct
|
|
{
|
|
void *original;
|
|
void *new_ptr;
|
|
} CopyFixup;
|
|
|
|
typedef struct CopyStruct_
|
|
{
|
|
CopyFixup fixups[MAX_FIXUPS];
|
|
CopyFixup *current_fixup;
|
|
bool single_static;
|
|
bool copy_in_use;
|
|
bool is_template;
|
|
} CopyStruct;
|
|
|
|
typedef struct
|
|
{
|
|
const char **links;
|
|
} Linking;
|
|
|
|
typedef struct
|
|
{
|
|
HTable modules;
|
|
Module *core_module;
|
|
CompilationUnit *core_unit;
|
|
Module **module_list;
|
|
Module **generic_module_list;
|
|
Type **type;
|
|
Decl **method_extensions;
|
|
const char *lib_dir;
|
|
const char **sources;
|
|
File **loaded_sources;
|
|
bool in_panic_mode : 1;
|
|
unsigned errors_found;
|
|
unsigned warnings_found;
|
|
unsigned includes_used;
|
|
Decl ***locals_list;
|
|
HTable compiler_defines;
|
|
HTable features;
|
|
Module std_module;
|
|
DeclTable symbols;
|
|
DeclTable generic_symbols;
|
|
Path std_module_path;
|
|
Type *string_type;
|
|
Decl *panic_var;
|
|
Decl *panicf;
|
|
Decl *io_error_file_not_found;
|
|
Decl *main;
|
|
Decl *test_func;
|
|
Decl *benchmark_func;
|
|
Decl *decl_stack[MAX_GLOBAL_DECL_STACK];
|
|
Decl **decl_stack_bottom;
|
|
Decl **decl_stack_top;
|
|
} GlobalContext;
|
|
|
|
typedef struct
|
|
{
|
|
BuildTarget build;
|
|
PlatformTarget platform;
|
|
Linking linking;
|
|
GlobalContext context;
|
|
} CompilerState;
|
|
|
|
extern CompilerState compiler;
|
|
extern Ast *poisoned_ast;
|
|
extern Decl *poisoned_decl;
|
|
extern Expr *poisoned_expr;
|
|
extern Type *poisoned_type;
|
|
extern TypeInfo *poisoned_type_info;
|
|
|
|
extern Type *type_bool, *type_void, *type_voidptr;
|
|
extern Type *type_float16, *type_bfloat, *type_float, *type_double, *type_f128;
|
|
extern Type *type_ichar, *type_short, *type_int, *type_long, *type_isz;
|
|
extern Type *type_char, *type_ushort, *type_uint, *type_ulong, *type_usz;
|
|
extern Type *type_iptr, *type_uptr;
|
|
extern Type *type_u128, *type_i128;
|
|
extern Type *type_typeid, *type_anyfault, *type_any, *type_typeinfo, *type_member;
|
|
extern Type *type_untypedlist;
|
|
extern Type *type_wildcard;
|
|
extern Type *type_cint;
|
|
extern Type *type_cuint;
|
|
extern Type *type_chars;
|
|
extern Type *type_wildcard_optional;
|
|
extern Type *type_string;
|
|
extern Type *type_reflected_param;
|
|
extern File stdin_file;
|
|
|
|
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
|
extern const char *builtin_list[NUMBER_OF_BUILTINS];
|
|
extern const char *builtin_defines[NUMBER_OF_BUILTIN_DEFINES];
|
|
extern const char *type_property_list[NUMBER_OF_TYPE_PROPERTIES];
|
|
extern const char *kw_std__core;
|
|
extern const char *kw_std__core__types;
|
|
extern const char *kw_std__io;
|
|
extern const char *kw_typekind;
|
|
extern const char *kw_FILE_NOT_FOUND;
|
|
extern const char *kw_IoError;
|
|
|
|
extern const char *kw_at_deprecated;
|
|
extern const char *kw_at_ensure;
|
|
extern const char *kw_at_param;
|
|
extern const char *kw_at_pure;
|
|
extern const char *kw_at_require;
|
|
extern const char *kw_at_return;
|
|
extern const char *kw_at_jump;
|
|
extern const char *kw_in;
|
|
extern const char *kw_inout;
|
|
extern const char *kw_len;
|
|
extern const char *kw_libc;
|
|
extern const char *kw_main;
|
|
extern const char *kw_mainstub;
|
|
extern const char *kw_memcmp;
|
|
extern const char *kw_nameof;
|
|
extern const char *kw_offsetof;
|
|
extern const char *kw_ordinal;
|
|
extern const char *kw_out;
|
|
extern const char *kw_ptr;
|
|
extern const char *kw_return;
|
|
extern const char *kw_self;
|
|
extern const char *kw_std;
|
|
extern const char *kw_type;
|
|
extern const char *kw_winmain;
|
|
extern const char *kw_wmain;
|
|
extern ArchOsTarget default_target;
|
|
|
|
ARENA_DEF(chars, char)
|
|
ARENA_DEF(ast, Ast)
|
|
ARENA_DEF(expr, Expr)
|
|
ARENA_DEF(decl, Decl)
|
|
ARENA_DEF(type_info, TypeInfo)
|
|
|
|
|
|
INLINE TypeInfo *vartype(Decl *var)
|
|
{
|
|
return type_infoptrzero(var->var.type_info);
|
|
}
|
|
|
|
INLINE Type *typeget(TypeInfoId id_)
|
|
{
|
|
return id_ ? type_infoptr(id_)->type : NULL;
|
|
}
|
|
|
|
INLINE bool no_panic(void)
|
|
{
|
|
return compiler.build.feature.panic_level == PANIC_OFF;
|
|
}
|
|
|
|
INLINE bool safe_mode_enabled(void)
|
|
{
|
|
return compiler.build.feature.safe_mode != SAFETY_OFF;
|
|
}
|
|
|
|
INLINE bool link_libc(void)
|
|
{
|
|
return compiler.build.link_libc != LINK_LIBC_OFF;
|
|
}
|
|
|
|
INLINE bool strip_unused(void)
|
|
{
|
|
return compiler.build.strip_unused != STRIP_UNUSED_OFF;
|
|
}
|
|
|
|
INLINE bool no_stdlib(void)
|
|
{
|
|
return compiler.build.use_stdlib == USE_STDLIB_OFF;
|
|
}
|
|
|
|
INLINE bool compile_asserts(void)
|
|
{
|
|
return safe_mode_enabled() || compiler.build.testing;
|
|
}
|
|
|
|
bool ast_is_not_empty(Ast *ast);
|
|
|
|
bool ast_is_compile_time(Ast *ast);
|
|
bool ast_supports_continue(Ast *stmt);
|
|
INLINE void ast_append(AstId **succ, Ast *next);
|
|
INLINE void ast_prepend(AstId *first, Ast *ast);
|
|
INLINE bool ast_ok(Ast *ast);
|
|
INLINE bool ast_poison(Ast *ast);
|
|
INLINE Ast *ast_last(Ast *ast);
|
|
INLINE Ast *new_ast(AstKind kind, SourceSpan range);
|
|
INLINE Ast *ast_next(AstId *current_ptr);
|
|
|
|
const char *span_to_string(SourceSpan span);
|
|
void span_to_scratch(SourceSpan span);
|
|
|
|
static inline SourceSpan extend_span_with_token(SourceSpan loc, SourceSpan after)
|
|
{
|
|
if (loc.row != after.row) return loc;
|
|
loc.length = after.col + after.length - loc.col;
|
|
return loc;
|
|
}
|
|
|
|
AttributeType attribute_by_name(const char *name);
|
|
|
|
void type_setup(PlatformTarget *target);
|
|
Float float_add(Float op1, Float op2);
|
|
Float float_sub(Float op1, Float op2);
|
|
Float float_mul(Float op1, Float op2);
|
|
Float float_div(Float op1, Float op2);
|
|
Float float_neg(Float op);
|
|
Float float_rem(Float op1, Float op2);
|
|
Float float_from_string(const char *string, char **error);
|
|
Float float_from_hex(const char *string, char **error);
|
|
Int128 i128_from_double(double x);
|
|
bool int_ucomp(Int op1, uint64_t op2, BinaryOp op);
|
|
bool int_icomp(Int op1, int64_t op2, BinaryOp op);
|
|
bool int_comp(Int op1, Int op2, BinaryOp op);
|
|
uint64_t int_to_u64(Int op);
|
|
int64_t int_to_i64(Int op);
|
|
bool int_is_zero(Int op);
|
|
unsigned int_bits_needed(Int op);
|
|
bool int_fits(Int op1, TypeKind kind);
|
|
Int int_conv(Int op, TypeKind to_type);
|
|
Int int_div(Int op1, Int op2);
|
|
Int int_mul(Int op1, Int op2);
|
|
Int int_sub(Int op1, Int op2);
|
|
Int int_sub64(Int op1, uint64_t op2);
|
|
Int int_add(Int op1, Int op2);
|
|
Int int_add64(Int op1, uint64_t op2);
|
|
Int int_rem(Int op1, Int op2);
|
|
Int int_and(Int op1, Int op2);
|
|
Int int_or(Int op1, Int op2);
|
|
Int int_xor(Int op1, Int op2);
|
|
Int int_neg(Int op);
|
|
Int int_not(Int op);
|
|
bool int_is_neg(Int op);
|
|
Int int_shr64(Int op, uint64_t);
|
|
Int int_shl64(Int op, uint64_t);
|
|
Real int_to_real(Int op);
|
|
Int int_from_real(Real d, TypeKind type);
|
|
char *int_to_str(Int i, int radix, bool use_prefix);
|
|
bool i128_can_convert_from_double(double x);
|
|
bool i128_can_convert_from_double_signed(double x);
|
|
Int128 i128_from_double(double x);
|
|
Int128 i128_from_double_signed(double x);
|
|
Int128 i128_extend(Int128 op, TypeKind type);
|
|
Int128 i128_add(Int128 op1, Int128 op2);
|
|
Int128 i128_add64(Int128 op1, uint64_t op2);
|
|
Int128 i128_add_swrap64(Int128 op1, int64_t op2, bool *wrapped);
|
|
Int128 i128_add_uwrap64(Int128 op1, uint64_t op2, bool *wrapped);
|
|
Int128 i128_sub(Int128 op1, Int128 op2);
|
|
Int128 i128_sub64(Int128 op1, uint64_t op2);
|
|
Int128 i128_and(Int128 op1, Int128 op2);
|
|
Int128 i128_or(Int128 op1, Int128 op2);
|
|
Int128 i128_xor(Int128 op1, Int128 op2);
|
|
Int128 i128_neg(Int128 op1);
|
|
Int128 i128_not(Int128 op1);
|
|
Int128 i128_mult(Int128 op1, Int128 op2);
|
|
Int128 i128_mult64(Int128 op1, uint64_t op2);
|
|
Int128 i128_from_str(const char *str);
|
|
char *i128_to_string(Int128 op, uint64_t base, bool is_signed, bool use_prefix);
|
|
bool i128_is_neg(Int128 op);
|
|
CmpRes i128_ucomp(Int128 op1, Int128 op2);
|
|
CmpRes i128_scomp(Int128 op1, Int128 op2);
|
|
CmpRes i128_comp(Int128 op1, Int128 op2, Type *type);
|
|
Int128 i128_shl64(Int128 op1, uint64_t amount);
|
|
Int128 i128_shl(Int128 op1, Int128 op);
|
|
Int128 i128_ashr64(Int128 op1, uint64_t amount);
|
|
Int128 i128_ashr(Int128 op1, Int128 op2);
|
|
Int128 i128_lshr64(Int128 op1, uint64_t amount);
|
|
Int128 i128_lshr(Int128 op1, Int128 op2);
|
|
Int128 i128_udiv(Int128 op1, Int128 op2);
|
|
Int128 i128_sdiv(Int128 op1, Int128 op2);
|
|
Int128 i128_urem(Int128 op1, Int128 op2);
|
|
Int128 i128_srem(Int128 op1, Int128 op2);
|
|
void i128_udivrem(Int128 op1, Int128 op2, Int128 *div, Int128 *rem);
|
|
Real i128_to_float(Int128 op);
|
|
Real i128_to_float_signed(Int128 op);
|
|
bool i128_is_zero(Int128 op);
|
|
uint32_t i128_clz(const Int128 *op);
|
|
uint32_t i128_ctz(const Int128 *op);
|
|
UNUSED int i128_lsb(const Int128 *op);
|
|
UNUSED int i128_msb(const Int128 *op);
|
|
Int128 i128_from_float_signed(Real d);
|
|
Int128 i128_from_float_unsigned(Real d);
|
|
Int128 i128_from_signed(int64_t i);
|
|
UNUSED Int128 i128_from_unsigned(uint64_t i);
|
|
UNUSED bool i128_get_bit(const Int128 *op, int bit);
|
|
|
|
// copy ---
|
|
|
|
#define MACRO_COPY_DECL(x) x = copy_decl(c, x)
|
|
#define MACRO_COPY_DECLID(x) x = declid_copy_deep(c, x)
|
|
#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(c, x)
|
|
#define MACRO_COPY_EXPR(x) x = copy_expr(c, x)
|
|
#define MACRO_COPY_EXPRID(x) x = exprid_copy_deep(c, x)
|
|
#define MACRO_COPY_TYPE(x) x = copy_type_info(c, x)
|
|
#define MACRO_COPY_TYPEID(x) x = type_info_id_copy_deep(c, x)
|
|
#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(c, x)
|
|
#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(c, x)
|
|
#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(c, x)
|
|
#define MACRO_COPY_AST(x) x = ast_copy_deep(c, x)
|
|
#define MACRO_COPY_ASTID(x) x = astid_copy_deep(c, x)
|
|
|
|
|
|
void copy_begin(void);
|
|
void copy_end(void);
|
|
Expr *copy_expr_single(Expr *source_expr);
|
|
Decl **copy_decl_list_single(Decl **decl_list);
|
|
Decl **copy_decl_list_single_for_unit(Decl **decl_list);
|
|
Attr **copy_attributes_single(Attr** attr_list);
|
|
Decl *copy_lambda_deep(Decl *decl);
|
|
Ast *copy_ast_single(Ast *source_ast);
|
|
Decl **copy_decl_list_macro(Decl **decl_list);
|
|
Ast *copy_ast_macro(Ast *source_ast);
|
|
Ast *copy_ast_defer(Ast *source_ast);
|
|
TypeInfo *copy_type_info_single(TypeInfo *type_info);
|
|
|
|
void init_asm(PlatformTarget *target);
|
|
AsmRegister *asm_reg_by_name(PlatformTarget *target, const char *name);
|
|
AsmInstruction *asm_instr_by_name(const char *name);
|
|
INLINE const char *asm_clobber_by_index(unsigned index);
|
|
INLINE AsmRegister *asm_reg_by_index(unsigned index);
|
|
|
|
AsmRegister *asm_reg_by_index(unsigned index);
|
|
bool asm_is_supported(ArchType arch);
|
|
|
|
bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type, bool is_binary_conversion);
|
|
|
|
bool cast_implicit_binary(SemaContext *context, Expr *expr, Type *to_type, bool is_silent);
|
|
bool cast_implicit(SemaContext *context, Expr *expr, Type *to_type, bool is_binary);
|
|
bool cast_explicit_silent(SemaContext *context, Expr *expr, Type *to_type);
|
|
bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type);
|
|
|
|
bool may_cast(SemaContext *cc, Expr *expr, Type *to_type, bool is_explicit, bool is_silent);
|
|
|
|
void cast_no_check(SemaContext *context, Expr *expr, Type *to_type, bool add_optional);
|
|
|
|
bool cast_to_index(SemaContext *context, Expr *index, Type *subscripted_type);
|
|
CastKind cast_to_bool_kind(Type *type);
|
|
|
|
const char *llvm_codegen(void *context);
|
|
const char *tilde_codegen(void *context);
|
|
void **llvm_gen(Module** modules, unsigned module_count);
|
|
void **tilde_gen(Module** modules, unsigned module_count);
|
|
|
|
void header_gen(Module **modules, unsigned module_count);
|
|
const char *build_base_name(void);
|
|
|
|
void global_context_clear_errors(void);
|
|
void global_context_add_type(Type *type);
|
|
void global_context_add_decl(Decl *type_decl);
|
|
void global_context_add_generic_decl(Decl *decl);
|
|
|
|
void linking_add_link(Linking *linker, const char *link);
|
|
|
|
Module *compiler_find_or_create_module(Path *module_name, const char **parameters);
|
|
Module *global_context_find_module(const char *name);
|
|
const char *get_object_extension(void);
|
|
const char *get_exe_extension(void);
|
|
|
|
CompilationUnit * unit_create(File *file);
|
|
void unit_register_global_decl(CompilationUnit *unit, Decl *decl);
|
|
void unit_register_external_symbol(SemaContext *context, Decl *decl);
|
|
|
|
bool unit_add_import(CompilationUnit *unit, Path *path, bool private_import, bool is_non_recursive);
|
|
bool context_set_module_from_filename(ParseContext *context);
|
|
bool context_set_module(ParseContext *context, Path *path, const char **generic_parameters);
|
|
bool context_is_macro(SemaContext *context);
|
|
|
|
// --- Decl functions
|
|
|
|
Decl *decl_new(DeclKind decl_kind, const char *name, SourceSpan span);
|
|
Decl *decl_new_ct(DeclKind kind, SourceSpan span);
|
|
Decl *decl_new_with_type(const char *name, SourceSpan span, DeclKind decl_type);
|
|
Decl *decl_new_var(const char *name, SourceSpan span, TypeInfo *type, VarDeclKind kind);
|
|
Decl *decl_new_generated_var(Type *type, VarDeclKind kind, SourceSpan span);
|
|
|
|
const char *decl_safe_name(Decl *decl);
|
|
const char *decl_to_name(Decl *decl);
|
|
const char *decl_to_a_name(Decl *decl);
|
|
int decl_count_elements(Decl *structlike);
|
|
void decl_append_links_to_global(Decl *decl);
|
|
|
|
INLINE bool decl_ok(Decl *decl);
|
|
INLINE bool decl_poison(Decl *decl);
|
|
INLINE bool decl_is_struct_type(Decl *decl);
|
|
INLINE bool decl_is_user_defined_type(Decl *decl);
|
|
INLINE Decl *decl_flatten(Decl *decl);
|
|
static inline Decl *decl_raw(Decl *decl);
|
|
static inline DeclKind decl_from_token(TokenType type);
|
|
static inline bool decl_is_var_local(Decl *decl);
|
|
bool decl_is_ct_var(Decl *decl);
|
|
Decl *decl_find_enum_constant(Decl *decl, const char *name);
|
|
bool decl_needs_prefix(Decl *decl);
|
|
AlignSize decl_find_member_offset(Decl *decl, Decl *member);
|
|
bool decl_is_externally_visible(Decl *decl);
|
|
bool decl_is_local(Decl *decl);
|
|
bool decl_is_global(Decl *decl);
|
|
void scratch_buffer_set_extern_decl_name(Decl *decl, bool clear);
|
|
|
|
// --- Expression functions
|
|
|
|
#define EXPR_NEW_TOKEN(kind_) expr_new(kind_, c->span)
|
|
Expr *expr_new(ExprKind kind, SourceSpan start);
|
|
Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v);
|
|
Expr *expr_new_const_bool(SourceSpan span, Type *type, bool value);
|
|
Expr *expr_new_const_typeid(SourceSpan span, Type *type);
|
|
Expr *expr_new_const_string(SourceSpan span, const char *string);
|
|
Expr *expr_new_const_initializer(SourceSpan span, Type *type, ConstInitializer *initializer);
|
|
bool expr_is_simple(Expr *expr, bool to_float);
|
|
bool expr_is_pure(Expr *expr);
|
|
bool expr_is_runtime_const(Expr *expr);
|
|
Expr *expr_generate_decl(Decl *decl, Expr *assign);
|
|
void expr_insert_addr(Expr *original);
|
|
void expr_rewrite_insert_deref(Expr *original);
|
|
Expr *expr_generate_decl(Decl *decl, Expr *assign);
|
|
Expr *expr_variable(Decl *decl);
|
|
Expr *expr_negate_expr(Expr *expr);
|
|
bool expr_may_addr(Expr *expr);
|
|
bool expr_in_int_range(Expr *expr, int64_t low, int64_t high);
|
|
bool expr_is_unwrapped_ident(Expr *expr);
|
|
INLINE Expr *expr_new_expr(ExprKind kind, Expr *expr);
|
|
INLINE bool expr_ok(Expr *expr);
|
|
INLINE void expr_resolve_ident(Expr *expr, Decl *decl);
|
|
INLINE bool exprid_is_simple(ExprId expr_id, bool to_float);
|
|
INLINE bool exprid_is_pure(ExprId expr_id);
|
|
INLINE Type *exprtype(ExprId expr_id);
|
|
INLINE void expr_replace(Expr *expr, Expr *replacement);
|
|
INLINE bool expr_poison(Expr *expr);
|
|
INLINE bool exprid_is_runtime_const(ExprId expr);
|
|
INLINE bool expr_is_init_list(Expr *expr);
|
|
INLINE bool expr_is_neg(Expr *expr);
|
|
INLINE bool expr_is_mult(Expr *expr);
|
|
INLINE bool expr_is_deref(Expr *expr);
|
|
INLINE bool expr_is_const(Expr *expr);
|
|
INLINE bool expr_is_const_int(Expr *expr);
|
|
INLINE bool expr_is_const_string(Expr *expr);
|
|
INLINE bool expr_is_const_initializer(Expr *expr);
|
|
INLINE bool expr_is_const_untyped_list(Expr *expr);
|
|
INLINE bool expr_is_const_member(Expr *expr);
|
|
|
|
INLINE void expr_rewrite_const_null(Expr *expr, Type *type);
|
|
INLINE void expr_rewrite_const_bool(Expr *expr, Type *type, bool b);
|
|
INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d);
|
|
INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v);
|
|
INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type);
|
|
INLINE void expr_rewrite_const_initializer(Expr *expr, Type *type, ConstInitializer *initializer);
|
|
INLINE void expr_rewrite_const_untyped_list(Expr *expr, Expr **elements);
|
|
void expr_rewrite_const_string(Expr *expr_to_rewrite, const char *string);
|
|
void expr_rewrite_const_ref(Expr *expr_to_rewrite, Decl *decl);
|
|
|
|
void expr_rewrite_to_builtin_access(Expr *expr, Expr *parent, BuiltinAccessKind kind, Type *type);
|
|
void expr_rewrite_to_const_zero(Expr *expr, Type *type);
|
|
bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index, bool from_back);
|
|
|
|
void expr_rewrite_to_binary(Expr *expr_to_rewrite, Expr *left, Expr *right, BinaryOp op);
|
|
|
|
bool expr_const_in_range(const ExprConst *left, const ExprConst *right, const ExprConst *right_to);
|
|
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
|
|
void expr_contract_array(ExprConst *expr_const, ConstKind contract_type);
|
|
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
|
|
const char *expr_const_to_error_string(const ExprConst *expr);
|
|
bool expr_const_float_fits_type(const ExprConst *expr_const, TypeKind kind);
|
|
|
|
// --- Lexer functions
|
|
|
|
void lexer_init(Lexer *lexer);
|
|
bool lexer_next_token(Lexer *lexer);
|
|
|
|
// --- Module functions
|
|
|
|
void scratch_buffer_append_module(Module *module, bool is_export);
|
|
Decl *module_find_symbol(Module *module, const char *symbol);
|
|
const char *module_create_object_file_name(Module *module);
|
|
|
|
bool parse_file(File *file);
|
|
Decl **parse_include_file(File *file, CompilationUnit *unit);
|
|
Ast *parse_include_file_stmts(File *file, CompilationUnit *unit);
|
|
bool parse_stdin(void);
|
|
Path *path_create_from_string(const char *string, uint32_t len, SourceSpan span);
|
|
|
|
|
|
void sema_analysis_run(void);
|
|
Decl **sema_decl_stack_store(void);
|
|
Decl *sema_decl_stack_find_decl_member(SemaContext *context, Decl *decl_owner, const char *symbol);
|
|
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
|
|
void sema_decl_stack_restore(Decl **state);
|
|
void sema_decl_stack_push(Decl *decl);
|
|
|
|
bool sema_error_failed_cast(SemaContext *context, Expr *expr, Type *from, Type *to);
|
|
bool sema_add_local(SemaContext *context, Decl *decl);
|
|
void sema_unwrap_var(SemaContext *context, Decl *decl);
|
|
void sema_rewrap_var(SemaContext *context, Decl *decl);
|
|
void sema_erase_var(SemaContext *context, Decl *decl);
|
|
void sema_erase_unwrapped(SemaContext *context, Decl *decl);
|
|
bool sema_analyse_cond_expr(SemaContext *context, Expr *expr, CondResult *result);
|
|
|
|
bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allow_optional, bool *no_match_ref,
|
|
bool as_binary);
|
|
|
|
bool sema_analyse_expr(SemaContext *context, Expr *expr);
|
|
bool sema_cast_const(Expr *expr);
|
|
|
|
bool sema_expr_check_discard(SemaContext *context, Expr *expr);
|
|
bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr);
|
|
bool sema_analyse_decl(SemaContext *context, Decl *decl);
|
|
bool sema_analyse_method_register(SemaContext *context, Decl *method);
|
|
bool sema_resolve_type_structure(SemaContext *context, Type *type, SourceSpan span);
|
|
bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl);
|
|
bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local);
|
|
bool sema_analyse_ct_assert_stmt(SemaContext *context, Ast *statement);
|
|
bool sema_analyse_ct_echo_stmt(SemaContext *context, Ast *statement);
|
|
bool sema_analyse_statement(SemaContext *context, Ast *statement);
|
|
|
|
bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right,
|
|
bool is_unwrapped_var, bool is_declaration);
|
|
bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr);
|
|
Expr **sema_expand_vasplat_exprs(SemaContext *c, Expr **exprs);
|
|
|
|
bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional,
|
|
bool *no_match_ref);
|
|
|
|
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
|
|
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
|
|
bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve);
|
|
Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
|
|
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
|
|
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name);
|
|
bool sema_resolve_type_decl(SemaContext *context, Type *type);
|
|
bool sema_check_type_variable_array(SemaContext *context, TypeInfo *type);
|
|
Decl *sema_find_symbol(SemaContext *context, const char *symbol);
|
|
Decl *sema_find_path_symbol(SemaContext *context, const char *symbol, Path *path);
|
|
Decl *sema_find_label_symbol(SemaContext *context, const char *symbol);
|
|
Decl *sema_find_label_symbol_anywhere(SemaContext *context, const char *symbol);
|
|
Decl *sema_resolve_symbol(SemaContext *context, const char *symbol, Path *path, SourceSpan span);
|
|
BoolErr sema_symbol_is_defined_in_scope(SemaContext *c, const char *symbol);
|
|
|
|
bool sema_resolve_array_like_len(SemaContext *context, TypeInfo *type_info, ArraySize *len_ref);
|
|
|
|
bool sema_resolve_type_info(SemaContext *context, TypeInfo *type_info, ResolveTypeKind kind);
|
|
|
|
void print_error_at(SourceSpan loc, const char *message, ...);
|
|
void print_error_after(SourceSpan loc, const char *message, ...);
|
|
void sema_note_prev_at(SourceSpan loc, const char *message, ...);
|
|
void sema_verror_range(SourceSpan location, const char *message, va_list args);
|
|
void print_error(ParseContext *context, const char *message, ...);
|
|
|
|
void sema_warning_at(SourceSpan loc, const char *message, ...);
|
|
void sema_shadow_error(SemaContext *context, Decl *decl, Decl *old);
|
|
|
|
bool sema_type_error_on_binop(SemaContext *context, Expr *expr);
|
|
|
|
File *source_file_by_id(FileId file);
|
|
File *source_file_load(const char *filename, bool *already_loaded, const char **error);
|
|
File *source_file_generate(const char *filename);
|
|
File *source_file_text_load(const char *filename, const char *content);
|
|
|
|
File *compile_and_invoke(const char *file, const char *args, const char *stdin_data);
|
|
void compiler_parse(void);
|
|
void emit_json(void);
|
|
|
|
void stable_init(STable *table, uint32_t initial_size);
|
|
void *stable_set(STable *table, const char *key, void *value);
|
|
void *stable_get(STable *table, const char *key);
|
|
|
|
void htable_init(HTable *table, uint32_t initial_size);
|
|
void *htable_set(HTable *table, void *key, void *value);
|
|
void *htable_get(HTable *table, void *key);
|
|
|
|
UNUSED void stable_clear(STable *table);
|
|
|
|
void decltable_init(DeclTable *table, uint32_t initial_size);
|
|
DeclId decltable_get(DeclTable *table, const char *name);
|
|
void decltable_set(DeclTable *table, Decl *decl);
|
|
|
|
const char *scratch_buffer_interned(void);
|
|
const char *scratch_buffer_interned_as(TokenType *type);
|
|
|
|
const char *symtab_preset(const char *data, TokenType type);
|
|
const char *symtab_add(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
|
|
const char *symtab_find(const char *symbol, uint32_t len, uint32_t fnv1hash, TokenType *type);
|
|
void *llvm_target_machine_create(void);
|
|
void codegen_setup_object_names(Module *module, const char **ir_filename, const char **asm_filename, const char **object_filename);
|
|
void target_setup(BuildTarget *build_target);
|
|
int target_alloca_addr_space();
|
|
bool os_is_apple(OsType os_type);
|
|
bool os_supports_stacktrace(OsType os_type);
|
|
bool arch_is_wasm(ArchType type);
|
|
|
|
const char *macos_sysroot(void);
|
|
MacSDK *macos_sysroot_sdk_information(const char *sdk_path);
|
|
WindowsSDK *windows_get_sdk(void);
|
|
const char *windows_cross_compile_library(void);
|
|
|
|
void c_abi_func_create(FunctionPrototype *proto);
|
|
|
|
bool token_is_any_type(TokenType type);
|
|
const char *token_type_to_string(TokenType type);
|
|
|
|
#define IS_OPTIONAL(element_) (type_is_optional((element_)->type))
|
|
#define IS_RESOLVED(element_) ((element_)->resolve_status == RESOLVE_DONE)
|
|
bool type_is_comparable(Type *type);
|
|
bool type_is_ordered(Type *type);
|
|
unsigned type_get_introspection_kind(TypeKind kind);
|
|
void type_mangle_introspect_name_to_buffer(Type *type);
|
|
AlignSize type_abi_alignment(Type *type);
|
|
bool type_func_match(Type *fn_type, Type *rtype, unsigned arg_count, ...);
|
|
AlignSize type_alloca_alignment(Type *type);
|
|
Type *type_find_largest_union_element(Type *type);
|
|
Type *type_find_max_type(Type *type, Type *other);
|
|
Type *type_find_max_type_may_fail(Type *type, Type *other);
|
|
Type *type_abi_find_single_struct_element(Type *type);
|
|
Module *type_base_module(Type *type);
|
|
bool type_is_valid_for_vector(Type *type);
|
|
bool type_is_valid_for_array(Type *type);
|
|
Type *type_get_array(Type *arr_type, ArraySize len);
|
|
Type *type_get_indexed_type(Type *type);
|
|
Type *type_get_ptr(Type *ptr_type);
|
|
Type *type_get_func_ptr(Type *func_type);
|
|
Type *type_get_ptr_recurse(Type *ptr_type);
|
|
Type *type_get_slice(Type *arr_type);
|
|
Type *type_get_inferred_array(Type *arr_type);
|
|
Type *type_get_inferred_vector(Type *arr_type);
|
|
Type *type_get_flexible_array(Type *arr_type);
|
|
|
|
Type *type_get_optional(Type *optional_type);
|
|
Type *type_get_vector(Type *vector_type, unsigned len);
|
|
Type *type_get_vector_bool(Type *original_type);
|
|
Type *type_int_signed_by_bitsize(BitSize bitsize);
|
|
Type *type_int_unsigned_by_bitsize(BitSize bit_size);
|
|
bool type_is_matching_int(CanonicalType *type1, CanonicalType *type2);
|
|
TypeSize type_size(Type *type); // Only call after all types are resolved.
|
|
void type_init_cint(void);
|
|
Type *type_new_func(Decl *decl, Signature *sig);
|
|
void type_func_prototype_init(uint32_t capacity);
|
|
Type *type_find_parent_type(Type *type);
|
|
bool type_is_subtype(Type *type, Type *possible_subtype);
|
|
bool type_is_abi_aggregate(Type *type);
|
|
bool type_is_int128(Type *type);
|
|
|
|
Type *type_from_token(TokenType type);
|
|
bool type_is_user_defined(Type *type);
|
|
bool type_is_structurally_equivalent(Type *type1, Type *type);
|
|
bool type_flat_is_floatlike(Type *type);
|
|
bool type_flat_is_intlike(Type *type);
|
|
bool type_flat_is_boolintlike(Type *type);
|
|
bool type_flat_is_numlike(Type *type);
|
|
bool type_may_have_sub_elements(Type *type);
|
|
bool type_may_have_method(Type *type);
|
|
void type_append_name_to_scratch(Type *type);
|
|
|
|
TypeCmpResult type_is_pointer_equivalent(SemaContext *context, Type *to_pointer, Type *from_pointer, bool flatten_distinct);
|
|
TypeCmpResult type_array_element_is_equivalent(SemaContext *context, Type *element1, Type *element2, bool is_explicit);
|
|
FunctionPrototype *type_get_resolved_prototype(Type *type);
|
|
bool type_is_inner_type(Type *type);
|
|
const char *type_to_error_string(Type *type);
|
|
const char *type_quoted_error_string(Type *type);
|
|
INLINE bool type_may_negate(Type *type);
|
|
INLINE bool type_is_builtin(TypeKind kind);
|
|
INLINE bool type_convert_will_trunc(Type *destination, Type *source);
|
|
INLINE Type *type_no_optional(Type *type);
|
|
INLINE Type *type_new(TypeKind kind, const char *name);
|
|
INLINE bool type_is_pointer_sized(Type *type);
|
|
INLINE bool type_is_pointer_sized_or_more(Type *type);
|
|
INLINE Type *type_add_optional(Type *type, bool make_optional);
|
|
INLINE Type *type_from_inferred(Type *flattened, Type *element_type, unsigned count);
|
|
INLINE bool type_len_is_inferred(Type *type);
|
|
INLINE bool type_is_substruct(Type *type);
|
|
INLINE Type *type_flatten_for_bitstruct(Type *type);
|
|
INLINE const char *type_invalid_storage_type_name(Type *type);
|
|
INLINE bool type_is_float(Type *type);
|
|
INLINE bool type_is_floatlike(Type *type);
|
|
INLINE bool type_is_optional(Type *type);
|
|
INLINE bool type_is_wildcard(Type *type);
|
|
INLINE bool type_is_void(Type *type);
|
|
INLINE bool type_is_integer(Type *type);
|
|
INLINE bool type_is_integer_unsigned(Type *type);
|
|
INLINE bool type_is_integer_signed(Type *type);
|
|
INLINE bool type_is_integer_or_bool_kind(Type *type);
|
|
INLINE bool type_is_numeric(Type *type);
|
|
INLINE bool type_is_inferred(Type *type);
|
|
INLINE bool type_underlying_is_numeric(Type *type);
|
|
INLINE bool type_underlying_may_add_sub(Type *type);
|
|
INLINE bool type_is_pointer(Type *type);
|
|
INLINE bool type_is_arraylike(Type *type);
|
|
INLINE bool type_is_any_arraylike(Type *type);
|
|
INLINE bool type_is_promotable_float(Type *type);
|
|
INLINE bool type_is_promotable_int_bool(Type *type);
|
|
INLINE bool type_is_signed(Type *type);
|
|
INLINE bool type_ok(Type *type);
|
|
INLINE bool type_is_unsigned(Type *type);
|
|
INLINE bool type_is_union_or_strukt(Type *type);
|
|
INLINE bool type_flat_is_vector(Type *type);
|
|
INLINE bool type_flat_is_vector_bitstruct(Type *type);
|
|
INLINE AlignSize type_min_alignment(AlignSize a, AlignSize b);
|
|
INLINE AlignSize type_max_alignment(AlignSize a, AlignSize b);
|
|
INLINE BitSize type_bit_size(Type *type);
|
|
INLINE Type *type_vector_type(Type *type);
|
|
|
|
static inline CanonicalType *type_pointer_type(Type *type);
|
|
static inline Type *type_flatten(Type *type);
|
|
static inline bool type_flat_is_char_array(Type *type);
|
|
static inline Type *type_base(Type *type);
|
|
|
|
INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
|
|
INLINE TypeInfo *type_info_new_base(Type *type, SourceSpan span);
|
|
INLINE bool type_info_ok(TypeInfo *type_info);
|
|
INLINE bool type_info_poison(TypeInfo *type);
|
|
|
|
int type_kind_bitsize(TypeKind kind);
|
|
INLINE bool type_kind_is_signed(TypeKind kind);
|
|
INLINE bool type_kind_is_unsigned(TypeKind kind);
|
|
INLINE bool type_kind_is_any_integer(TypeKind kind);
|
|
INLINE bool type_kind_is_enumlike(TypeKind kind);
|
|
|
|
void advance(ParseContext *c);
|
|
INLINE void advance_and_verify(ParseContext *context, TokenType token_type);
|
|
|
|
UnaryOp unaryop_from_token(TokenType type);
|
|
BinaryOp binaryop_from_token(TokenType type);
|
|
BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op);
|
|
TokenType binaryop_to_token(BinaryOp type);
|
|
|
|
|
|
// ---- static inline function implementations.
|
|
|
|
INLINE Type *type_no_optional(Type *type)
|
|
{
|
|
if (!type) return NULL;
|
|
if (type->type_kind == TYPE_OPTIONAL) return type->optional;
|
|
return type;
|
|
}
|
|
|
|
INLINE bool type_is_pointer_sized_or_more(Type *type)
|
|
{
|
|
return type_is_integer(type) && type_size(type) >= type_size(type_iptr);
|
|
}
|
|
|
|
INLINE bool type_is_pointer_sized(Type *type)
|
|
{
|
|
return type_is_integer(type) && type_size(type) == type_size(type_iptr);
|
|
}
|
|
|
|
#define DECL_TYPE_KIND_REAL(k_, t_) \
|
|
TypeKind k_ = (t_)->type_kind; \
|
|
if (k_ == TYPE_TYPEDEF) k_ = (t_)->canonical->type_kind;
|
|
|
|
|
|
INLINE Type *type_add_optional(Type *type, bool make_optional)
|
|
{
|
|
if (!make_optional || type->type_kind == TYPE_OPTIONAL) return type;
|
|
return type_get_optional(type);
|
|
}
|
|
|
|
INLINE Type *type_from_inferred(Type *flattened, Type *element_type, unsigned count)
|
|
{
|
|
switch (flattened->type_kind)
|
|
{
|
|
case TYPE_POINTER:
|
|
assert(count == 0);
|
|
return type_get_ptr(element_type);
|
|
case TYPE_VECTOR:
|
|
assert(flattened->array.len == count);
|
|
FALLTHROUGH;
|
|
case TYPE_INFERRED_VECTOR:
|
|
return type_get_vector(element_type, count);
|
|
break;
|
|
case TYPE_ARRAY:
|
|
assert(flattened->array.len == count);
|
|
FALLTHROUGH;
|
|
case TYPE_INFERRED_ARRAY:
|
|
return type_get_array(element_type, count);
|
|
default:
|
|
UNREACHABLE
|
|
}
|
|
}
|
|
INLINE bool type_len_is_inferred(Type *type)
|
|
{
|
|
if (!type) return true;
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
while (1)
|
|
{
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
continue;
|
|
case TYPE_OPTIONAL:
|
|
type = type->optional;
|
|
continue;
|
|
case TYPE_ARRAY:
|
|
case TYPE_SLICE:
|
|
case TYPE_FLEXIBLE_ARRAY:
|
|
case TYPE_VECTOR:
|
|
type = type->array.base;
|
|
continue;
|
|
case TYPE_INFERRED_ARRAY:
|
|
case TYPE_INFERRED_VECTOR:
|
|
return true;
|
|
case TYPE_POINTER:
|
|
type = type->pointer;
|
|
continue;
|
|
default:
|
|
return false;
|
|
}
|
|
UNREACHABLE;
|
|
}
|
|
}
|
|
|
|
INLINE bool type_is_wildcard(Type *type)
|
|
{
|
|
return type == type_wildcard || type == type_wildcard_optional;
|
|
}
|
|
|
|
INLINE bool type_is_fault_raw(Type *type)
|
|
{
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_FAULTTYPE:
|
|
case TYPE_ANYFAULT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
INLINE bool type_is_any_raw(Type *type)
|
|
{
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_ANY:
|
|
case TYPE_INTERFACE:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
INLINE bool type_is_any(Type *type)
|
|
{
|
|
return type->canonical == type_any;
|
|
}
|
|
|
|
|
|
|
|
INLINE bool type_is_optional(Type *type)
|
|
{
|
|
if (!type) return false;
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_OPTIONAL;
|
|
}
|
|
|
|
INLINE bool type_may_implement_interface(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
switch (kind)
|
|
{
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
case TYPE_ENUM:
|
|
case TYPE_DISTINCT:
|
|
case TYPE_FAULTTYPE:
|
|
case TYPE_BITSTRUCT:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
INLINE bool type_is_void(Type *type)
|
|
{
|
|
return type->canonical == type_void;
|
|
}
|
|
|
|
INLINE bool type_is_integer(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind >= TYPE_INTEGER_FIRST && kind <= TYPE_INTEGER_LAST;
|
|
}
|
|
|
|
INLINE bool type_is_integer_signed(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind >= TYPE_INT_FIRST && kind <= TYPE_INT_LAST;
|
|
}
|
|
|
|
INLINE bool type_is_integer_or_bool_kind(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind >= TYPE_BOOL && kind <= TYPE_U128;
|
|
}
|
|
|
|
INLINE bool type_is_integer_unsigned(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind >= TYPE_UINT_FIRST && kind <= TYPE_UINT_LAST;
|
|
}
|
|
|
|
INLINE bool type_info_poison(TypeInfo *type)
|
|
{
|
|
type->kind = TYPE_INFO_POISON;
|
|
type->type = poisoned_type;
|
|
type->resolve_status = RESOLVE_DONE;
|
|
return false;
|
|
}
|
|
|
|
INLINE bool type_is_arraylike(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_ARRAY || kind == TYPE_VECTOR || kind == TYPE_FLEXIBLE_ARRAY;
|
|
}
|
|
|
|
INLINE bool type_is_any_arraylike(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind >= TYPE_FIRST_ARRAYLIKE && kind <= TYPE_LAST_ARRAYLIKE;
|
|
}
|
|
|
|
INLINE CanonicalType *type_pointer_type(Type *type)
|
|
{
|
|
CanonicalType *res = type->canonical;
|
|
if (res->type_kind != TYPE_POINTER) return NULL;
|
|
return res->pointer;
|
|
}
|
|
|
|
INLINE bool type_is_pointer_like(Type *type)
|
|
{
|
|
TypeKind kind = type->type_kind;
|
|
return kind == TYPE_POINTER || (kind == TYPE_VECTOR && type->array.base->canonical->type_kind == TYPE_POINTER);
|
|
}
|
|
|
|
INLINE bool type_is_pointer_vector(Type *type)
|
|
{
|
|
return type->type_kind == TYPE_VECTOR && type->array.base->canonical->type_kind == TYPE_POINTER;
|
|
}
|
|
|
|
INLINE bool type_is_atomic(Type *type_flat)
|
|
{
|
|
switch (type_flat->type_kind)
|
|
{
|
|
case ALL_UNSIGNED_INTS:
|
|
case ALL_SIGNED_INTS:
|
|
case ALL_FLOATS:
|
|
case TYPE_ENUM:
|
|
case TYPE_FAULTTYPE:
|
|
case TYPE_ANYFAULT:
|
|
case TYPE_TYPEID:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
return type_size(type_flat) <= type_size(type_iptr);
|
|
}
|
|
|
|
INLINE bool type_is_pointer(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_POINTER;
|
|
}
|
|
|
|
INLINE bool type_is_pointer_type(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_POINTER || kind == TYPE_FUNC_PTR;
|
|
}
|
|
|
|
static inline AlignSize aligned_offset(AlignSize offset, AlignSize alignment)
|
|
{
|
|
return ((offset + alignment - 1) / alignment) * alignment;
|
|
}
|
|
|
|
INLINE bool type_is_substruct(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_STRUCT && type->decl->is_substruct;
|
|
}
|
|
|
|
INLINE bool type_may_negate(Type *type)
|
|
{
|
|
RETRY:
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_VECTOR:
|
|
type = type->array.base;
|
|
goto RETRY;
|
|
case ALL_FLOATS:
|
|
case ALL_INTS:
|
|
return true;
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct->type;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_OPTIONAL:
|
|
type = type->optional;
|
|
goto RETRY;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
INLINE bool type_is_float(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
|
|
}
|
|
|
|
INLINE bool type_is_16bit_float(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_BF16 || kind == TYPE_F16;
|
|
}
|
|
|
|
INLINE bool type_is_floatlike(Type *type)
|
|
{
|
|
type = type->canonical;
|
|
TypeKind kind = type->type_kind;
|
|
if (kind == TYPE_VECTOR && type_is_float(type->array.base)) return true;
|
|
return kind >= TYPE_FLOAT_FIRST && kind <= TYPE_FLOAT_LAST;
|
|
}
|
|
|
|
INLINE const char *type_invalid_storage_type_name(Type *type)
|
|
{
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_MEMBER:
|
|
return "a member reference";
|
|
case TYPE_UNTYPED_LIST:
|
|
return "an untyped list";
|
|
case TYPE_TYPEINFO:
|
|
return "a type";
|
|
case TYPE_WILDCARD:
|
|
return "an empty value";
|
|
default:
|
|
UNREACHABLE;
|
|
}
|
|
}
|
|
|
|
static inline StorageType type_storage_type(Type *type)
|
|
{
|
|
if (!type) return STORAGE_NORMAL;
|
|
bool is_distinct = false;
|
|
RETRY:
|
|
if (type == type_wildcard_optional) return STORAGE_WILDCARD;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_VOID:
|
|
return is_distinct ? STORAGE_UNKNOWN : STORAGE_VOID;
|
|
case TYPE_WILDCARD:
|
|
return STORAGE_WILDCARD;
|
|
case TYPE_MEMBER:
|
|
case TYPE_UNTYPED_LIST:
|
|
case TYPE_TYPEINFO:
|
|
case TYPE_FUNC_RAW:
|
|
return STORAGE_COMPILE_TIME;
|
|
case TYPE_OPTIONAL:
|
|
type = type->optional;
|
|
goto RETRY;
|
|
case TYPE_TYPEDEF:
|
|
type = type->canonical;
|
|
goto RETRY;
|
|
case TYPE_DISTINCT:
|
|
is_distinct = true;
|
|
type = type->decl->distinct->type;
|
|
goto RETRY;
|
|
default:
|
|
return STORAGE_NORMAL;
|
|
}
|
|
}
|
|
|
|
INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span)
|
|
{
|
|
TypeInfo *type_info = type_info_calloc();
|
|
type_info->kind = kind;
|
|
type_info->span = span;
|
|
type_info->resolve_status = RESOLVE_NOT_DONE;
|
|
return type_info;
|
|
}
|
|
|
|
INLINE TypeInfo *type_info_new_base(Type *type, SourceSpan span)
|
|
{
|
|
TypeInfo *type_info = type_info_calloc();
|
|
type_info->kind = TYPE_INFO_IDENTIFIER;
|
|
type_info->resolve_status = RESOLVE_DONE;
|
|
type_info->type = type;
|
|
type_info->span = span;
|
|
return type_info;
|
|
}
|
|
|
|
|
|
INLINE TypeInfoId type_info_id_new_base(Type *type, SourceSpan span)
|
|
{
|
|
return type_infoid(type_info_new_base(type, span));
|
|
}
|
|
|
|
INLINE Type *type_new(TypeKind kind, const char *name)
|
|
{
|
|
Type *type = CALLOCS(Type);
|
|
type->type_kind = kind;
|
|
assert(name);
|
|
type->name = name;
|
|
global_context_add_type(type);
|
|
return type;
|
|
}
|
|
|
|
|
|
INLINE bool type_convert_will_trunc(Type *destination, Type *source)
|
|
{
|
|
assert(type_flat_is_vector(destination) || type_is_builtin(destination->canonical->type_kind));
|
|
assert(type_flat_is_vector(destination) || type_is_builtin(source->canonical->type_kind));
|
|
return type_size(destination) < type_size(source);
|
|
}
|
|
|
|
|
|
|
|
// Useful sanity check function.
|
|
INLINE void advance_and_verify(ParseContext *context, TokenType token_type)
|
|
{
|
|
assert(context->tok == token_type);
|
|
advance(context);
|
|
}
|
|
|
|
|
|
INLINE Type *type_flatten_for_bitstruct(Type *type)
|
|
{
|
|
type = type->canonical;
|
|
RETRY:
|
|
while (type->type_kind == TYPE_DISTINCT)
|
|
{
|
|
type = type->decl->distinct->type;
|
|
}
|
|
if (type->type_kind == TYPE_ENUM)
|
|
{
|
|
type = type->decl->enums.type_info->type->canonical;
|
|
goto RETRY;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
static inline Type *type_base(Type *type)
|
|
{
|
|
while (1)
|
|
{
|
|
type = type->canonical;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct->type;
|
|
break;
|
|
case TYPE_ENUM:
|
|
type = type->decl->enums.type_info->type;
|
|
break;
|
|
case TYPE_OPTIONAL:
|
|
type = type->optional;
|
|
break;
|
|
case TYPE_TYPEDEF:
|
|
UNREACHABLE
|
|
default:
|
|
return type;
|
|
}
|
|
}
|
|
}
|
|
static inline Type *type_flat_distinct_inline(Type *type)
|
|
{
|
|
do
|
|
{
|
|
type = type->canonical;
|
|
if (type->type_kind != TYPE_DISTINCT) break;
|
|
Decl *decl = type->decl;
|
|
if (!decl->is_substruct) break;
|
|
type = decl->distinct->type;
|
|
} while (1);
|
|
return type;
|
|
}
|
|
|
|
static inline Type *type_flatten(Type *type)
|
|
{
|
|
while (1)
|
|
{
|
|
type = type->canonical;
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_DISTINCT:
|
|
type = type->decl->distinct->type;
|
|
break;
|
|
case TYPE_OPTIONAL:
|
|
type = type->optional;
|
|
break;
|
|
case TYPE_TYPEDEF:
|
|
UNREACHABLE
|
|
default:
|
|
return type;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline Type *type_flatten_no_export(Type *type)
|
|
{
|
|
while (1)
|
|
{
|
|
switch (type->type_kind)
|
|
{
|
|
case TYPE_TYPEDEF:
|
|
if (type->decl->is_export) return type;
|
|
type = type->canonical;
|
|
break;
|
|
case TYPE_DISTINCT:
|
|
if (type->decl->is_export) return type;
|
|
type = type->decl->distinct->type;
|
|
break;
|
|
case TYPE_OPTIONAL:
|
|
type = type->optional;
|
|
break;
|
|
default:
|
|
return type;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline bool type_flat_is_char_array(Type *type)
|
|
{
|
|
type = type_flatten(type);
|
|
if (type->type_kind != TYPE_ARRAY) return false;
|
|
switch (type->array.base->type_kind)
|
|
{
|
|
case TYPE_I8:
|
|
case TYPE_U8:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
INLINE Type *type_vector_type(Type *type)
|
|
{
|
|
Type *flatten = type_flatten(type);
|
|
return flatten->type_kind == TYPE_VECTOR ? flatten->array.base : NULL;
|
|
}
|
|
|
|
INLINE bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
|
INLINE bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind < TYPE_U8; }
|
|
INLINE bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U128; }
|
|
INLINE bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_U128; }
|
|
INLINE bool type_kind_is_enumlike(TypeKind kind) { return kind == TYPE_ENUM || kind == TYPE_FAULTTYPE; }
|
|
INLINE bool type_is_unsigned(Type *type) { return type->type_kind >= TYPE_U8 && type->type_kind <= TYPE_U128; }
|
|
INLINE bool type_ok(Type *type) { return !type || type->type_kind != TYPE_POISONED; }
|
|
INLINE bool type_info_ok(TypeInfo *type_info) { return !type_info || type_info->kind != TYPE_INFO_POISON; }
|
|
bool type_is_scalar(Type *type);
|
|
|
|
INLINE bool type_is_signed(Type *type)
|
|
{
|
|
TypeKind kind = type->type_kind;
|
|
if (kind >= TYPE_I8 && kind < TYPE_U8) return true;
|
|
if (kind != TYPE_VECTOR) return false;
|
|
kind = type->array.base->type_kind;
|
|
return kind >= TYPE_I8 && kind < TYPE_U8;
|
|
}
|
|
|
|
INLINE bool type_is_func_ptr(Type *fn_type)
|
|
{
|
|
return fn_type->canonical->type_kind == TYPE_FUNC_PTR;
|
|
}
|
|
|
|
INLINE bool type_is_inferred(Type *type)
|
|
{
|
|
TypeKind kind = type->type_kind;
|
|
return kind == TYPE_INFERRED_VECTOR || kind == TYPE_INFERRED_ARRAY;
|
|
}
|
|
|
|
INLINE bool type_is_number_or_bool(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return (kind >= TYPE_BOOL) && (kind <= TYPE_FLOAT_LAST);
|
|
}
|
|
|
|
INLINE bool type_is_number(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return (kind >= TYPE_I8) && (kind <= TYPE_FLOAT_LAST);
|
|
}
|
|
|
|
INLINE bool type_is_numeric(Type *type)
|
|
{
|
|
RETRY:;
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
if ((kind >= TYPE_I8) & (kind <= TYPE_FLOAT_LAST)) return true;
|
|
if (type->type_kind == TYPE_VECTOR)
|
|
{
|
|
type = type->array.base;
|
|
goto RETRY;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
INLINE bool type_underlying_is_numeric(Type *type)
|
|
{
|
|
return type_is_numeric(type_flatten(type));
|
|
}
|
|
|
|
INLINE bool type_underlying_may_add_sub(Type *type)
|
|
{
|
|
type = type_flatten(type);
|
|
return type->type_kind == TYPE_ENUM || type_is_numeric(type_flatten(type));
|
|
}
|
|
|
|
INLINE bool type_flat_is_vector(Type *type)
|
|
{
|
|
return type_flatten(type)->type_kind == TYPE_VECTOR;
|
|
}
|
|
|
|
INLINE bool type_flat_is_vector_bitstruct(Type *type)
|
|
{
|
|
TypeKind kind = type_flatten(type)->type_kind;
|
|
return kind == TYPE_VECTOR || kind == TYPE_BITSTRUCT;
|
|
}
|
|
|
|
INLINE bool type_kind_is_any_vector(TypeKind kind)
|
|
{
|
|
return kind == TYPE_VECTOR || kind == TYPE_INFERRED_VECTOR;
|
|
}
|
|
|
|
INLINE bool type_flat_is_bool_vector(Type *type)
|
|
{
|
|
Type *flat = type_flatten(type);
|
|
return flat->type_kind == TYPE_VECTOR && type_flatten(flat->array.base) == type_bool;
|
|
}
|
|
|
|
INLINE bool type_is_union_or_strukt(Type *type)
|
|
{
|
|
DECL_TYPE_KIND_REAL(kind, type);
|
|
return kind == TYPE_UNION || kind == TYPE_STRUCT;
|
|
}
|
|
|
|
|
|
INLINE bool decl_ok(Decl *decl)
|
|
{
|
|
return !decl || decl->decl_kind != DECL_POISONED;
|
|
}
|
|
|
|
INLINE bool decl_poison(Decl *decl)
|
|
{
|
|
decl->decl_kind = DECL_POISONED; decl->resolve_status = RESOLVE_DONE; return false;
|
|
}
|
|
|
|
static inline Decl *decl_raw(Decl *decl)
|
|
{
|
|
while (decl->decl_kind == DECL_DEFINE)
|
|
{
|
|
decl = decl->define_decl.alias;
|
|
}
|
|
if (decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED) return decl;
|
|
decl = decl->var.alias;
|
|
assert(decl->decl_kind != DECL_VAR || decl->var.kind != VARDECL_UNWRAPPED);
|
|
return decl;
|
|
}
|
|
|
|
INLINE bool decl_is_struct_type(Decl *decl)
|
|
{
|
|
DeclKind kind = decl->decl_kind;
|
|
return (kind == DECL_UNION) | (kind == DECL_STRUCT);
|
|
}
|
|
|
|
static inline bool decl_is_enum_kind(Decl *decl)
|
|
{
|
|
DeclKind kind = decl->decl_kind;
|
|
return (kind == DECL_ENUM) | (kind == DECL_FAULT);
|
|
}
|
|
|
|
INLINE bool decl_is_user_defined_type(Decl *decl)
|
|
{
|
|
DeclKind kind = decl->decl_kind;
|
|
return (kind == DECL_UNION) | (kind == DECL_STRUCT) | (kind == DECL_BITSTRUCT)
|
|
| (kind == DECL_ENUM) | (kind == DECL_TYPEDEF) || (kind == DECL_DISTINCT);
|
|
}
|
|
|
|
INLINE Decl *decl_flatten(Decl *decl)
|
|
{
|
|
if (decl->decl_kind == DECL_DEFINE)
|
|
{
|
|
return decl->define_decl.alias;
|
|
}
|
|
return decl;
|
|
}
|
|
|
|
static inline DeclKind decl_from_token(TokenType type)
|
|
{
|
|
if (type == TOKEN_STRUCT) return DECL_STRUCT;
|
|
if (type == TOKEN_UNION) return DECL_UNION;
|
|
if (type == TOKEN_BITSTRUCT) return DECL_BITSTRUCT;
|
|
UNREACHABLE
|
|
}
|
|
|
|
INLINE bool expr_is_deref(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_UNARY && expr->unary_expr.operator == UNARYOP_DEREF;
|
|
}
|
|
|
|
INLINE bool expr_is_addr(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_UNARY && expr->unary_expr.operator == UNARYOP_ADDR;
|
|
}
|
|
|
|
INLINE bool expr_is_any_addr(Expr *expr)
|
|
{
|
|
if (expr->expr_kind != EXPR_UNARY) return false;
|
|
switch (expr->unary_expr.operator)
|
|
{
|
|
case UNARYOP_ADDR:
|
|
case UNARYOP_TADDR:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
INLINE bool expr_is_mult(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_BINARY && expr->binary_expr.operator == BINARYOP_MULT;
|
|
}
|
|
|
|
INLINE bool expr_is_neg(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_UNARY && expr->unary_expr.operator == UNARYOP_NEG;
|
|
}
|
|
|
|
INLINE bool expr_is_init_list(Expr *expr)
|
|
{
|
|
ExprKind kind = expr->expr_kind;
|
|
return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST;
|
|
}
|
|
|
|
INLINE bool exprid_is_runtime_const(ExprId expr)
|
|
{
|
|
return expr ? expr_is_runtime_const(exprptr(expr)) : true;
|
|
}
|
|
|
|
INLINE bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; return false; }
|
|
|
|
static inline void expr_list_set_span(Expr **expr, SourceSpan loc);
|
|
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc);
|
|
static inline void expr_set_span(Expr *expr, SourceSpan loc);
|
|
|
|
bool const_init_local_init_may_be_global(ConstInitializer *init);
|
|
ConstInitializer *const_init_new_zero(Type *type);
|
|
ConstInitializer *const_init_new_value(Expr *value);
|
|
ConstInitializer *const_init_new_array(Type *type, ConstInitializer **elements) UNUSED;
|
|
ConstInitializer *const_init_new_struct(Type *type, Expr **elements);
|
|
ConstInitializer *const_init_new_array_full(Type *type, ConstInitializer **elements);
|
|
ConstInitializer *const_init_new_zero_array_value(Type *type, ArrayIndex index);
|
|
ConstInitializer *const_init_new_array_value(Expr *expr, ArrayIndex index);
|
|
void const_init_rewrite_to_value(ConstInitializer *const_init, Expr *value);
|
|
void const_init_rewrite_to_zero(ConstInitializer *init, Type *type);
|
|
|
|
static inline void const_init_set_span(ConstInitializer *init, SourceSpan loc)
|
|
{
|
|
RETRY:
|
|
switch (init->kind)
|
|
{
|
|
case CONST_INIT_ZERO:
|
|
return;
|
|
case CONST_INIT_STRUCT:
|
|
{
|
|
FOREACH(ConstInitializer *, init_val, init->init_struct)
|
|
{
|
|
const_init_set_span(init_val, loc);
|
|
}
|
|
return;
|
|
}
|
|
case CONST_INIT_UNION:
|
|
init = init->init_union.element;
|
|
goto RETRY;
|
|
case CONST_INIT_VALUE:
|
|
expr_set_span(init->init_value, loc);
|
|
return;
|
|
case CONST_INIT_ARRAY:
|
|
{
|
|
FOREACH(ConstInitializer *, init2, init->init_array.elements) const_init_set_span(init2, loc);
|
|
return;
|
|
}
|
|
case CONST_INIT_ARRAY_FULL:
|
|
{
|
|
FOREACH(ConstInitializer *, init2, init->init_array_full) const_init_set_span(init2, loc);
|
|
return;
|
|
}
|
|
case CONST_INIT_ARRAY_VALUE:
|
|
const_init_set_span(init->init_array_value.element, loc);
|
|
return;
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
static inline void expr_list_set_span(Expr **expr, SourceSpan loc);
|
|
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc);
|
|
|
|
static inline void expr_set_span(Expr *expr, SourceSpan loc)
|
|
{
|
|
expr->span = loc;
|
|
switch (expr->expr_kind)
|
|
{
|
|
case EXPR_NAMED_ARGUMENT:
|
|
expr->named_argument_expr.name_span = loc;
|
|
expr_set_span(expr->named_argument_expr.value, loc);
|
|
return;
|
|
case EXPR_CONST:
|
|
switch (expr->const_expr.const_kind)
|
|
{
|
|
case CONST_INITIALIZER:
|
|
const_init_set_span(expr->const_expr.initializer, loc);
|
|
return;
|
|
case CONST_UNTYPED_LIST:
|
|
expr_list_set_span(expr->const_expr.untyped_list, loc);
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
expr_list_set_span(expr->expression_list, loc);
|
|
return;
|
|
case EXPR_CAST:
|
|
exprid_set_span(expr->cast_expr.expr, loc);
|
|
return;
|
|
case EXPR_INITIALIZER_LIST:
|
|
expr_list_set_span(expr->initializer_list, loc);
|
|
return;
|
|
case EXPR_DESIGNATED_INITIALIZER_LIST:
|
|
expr_list_set_span(expr->designated_init_list, loc);
|
|
return;
|
|
case EXPR_SPLAT:
|
|
expr_set_span(expr->inner_expr, loc);
|
|
return;
|
|
case EXPR_EXPRESSION_LIST:
|
|
case EXPR_ACCESS:
|
|
case EXPR_BITACCESS:
|
|
case EXPR_POISONED:
|
|
case EXPR_ASM:
|
|
case EXPR_BUILTIN:
|
|
case EXPR_BINARY:
|
|
case EXPR_BITASSIGN:
|
|
case EXPR_BUILTIN_ACCESS:
|
|
case EXPR_CALL:
|
|
case EXPR_CATCH_UNWRAP:
|
|
case EXPR_COMPILER_CONST:
|
|
case EXPR_COMPOUND_LITERAL:
|
|
case EXPR_COND:
|
|
case EXPR_CT_AND_OR:
|
|
case EXPR_CT_APPEND:
|
|
case EXPR_CT_CONCAT:
|
|
case EXPR_CT_ARG:
|
|
case EXPR_CT_CALL:
|
|
case EXPR_CT_CASTABLE:
|
|
case EXPR_CT_IS_CONST:
|
|
case EXPR_CT_DEFINED:
|
|
case EXPR_CT_EVAL:
|
|
case EXPR_CT_IDENT:
|
|
case EXPR_DECL:
|
|
case EXPR_DESIGNATOR:
|
|
case EXPR_EMBED:
|
|
case EXPR_EXPR_BLOCK:
|
|
case EXPR_OPTIONAL:
|
|
case EXPR_FORCE_UNWRAP:
|
|
case EXPR_GENERIC_IDENT:
|
|
case EXPR_HASH_IDENT:
|
|
case EXPR_IDENTIFIER:
|
|
case EXPR_LAMBDA:
|
|
case EXPR_LAST_FAULT:
|
|
case EXPR_MACRO_BLOCK:
|
|
case EXPR_MACRO_BODY_EXPANSION:
|
|
case EXPR_NOP:
|
|
case EXPR_OPERATOR_CHARS:
|
|
case EXPR_OTHER_CONTEXT:
|
|
case EXPR_POINTER_OFFSET:
|
|
case EXPR_POST_UNARY:
|
|
case EXPR_RETHROW:
|
|
case EXPR_RETVAL:
|
|
case EXPR_SLICE:
|
|
case EXPR_SLICE_ASSIGN:
|
|
case EXPR_SLICE_COPY:
|
|
case EXPR_STRINGIFY:
|
|
case EXPR_SUBSCRIPT:
|
|
case EXPR_SWIZZLE:
|
|
case EXPR_SUBSCRIPT_ADDR:
|
|
case EXPR_SUBSCRIPT_ASSIGN:
|
|
case EXPR_TERNARY:
|
|
case EXPR_BENCHMARK_HOOK:
|
|
case EXPR_TEST_HOOK:
|
|
case EXPR_TRY_UNWRAP:
|
|
case EXPR_TRY_UNWRAP_CHAIN:
|
|
case EXPR_TYPEID:
|
|
case EXPR_TYPEID_INFO:
|
|
case EXPR_TYPEINFO:
|
|
case EXPR_UNARY:
|
|
case EXPR_ANYSWITCH:
|
|
case EXPR_VASPLAT:
|
|
case EXPR_MACRO_BODY:
|
|
case EXPR_DEFAULT_ARG:
|
|
case EXPR_TYPECALL:
|
|
case EXPR_MEMBER_GET:
|
|
break;
|
|
}
|
|
}
|
|
static inline void exprid_set_span(ExprId expr_id, SourceSpan loc)
|
|
{
|
|
if (expr_id) expr_set_span(exprptr(expr_id), loc);
|
|
}
|
|
static inline void expr_list_set_span(Expr **exprs, SourceSpan loc)
|
|
{
|
|
FOREACH(Expr *, expr, exprs) expr_set_span(expr, loc);
|
|
}
|
|
INLINE void expr_replace(Expr *expr, Expr *replacement)
|
|
{
|
|
SourceSpan loc = expr->span;
|
|
*expr = *replacement;
|
|
expr_set_span(expr, loc);
|
|
}
|
|
|
|
INLINE bool expr_ok(Expr *expr) { return expr == NULL || expr->expr_kind != EXPR_POISONED; }
|
|
|
|
INLINE bool exprid_is_simple(ExprId expr_id, bool to_float) { return expr_is_simple(exprptr(expr_id), to_float); }
|
|
|
|
INLINE void expr_resolve_ident(Expr *expr, Decl *decl)
|
|
{
|
|
expr->identifier_expr = (ExprIdentifier) { .decl = decl };
|
|
expr->type = decl->type;
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE Type *exprtype(ExprId expr_id)
|
|
{
|
|
assert(expr_id);
|
|
return exprptr(expr_id)->type;
|
|
}
|
|
|
|
INLINE bool exprid_is_pure(ExprId expr_id)
|
|
{
|
|
return expr_id ? expr_is_pure(exprptr(expr_id)) : false;
|
|
}
|
|
|
|
INLINE Expr *expr_new_expr(ExprKind kind, Expr *expr)
|
|
{
|
|
return expr_new(kind, expr->span);
|
|
}
|
|
|
|
INLINE bool type_is_promotable_int_bool(Type *type)
|
|
{
|
|
// If we support other architectures, update this.
|
|
return type_is_integer_or_bool_kind(type) && type->builtin.bitsize < compiler.platform.width_c_int;
|
|
}
|
|
|
|
INLINE bool type_is_promotable_float(Type *type)
|
|
{
|
|
// If we support other architectures, update this.
|
|
return type_is_float(type->canonical) && type->builtin.bytesize < type_double->builtin.bytesize;
|
|
}
|
|
|
|
|
|
/**
|
|
* Minimum alignment, values are either offsets or alignments.
|
|
* @return
|
|
*/
|
|
INLINE AlignSize type_min_alignment(AlignSize a, AlignSize b)
|
|
{
|
|
return (a | b) & (1 + ~(a | b));
|
|
}
|
|
|
|
/**
|
|
* Max highest required alignment
|
|
*/
|
|
INLINE AlignSize type_max_alignment(AlignSize a, AlignSize b)
|
|
{
|
|
return a < b ? b : a;
|
|
}
|
|
|
|
INLINE BitSize type_bit_size(Type *type)
|
|
{
|
|
return type_size(type) * 8;
|
|
}
|
|
|
|
bool obj_format_linking_supported(ObjectFormatType format_type);
|
|
bool static_lib_linker(const char *output_file, const char **files, unsigned file_count);
|
|
bool dynamic_lib_linker(const char *output_file, const char **files, unsigned file_count);
|
|
bool linker(const char *output_file, const char **files, unsigned file_count);
|
|
void platform_linker(const char *output_file, const char **files, unsigned file_count);
|
|
const char *cc_compiler(const char *cc, const char *file, const char *flags, const char **include_dirs, const char *output_subdir);
|
|
const char *arch_to_linker_arch(ArchType arch);
|
|
extern char swizzle[256];
|
|
|
|
#define CAT(a,b) CAT2(a,b) // force expand
|
|
#define CAT2(a,b) a##b // actually concatenate
|
|
#define TEMP(X) CAT(X, __LINE__)
|
|
#define ASSIGN_AST_OR_RET(_assign, _ast_stmt, _res) Ast* TEMP(_ast) = (_ast_stmt); if (!ast_ok(TEMP(_ast))) return _res; _assign = TEMP(_ast)
|
|
#define ASSIGN_ASTID_OR_RET(_assign, _ast_stmt, _res) Ast* TEMP(_ast) = (_ast_stmt); if (!ast_ok(TEMP(_ast))) return _res; _assign = astid(TEMP(_ast))
|
|
#define ASSIGN_EXPR_OR_RET(_assign, _expr_stmt, _res) Expr* TEMP(_expr) = (_expr_stmt); if (!expr_ok(TEMP(_expr))) return _res; _assign = TEMP(_expr)
|
|
#define ASSIGN_EXPRID_OR_RET(_assign, _expr_stmt, _res) Expr* TEMP(_expr) = (_expr_stmt); if (!expr_ok(TEMP(_expr))) return _res; _assign = exprid(TEMP(_expr))
|
|
#define ASSIGN_TYPE_OR_RET(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = TEMP(_type)
|
|
#define ASSIGN_TYPEID_OR_RET(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = type_infoid(TEMP(_type))
|
|
#define ASSIGN_DECL_OR_RET(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl)
|
|
#define ASSIGN_DECLID_OR_RET(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl) ? declid(TEMP(_decl)) : 0
|
|
|
|
|
|
|
|
INLINE void ast_append(AstId **succ, Ast *next)
|
|
{
|
|
**succ = astid(next);
|
|
*succ = &next->next;
|
|
}
|
|
|
|
INLINE bool ast_ok(Ast *ast) { return ast == NULL || ast->ast_kind != AST_POISONED; }
|
|
|
|
INLINE bool ast_poison(Ast *ast) { ast->ast_kind = AST_POISONED; return false; }
|
|
|
|
INLINE Ast *new_ast(AstKind kind, SourceSpan range)
|
|
{
|
|
Ast *ast = ast_calloc();
|
|
ast->span = range;
|
|
ast->ast_kind = kind;
|
|
return ast;
|
|
}
|
|
|
|
INLINE Ast *ast_last(Ast *ast)
|
|
{
|
|
while (ast->next) ast = astptr(ast->next);
|
|
return ast;
|
|
}
|
|
|
|
INLINE void ast_prepend(AstId *first, Ast *ast)
|
|
{
|
|
Ast *end = ast;
|
|
while (end->next)
|
|
{
|
|
end = astptr(end->next);
|
|
}
|
|
end->next = *first;
|
|
*first = astid(ast);
|
|
}
|
|
|
|
|
|
INLINE Ast *ast_next(AstId *current_ptr)
|
|
{
|
|
Ast *ast = astptr(*current_ptr);
|
|
*current_ptr = ast->next;
|
|
return ast;
|
|
}
|
|
|
|
|
|
|
|
|
|
INLINE void expr_rewrite_const_bool(Expr *expr, Type *type, bool b)
|
|
{
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
expr->const_expr = (ExprConst) { .b = b, .const_kind = CONST_BOOL };
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_null(Expr *expr, Type *type)
|
|
{
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
expr->const_expr = (ExprConst) { .ptr = 0, .const_kind = CONST_POINTER };
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_empty_slice(Expr *expr, Type *type)
|
|
{
|
|
assert(type_flatten(type)->type_kind == TYPE_SLICE);
|
|
expr->const_expr = (ExprConst) { .const_kind = CONST_SLICE, .initializer = NULL };
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_untyped_list(Expr *expr, Expr **elements)
|
|
{
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type_untypedlist;
|
|
expr->const_expr = (ExprConst) { .untyped_list = elements, .const_kind = CONST_UNTYPED_LIST };
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_initializer(Expr *expr, Type *type, ConstInitializer *initializer)
|
|
{
|
|
assert(type_flatten(type)->type_kind != TYPE_SLICE);
|
|
assert(type != type_untypedlist);
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
expr->const_expr = (ExprConst) { .initializer = initializer, .const_kind = CONST_INITIALIZER };
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_slice(Expr *expr, Type *type, ConstInitializer *initializer)
|
|
{
|
|
assert(type_flatten(type)->type_kind == TYPE_SLICE);
|
|
assert(type != type_untypedlist);
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
expr->const_expr = (ExprConst) { .slice_init = initializer, .const_kind = CONST_SLICE };
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type)
|
|
{
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->const_expr.const_kind = CONST_TYPEID;
|
|
expr->const_expr.typeid = type->canonical;
|
|
expr->type = type_typeid;
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v)
|
|
{
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
TypeKind kind = type_flatten(type)->type_kind;
|
|
(&expr->const_expr)->ixx.i.high = 0;
|
|
if (type_kind_is_signed(kind))
|
|
{
|
|
if (v > (uint64_t)INT64_MAX) (&expr->const_expr)->ixx.i.high = UINT64_MAX;
|
|
}
|
|
else
|
|
{
|
|
switch (kind)
|
|
{
|
|
case TYPE_U8:
|
|
v &= 0xFF;
|
|
break;
|
|
case TYPE_U16:
|
|
v &= 0xFFFF;
|
|
break;
|
|
case TYPE_U32:
|
|
v &= 0xFFFFFFFF;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
(&expr->const_expr)->ixx.i.low = v;
|
|
(&expr->const_expr)->ixx.type = kind;
|
|
(&expr->const_expr)->is_character = false;
|
|
(&expr->const_expr)->const_kind = CONST_INTEGER;
|
|
}
|
|
|
|
INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d)
|
|
{
|
|
expr->expr_kind = EXPR_CONST;
|
|
expr->type = type;
|
|
TypeKind kind = type_flatten(type)->type_kind;
|
|
Real real;
|
|
switch (kind)
|
|
{
|
|
case TYPE_F16:
|
|
case TYPE_BF16:
|
|
case TYPE_F32:
|
|
real = (float)d;
|
|
break;
|
|
case TYPE_F64:
|
|
real = (double)d;
|
|
break;
|
|
default:
|
|
REMINDER("Handling of float type may not be accurate");
|
|
real = d;
|
|
break;
|
|
}
|
|
expr->const_expr = (ExprConst) {
|
|
.fxx = (Float){ real, kind },
|
|
.const_kind = CONST_FLOAT,
|
|
};
|
|
expr->resolve_status = RESOLVE_DONE;
|
|
}
|
|
|
|
INLINE const char *asm_clobber_by_index(unsigned index)
|
|
{
|
|
return compiler.platform.clobber_name_list[index];
|
|
}
|
|
|
|
INLINE AsmRegister *asm_reg_by_index(unsigned index)
|
|
{
|
|
return &compiler.platform.registers[index];
|
|
}
|
|
|
|
INLINE void clobbers_add(Clobbers *clobbers, unsigned index)
|
|
{
|
|
assert(index < MAX_CLOBBER_FLAGS);
|
|
unsigned bit = index % 64;
|
|
unsigned element = index / 64;
|
|
clobbers->mask[element] |= (1ull << bit);
|
|
}
|
|
|
|
static inline Clobbers clobbers_make_from(Clobbers clobbers, ...)
|
|
{
|
|
va_list list;
|
|
va_start(list, clobbers);
|
|
int i;
|
|
while ((i = va_arg(list, int)) > -1)
|
|
{
|
|
assert(i < MAX_CLOBBER_FLAGS);
|
|
unsigned bit = i % 64;
|
|
unsigned element = i / 64;
|
|
clobbers.mask[element] |= (1ull << bit);
|
|
}
|
|
va_end(list);
|
|
return clobbers;
|
|
}
|
|
|
|
static inline Clobbers clobbers_make(unsigned index, ...)
|
|
{
|
|
Clobbers clobbers = { .mask[0] = 0 };
|
|
assert(index < MAX_CLOBBER_FLAGS);
|
|
unsigned bit = index % 64;
|
|
unsigned element = index / 64;
|
|
clobbers.mask[element] |= (1ull << bit);
|
|
va_list list;
|
|
va_start(list, index);
|
|
int i;
|
|
while ((i = va_arg(list, int)) > -1)
|
|
{
|
|
assert(i < MAX_CLOBBER_FLAGS);
|
|
bit = i % 64;
|
|
element = i / 64;
|
|
clobbers.mask[element] |= (1ull << bit);
|
|
}
|
|
va_end(list);
|
|
return clobbers;
|
|
}
|
|
|
|
|
|
INLINE unsigned arg_bits_max(AsmArgBits bits, unsigned limit)
|
|
{
|
|
if (limit == 0) limit = ~(0u);
|
|
if (limit >= 128 && (bits & ARG_BITS_128)) return 128;
|
|
if (limit >= 80 && (bits & ARG_BITS_80)) return 80;
|
|
if (limit >= 64 && (bits & ARG_BITS_64)) return 64;
|
|
if (limit >= 32 && (bits & ARG_BITS_32)) return 32;
|
|
if (limit >= 20 && (bits & ARG_BITS_20)) return 20;
|
|
if (limit >= 16 && (bits & ARG_BITS_16)) return 16;
|
|
if (limit >= 12 && (bits & ARG_BITS_12)) return 12;
|
|
if (limit >= 8 && (bits & ARG_BITS_8)) return 8;
|
|
if (limit >= 5 && (bits & ARG_BITS_5)) return 5;
|
|
return 0;
|
|
}
|
|
|
|
INLINE bool expr_is_empty_const_slice(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST
|
|
&& expr->const_expr.const_kind == CONST_SLICE
|
|
&& expr->const_expr.slice_init == NULL;
|
|
}
|
|
|
|
INLINE bool expr_is_const(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST;
|
|
}
|
|
|
|
INLINE bool decl_var_kind_is_ct(VarDeclKind kind)
|
|
{
|
|
return kind >= VARDECL_FIRST_CT && kind <= VARDECL_LAST_CT;
|
|
}
|
|
|
|
|
|
static inline bool decl_is_var_local(Decl *decl)
|
|
{
|
|
if (decl->decl_kind != DECL_VAR) return false;
|
|
VarDeclKind kind = decl->var.kind;
|
|
return kind == VARDECL_PARAM_CT_TYPE
|
|
|| kind == VARDECL_PARAM
|
|
|| kind == VARDECL_PARAM_CT
|
|
|| kind == VARDECL_LOCAL
|
|
|| kind == VARDECL_LOCAL_CT_TYPE
|
|
|| kind == VARDECL_LOCAL_CT
|
|
|| kind == VARDECL_PARAM_REF
|
|
|| kind == VARDECL_PARAM_EXPR
|
|
|| kind == VARDECL_BITMEMBER
|
|
|| kind == VARDECL_MEMBER;
|
|
}
|
|
|
|
INLINE bool expr_is_const_string(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_STRING;
|
|
}
|
|
|
|
INLINE bool expr_is_const_enum(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ENUM;
|
|
}
|
|
|
|
INLINE bool expr_is_const_fault(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ERR;
|
|
}
|
|
|
|
INLINE bool expr_is_const_pointer(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_POINTER;
|
|
}
|
|
|
|
INLINE bool expr_is_const_bool(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_BOOL;
|
|
}
|
|
|
|
INLINE bool expr_is_const_initializer(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER;
|
|
}
|
|
|
|
INLINE bool expr_is_const_slice(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_SLICE;
|
|
}
|
|
|
|
INLINE bool expr_is_const_bytes(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_BYTES;
|
|
}
|
|
|
|
INLINE bool expr_is_const_untyped_list(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_UNTYPED_LIST;
|
|
}
|
|
|
|
INLINE bool expr_is_const_int(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INTEGER;
|
|
}
|
|
|
|
INLINE bool expr_is_const_member(Expr *expr)
|
|
{
|
|
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_MEMBER;
|
|
}
|
|
|
|
INLINE bool check_module_name(Path *path)
|
|
{
|
|
if (!str_is_valid_module_name(path->module))
|
|
{
|
|
RETURN_PRINT_ERROR_AT(false, path, "A module name may not have any uppercase characters, trailing, leading or double '_'");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const char *default_c_compiler(void); |