refactor out the horrible beast that was codegen_node
parent
d4b8852d78
commit
3ef2f7058b
|
@ -0,0 +1,928 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef ZIG_ALL_TYPES_HPP
|
||||
#define ZIG_ALL_TYPES_HPP
|
||||
|
||||
#include "list.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "zig_llvm.hpp"
|
||||
#include "hash_map.hpp"
|
||||
#include "errmsg.hpp"
|
||||
|
||||
struct AstNode;
|
||||
struct ImportTableEntry;
|
||||
struct AsmToken;
|
||||
struct FnTableEntry;
|
||||
struct BlockContext;
|
||||
struct TypeTableEntry;
|
||||
struct VariableTableEntry;
|
||||
struct Cast;
|
||||
struct BuiltinFnEntry;
|
||||
struct LabelTableEntry;
|
||||
struct TypeStructField;
|
||||
struct CodeGen;
|
||||
|
||||
enum OutType {
|
||||
OutTypeUnknown,
|
||||
OutTypeExe,
|
||||
OutTypeLib,
|
||||
OutTypeObj,
|
||||
};
|
||||
|
||||
enum CodeGenBuildType {
|
||||
CodeGenBuildTypeDebug,
|
||||
CodeGenBuildTypeRelease,
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
CastOpNothing,
|
||||
CastOpPtrToInt,
|
||||
CastOpIntWidenOrShorten,
|
||||
CastOpToUnknownSizeArray,
|
||||
CastOpMaybeWrap,
|
||||
CastOpPointerReinterpret,
|
||||
};
|
||||
|
||||
struct Cast {
|
||||
CastOp op;
|
||||
// if op is CastOpArrayToString, this will be a pointer to
|
||||
// the string struct on the stack
|
||||
LLVMValueRef ptr;
|
||||
TypeTableEntry *after_type;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
struct Expr {
|
||||
TypeTableEntry *type_entry;
|
||||
// the context in which this expression is evaluated.
|
||||
// for blocks, this points to the containing scope, not the block's own scope for its children.
|
||||
BlockContext *block_context;
|
||||
|
||||
// may be null for no cast
|
||||
Cast implicit_cast; // happens first
|
||||
Cast implicit_maybe_cast; // happens second
|
||||
};
|
||||
|
||||
struct NumLitCodeGen {
|
||||
TypeTableEntry *resolved_type;
|
||||
};
|
||||
|
||||
struct StructValExprCodeGen {
|
||||
TypeTableEntry *type_entry;
|
||||
LLVMValueRef ptr;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
struct TopLevelDecl {
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps;
|
||||
Buf *name;
|
||||
ImportTableEntry *import;
|
||||
// set this flag temporarily to detect infinite loops
|
||||
bool in_current_deps;
|
||||
};
|
||||
|
||||
enum NodeType {
|
||||
NodeTypeRoot,
|
||||
NodeTypeRootExportDecl,
|
||||
NodeTypeFnProto,
|
||||
NodeTypeFnDef,
|
||||
NodeTypeFnDecl,
|
||||
NodeTypeParamDecl,
|
||||
NodeTypeType,
|
||||
NodeTypeBlock,
|
||||
NodeTypeExternBlock,
|
||||
NodeTypeDirective,
|
||||
NodeTypeReturnExpr,
|
||||
NodeTypeVariableDeclaration,
|
||||
NodeTypeBinOpExpr,
|
||||
NodeTypeCastExpr,
|
||||
NodeTypeNumberLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
NodeTypeCharLiteral,
|
||||
NodeTypeUnreachable,
|
||||
NodeTypeSymbol,
|
||||
NodeTypePrefixOpExpr,
|
||||
NodeTypeFnCallExpr,
|
||||
NodeTypeArrayAccessExpr,
|
||||
NodeTypeSliceExpr,
|
||||
NodeTypeFieldAccessExpr,
|
||||
NodeTypeUse,
|
||||
NodeTypeVoid,
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
NodeTypeIfBoolExpr,
|
||||
NodeTypeIfVarExpr,
|
||||
NodeTypeWhileExpr,
|
||||
NodeTypeLabel,
|
||||
NodeTypeGoto,
|
||||
NodeTypeBreak,
|
||||
NodeTypeContinue,
|
||||
NodeTypeAsmExpr,
|
||||
NodeTypeStructDecl,
|
||||
NodeTypeStructField,
|
||||
NodeTypeStructValueExpr,
|
||||
NodeTypeStructValueField,
|
||||
NodeTypeEnumDecl,
|
||||
NodeTypeEnumField,
|
||||
NodeTypeCompilerFnExpr,
|
||||
NodeTypeCompilerFnType,
|
||||
};
|
||||
|
||||
struct AstNodeRoot {
|
||||
ZigList<AstNode *> top_level_decls;
|
||||
};
|
||||
|
||||
enum VisibMod {
|
||||
VisibModPrivate,
|
||||
VisibModPub,
|
||||
VisibModExport,
|
||||
};
|
||||
|
||||
struct AstNodeFnProto {
|
||||
ZigList<AstNode *> *directives;
|
||||
VisibMod visib_mod;
|
||||
Buf name;
|
||||
ZigList<AstNode *> params;
|
||||
AstNode *return_type;
|
||||
bool is_var_args;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
|
||||
// the extern block this fn proto is inside. can be null.
|
||||
AstNode *extern_node;
|
||||
// the struct decl node this fn proto is inside. can be null.
|
||||
AstNode *struct_node;
|
||||
// the function definition this fn proto is inside. can be null.
|
||||
AstNode *fn_def_node;
|
||||
FnTableEntry *fn_table_entry;
|
||||
bool skip;
|
||||
TopLevelDecl top_level_decl;
|
||||
};
|
||||
|
||||
struct AstNodeFnDef {
|
||||
AstNode *fn_proto;
|
||||
AstNode *body;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *implicit_return_type;
|
||||
BlockContext *block_context;
|
||||
};
|
||||
|
||||
struct AstNodeFnDecl {
|
||||
AstNode *fn_proto;
|
||||
};
|
||||
|
||||
struct AstNodeParamDecl {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
|
||||
// populated by semantic analyzer
|
||||
VariableTableEntry *variable;
|
||||
};
|
||||
|
||||
enum AstNodeTypeType {
|
||||
AstNodeTypeTypePrimitive,
|
||||
AstNodeTypeTypePointer,
|
||||
AstNodeTypeTypeArray,
|
||||
AstNodeTypeTypeMaybe,
|
||||
AstNodeTypeTypeCompilerExpr,
|
||||
};
|
||||
|
||||
struct AstNodeType {
|
||||
AstNodeTypeType type;
|
||||
Buf primitive_name;
|
||||
AstNode *child_type;
|
||||
AstNode *array_size; // can be null
|
||||
bool is_const;
|
||||
bool is_noalias;
|
||||
AstNode *compiler_expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *entry;
|
||||
};
|
||||
|
||||
struct AstNodeBlock {
|
||||
ZigList<AstNode *> statements;
|
||||
|
||||
// populated by semantic analyzer
|
||||
BlockContext *block_context;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeReturnExpr {
|
||||
// might be null in case of return void;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeVariableDeclaration {
|
||||
Buf symbol;
|
||||
bool is_const;
|
||||
VisibMod visib_mod;
|
||||
// one or both of type and expr will be non null
|
||||
AstNode *type;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TopLevelDecl top_level_decl;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
enum BinOpType {
|
||||
BinOpTypeInvalid,
|
||||
BinOpTypeAssign,
|
||||
BinOpTypeAssignTimes,
|
||||
BinOpTypeAssignDiv,
|
||||
BinOpTypeAssignMod,
|
||||
BinOpTypeAssignPlus,
|
||||
BinOpTypeAssignMinus,
|
||||
BinOpTypeAssignBitShiftLeft,
|
||||
BinOpTypeAssignBitShiftRight,
|
||||
BinOpTypeAssignBitAnd,
|
||||
BinOpTypeAssignBitXor,
|
||||
BinOpTypeAssignBitOr,
|
||||
BinOpTypeAssignBoolAnd,
|
||||
BinOpTypeAssignBoolOr,
|
||||
BinOpTypeBoolOr,
|
||||
BinOpTypeBoolAnd,
|
||||
BinOpTypeCmpEq,
|
||||
BinOpTypeCmpNotEq,
|
||||
BinOpTypeCmpLessThan,
|
||||
BinOpTypeCmpGreaterThan,
|
||||
BinOpTypeCmpLessOrEq,
|
||||
BinOpTypeCmpGreaterOrEq,
|
||||
BinOpTypeBinOr,
|
||||
BinOpTypeBinXor,
|
||||
BinOpTypeBinAnd,
|
||||
BinOpTypeBitShiftLeft,
|
||||
BinOpTypeBitShiftRight,
|
||||
BinOpTypeAdd,
|
||||
BinOpTypeSub,
|
||||
BinOpTypeMult,
|
||||
BinOpTypeDiv,
|
||||
BinOpTypeMod,
|
||||
BinOpTypeUnwrapMaybe,
|
||||
};
|
||||
|
||||
struct AstNodeBinOpExpr {
|
||||
AstNode *op1;
|
||||
BinOpType bin_op;
|
||||
AstNode *op2;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
// for when op is BinOpTypeAssign
|
||||
VariableTableEntry *var_entry;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeFnCallExpr {
|
||||
AstNode *fn_ref_expr;
|
||||
ZigList<AstNode *> params;
|
||||
bool is_builtin;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
BuiltinFnEntry *builtin_fn;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeArrayAccessExpr {
|
||||
AstNode *array_ref_expr;
|
||||
AstNode *subscript;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeSliceExpr {
|
||||
AstNode *array_ref_expr;
|
||||
AstNode *start;
|
||||
AstNode *end;
|
||||
bool is_const;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
Expr resolved_expr;
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
};
|
||||
|
||||
struct AstNodeFieldAccessExpr {
|
||||
AstNode *struct_expr;
|
||||
Buf field_name;
|
||||
|
||||
// populated by semantic analyzer
|
||||
int field_index;
|
||||
TypeStructField *type_struct_field;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeExternBlock {
|
||||
ZigList<AstNode *> *directives;
|
||||
ZigList<AstNode *> fn_decls;
|
||||
};
|
||||
|
||||
struct AstNodeDirective {
|
||||
Buf name;
|
||||
Buf param;
|
||||
};
|
||||
|
||||
struct AstNodeRootExportDecl {
|
||||
Buf type;
|
||||
Buf name;
|
||||
ZigList<AstNode *> *directives;
|
||||
};
|
||||
|
||||
struct AstNodeCastExpr {
|
||||
AstNode *expr;
|
||||
AstNode *type;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Cast cast;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
enum PrefixOp {
|
||||
PrefixOpInvalid,
|
||||
PrefixOpBoolNot,
|
||||
PrefixOpBinNot,
|
||||
PrefixOpNegation,
|
||||
PrefixOpAddressOf,
|
||||
PrefixOpConstAddressOf,
|
||||
PrefixOpDereference,
|
||||
};
|
||||
|
||||
struct AstNodePrefixOpExpr {
|
||||
PrefixOp prefix_op;
|
||||
AstNode *primary_expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeUse {
|
||||
Buf path;
|
||||
ZigList<AstNode *> *directives;
|
||||
|
||||
// populated by semantic analyzer
|
||||
ImportTableEntry *import;
|
||||
};
|
||||
|
||||
struct AstNodeIfBoolExpr {
|
||||
AstNode *condition;
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeIfVarExpr {
|
||||
AstNodeVariableDeclaration var_decl;
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *type;
|
||||
BlockContext *block_context;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeWhileExpr {
|
||||
AstNode *condition;
|
||||
AstNode *body;
|
||||
|
||||
// populated by semantic analyzer
|
||||
bool condition_always_true;
|
||||
bool contains_break;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeLabel {
|
||||
Buf name;
|
||||
|
||||
// populated by semantic analyzer
|
||||
LabelTableEntry *label_entry;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeGoto {
|
||||
Buf name;
|
||||
|
||||
// populated by semantic analyzer
|
||||
LabelTableEntry *label_entry;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AsmOutput {
|
||||
Buf asm_symbolic_name;
|
||||
Buf constraint;
|
||||
Buf variable_name;
|
||||
AstNode *return_type; // null unless "=r" and return
|
||||
};
|
||||
|
||||
struct AsmInput {
|
||||
Buf asm_symbolic_name;
|
||||
Buf constraint;
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct SrcPos {
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct AstNodeAsmExpr {
|
||||
bool is_volatile;
|
||||
Buf asm_template;
|
||||
ZigList<SrcPos> offset_map;
|
||||
ZigList<AsmToken> token_list;
|
||||
ZigList<AsmOutput*> output_list;
|
||||
ZigList<AsmInput*> input_list;
|
||||
ZigList<Buf*> clobber_list;
|
||||
|
||||
// populated by semantic analyzer
|
||||
int return_count;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeStructDecl {
|
||||
Buf name;
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> fns;
|
||||
ZigList<AstNode *> *directives;
|
||||
VisibMod visib_mod;
|
||||
|
||||
// populated by semantic analyzer
|
||||
TypeTableEntry *type_entry;
|
||||
TopLevelDecl top_level_decl;
|
||||
};
|
||||
|
||||
struct AstNodeStructField {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
ZigList<AstNode *> *directives;
|
||||
};
|
||||
|
||||
struct AstNodeEnumDecl {
|
||||
Buf name;
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> *directives;
|
||||
VisibMod visib_mod;
|
||||
};
|
||||
|
||||
struct AstNodeEnumField {
|
||||
Buf name;
|
||||
ZigList<AstNode *> fields; // length 0 means simple enum
|
||||
AstNode *val_expr;
|
||||
};
|
||||
|
||||
struct AstNodeStringLiteral {
|
||||
Buf buf;
|
||||
bool c;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeCharLiteral {
|
||||
uint8_t value;
|
||||
|
||||
// populated by semantic analyzer:
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
enum NumLit {
|
||||
NumLitF32,
|
||||
NumLitF64,
|
||||
NumLitF128,
|
||||
NumLitU8,
|
||||
NumLitU16,
|
||||
NumLitU32,
|
||||
NumLitU64,
|
||||
NumLitI8,
|
||||
NumLitI16,
|
||||
NumLitI32,
|
||||
NumLitI64,
|
||||
|
||||
NumLitCount
|
||||
};
|
||||
|
||||
struct AstNodeNumberLiteral {
|
||||
NumLit kind;
|
||||
|
||||
// overflow is true if when parsing the number, we discovered it would not
|
||||
// fit without losing data in a uint64_t, int64_t, or double
|
||||
bool overflow;
|
||||
|
||||
union {
|
||||
uint64_t x_uint;
|
||||
int64_t x_int;
|
||||
double x_float;
|
||||
} data;
|
||||
|
||||
// populated by semantic analyzer
|
||||
NumLitCodeGen codegen;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeStructValueField {
|
||||
Buf name;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
int index;
|
||||
};
|
||||
|
||||
struct AstNodeStructValueExpr {
|
||||
AstNode *type;
|
||||
ZigList<AstNode *> fields;
|
||||
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen codegen;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeCompilerFnExpr {
|
||||
Buf name;
|
||||
AstNode *expr;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeCompilerFnType {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
NumLitCodeGen resolved_num_lit;
|
||||
};
|
||||
|
||||
struct AstNodeNullLiteral {
|
||||
// populated by semantic analyzer
|
||||
StructValExprCodeGen resolved_struct_val_expr;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeVoidExpr {
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeUnreachableExpr {
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeSymbolExpr {
|
||||
Buf symbol;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeBoolLiteral {
|
||||
bool value;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeBreakExpr {
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNodeContinueExpr {
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
struct AstNode {
|
||||
enum NodeType type;
|
||||
int line;
|
||||
int column;
|
||||
uint32_t create_index; // for determinism purposes
|
||||
ImportTableEntry *owner;
|
||||
union {
|
||||
AstNodeRoot root;
|
||||
AstNodeRootExportDecl root_export_decl;
|
||||
AstNodeFnDef fn_def;
|
||||
AstNodeFnDecl fn_decl;
|
||||
AstNodeFnProto fn_proto;
|
||||
AstNodeType type;
|
||||
AstNodeParamDecl param_decl;
|
||||
AstNodeBlock block;
|
||||
AstNodeReturnExpr return_expr;
|
||||
AstNodeVariableDeclaration variable_declaration;
|
||||
AstNodeBinOpExpr bin_op_expr;
|
||||
AstNodeExternBlock extern_block;
|
||||
AstNodeDirective directive;
|
||||
AstNodeCastExpr cast_expr;
|
||||
AstNodePrefixOpExpr prefix_op_expr;
|
||||
AstNodeFnCallExpr fn_call_expr;
|
||||
AstNodeArrayAccessExpr array_access_expr;
|
||||
AstNodeSliceExpr slice_expr;
|
||||
AstNodeUse use;
|
||||
AstNodeIfBoolExpr if_bool_expr;
|
||||
AstNodeIfVarExpr if_var_expr;
|
||||
AstNodeWhileExpr while_expr;
|
||||
AstNodeLabel label;
|
||||
AstNodeGoto goto_expr;
|
||||
AstNodeAsmExpr asm_expr;
|
||||
AstNodeFieldAccessExpr field_access_expr;
|
||||
AstNodeStructDecl struct_decl;
|
||||
AstNodeStructField struct_field;
|
||||
AstNodeEnumDecl enum_decl;
|
||||
AstNodeEnumField enum_field;
|
||||
AstNodeStringLiteral string_literal;
|
||||
AstNodeCharLiteral char_literal;
|
||||
AstNodeNumberLiteral number_literal;
|
||||
AstNodeStructValueExpr struct_val_expr;
|
||||
AstNodeStructValueField struct_val_field;
|
||||
AstNodeCompilerFnExpr compiler_fn_expr;
|
||||
AstNodeCompilerFnType compiler_fn_type;
|
||||
AstNodeNullLiteral null_literal;
|
||||
AstNodeVoidExpr void_expr;
|
||||
AstNodeUnreachableExpr unreachable_expr;
|
||||
AstNodeSymbolExpr symbol_expr;
|
||||
AstNodeBoolLiteral bool_literal;
|
||||
AstNodeBreakExpr break_expr;
|
||||
AstNodeContinueExpr continue_expr;
|
||||
} data;
|
||||
};
|
||||
|
||||
enum AsmTokenId {
|
||||
AsmTokenIdTemplate,
|
||||
AsmTokenIdPercent,
|
||||
AsmTokenIdVar,
|
||||
};
|
||||
|
||||
struct AsmToken {
|
||||
enum AsmTokenId id;
|
||||
int start;
|
||||
int end;
|
||||
};
|
||||
|
||||
struct TypeTableEntryPointer {
|
||||
TypeTableEntry *child_type;
|
||||
bool is_const;
|
||||
bool is_noalias;
|
||||
};
|
||||
|
||||
struct TypeTableEntryInt {
|
||||
bool is_signed;
|
||||
};
|
||||
|
||||
struct TypeTableEntryArray {
|
||||
TypeTableEntry *child_type;
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
struct TypeStructField {
|
||||
Buf *name;
|
||||
TypeTableEntry *type_entry;
|
||||
};
|
||||
|
||||
struct TypeTableEntryStruct {
|
||||
AstNode *decl_node;
|
||||
bool is_packed;
|
||||
int field_count;
|
||||
TypeStructField *fields;
|
||||
uint64_t size_bytes;
|
||||
bool is_invalid; // true if any fields are invalid
|
||||
bool is_unknown_size_array;
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
|
||||
|
||||
// set this flag temporarily to detect infinite loops
|
||||
bool embedded_in_current;
|
||||
bool reported_infinite_err;
|
||||
};
|
||||
|
||||
struct TypeTableEntryNumLit {
|
||||
NumLit kind;
|
||||
};
|
||||
|
||||
struct TypeTableEntryMaybe {
|
||||
TypeTableEntry *child_type;
|
||||
};
|
||||
|
||||
enum TypeTableEntryId {
|
||||
TypeTableEntryIdInvalid,
|
||||
TypeTableEntryIdVoid,
|
||||
TypeTableEntryIdBool,
|
||||
TypeTableEntryIdUnreachable,
|
||||
TypeTableEntryIdInt,
|
||||
TypeTableEntryIdFloat,
|
||||
TypeTableEntryIdPointer,
|
||||
TypeTableEntryIdArray,
|
||||
TypeTableEntryIdStruct,
|
||||
TypeTableEntryIdNumberLiteral,
|
||||
TypeTableEntryIdMaybe,
|
||||
};
|
||||
|
||||
struct TypeTableEntry {
|
||||
TypeTableEntryId id;
|
||||
|
||||
LLVMTypeRef type_ref;
|
||||
LLVMZigDIType *di_type;
|
||||
uint64_t size_in_bits;
|
||||
uint64_t align_in_bits;
|
||||
|
||||
Buf name;
|
||||
|
||||
union {
|
||||
TypeTableEntryPointer pointer;
|
||||
TypeTableEntryInt integral;
|
||||
TypeTableEntryArray array;
|
||||
TypeTableEntryStruct structure;
|
||||
TypeTableEntryNumLit num_lit;
|
||||
TypeTableEntryMaybe maybe;
|
||||
} data;
|
||||
|
||||
// use these fields to make sure we don't duplicate type table entries for the same type
|
||||
TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
|
||||
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
|
||||
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
|
||||
TypeTableEntry *maybe_parent;
|
||||
|
||||
};
|
||||
|
||||
struct ImporterInfo {
|
||||
ImportTableEntry *import;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
struct ImportTableEntry {
|
||||
AstNode *root;
|
||||
Buf *path; // relative to root_source_dir
|
||||
LLVMZigDIFile *di_file;
|
||||
Buf *source_code;
|
||||
ZigList<int> *line_offsets;
|
||||
BlockContext *block_context;
|
||||
ZigList<ImporterInfo> importers;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
|
||||
};
|
||||
|
||||
struct LabelTableEntry {
|
||||
AstNode *label_node;
|
||||
LLVMBasicBlockRef basic_block;
|
||||
bool used;
|
||||
bool entered_from_fallthrough;
|
||||
};
|
||||
|
||||
enum FnAttrId {
|
||||
FnAttrIdNaked,
|
||||
FnAttrIdAlwaysInline,
|
||||
};
|
||||
|
||||
struct FnTableEntry {
|
||||
LLVMValueRef fn_value;
|
||||
AstNode *proto_node;
|
||||
AstNode *fn_def_node;
|
||||
bool is_extern;
|
||||
bool internal_linkage;
|
||||
unsigned calling_convention;
|
||||
ImportTableEntry *import_entry;
|
||||
ZigList<FnAttrId> fn_attr_list;
|
||||
// Required to be a pre-order traversal of the AST. (parents must come before children)
|
||||
ZigList<BlockContext *> all_block_contexts;
|
||||
TypeTableEntry *member_of_struct;
|
||||
Buf symbol_name;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
};
|
||||
|
||||
enum BuiltinFnId {
|
||||
BuiltinFnIdInvalid,
|
||||
BuiltinFnIdArithmeticWithOverflow,
|
||||
BuiltinFnIdMemcpy,
|
||||
BuiltinFnIdMemset,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
BuiltinFnId id;
|
||||
Buf name;
|
||||
int param_count;
|
||||
TypeTableEntry *return_type;
|
||||
TypeTableEntry **param_types;
|
||||
LLVMValueRef fn_val;
|
||||
};
|
||||
|
||||
struct CodeGen {
|
||||
LLVMModuleRef module;
|
||||
ZigList<ErrorMsg*> errors;
|
||||
LLVMBuilderRef builder;
|
||||
LLVMZigDIBuilder *dbuilder;
|
||||
LLVMZigDICompileUnit *compile_unit;
|
||||
|
||||
ZigList<Buf *> lib_search_paths;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
|
||||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
|
||||
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
|
||||
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
|
||||
|
||||
uint32_t next_unresolved_index;
|
||||
|
||||
struct {
|
||||
TypeTableEntry *entry_bool;
|
||||
TypeTableEntry *entry_u8;
|
||||
TypeTableEntry *entry_u16;
|
||||
TypeTableEntry *entry_u32;
|
||||
TypeTableEntry *entry_u64;
|
||||
TypeTableEntry *entry_i8;
|
||||
TypeTableEntry *entry_i16;
|
||||
TypeTableEntry *entry_i32;
|
||||
TypeTableEntry *entry_i64;
|
||||
TypeTableEntry *entry_isize;
|
||||
TypeTableEntry *entry_usize;
|
||||
TypeTableEntry *entry_f32;
|
||||
TypeTableEntry *entry_f64;
|
||||
TypeTableEntry *entry_c_string_literal;
|
||||
TypeTableEntry *entry_void;
|
||||
TypeTableEntry *entry_unreachable;
|
||||
TypeTableEntry *entry_invalid;
|
||||
} builtin_types;
|
||||
|
||||
TypeTableEntry *num_lit_types[NumLitCount];
|
||||
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
unsigned pointer_size_bytes;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool have_exported_main;
|
||||
bool link_libc;
|
||||
Buf *libc_path;
|
||||
CodeGenBuildType build_type;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
LLVMZigDIFile *dummy_di_file;
|
||||
bool is_native_target;
|
||||
Buf *root_source_dir;
|
||||
Buf *root_out_name;
|
||||
|
||||
// The function definitions this module includes. There must be a corresponding
|
||||
// fn_protos entry.
|
||||
ZigList<FnTableEntry *> fn_defs;
|
||||
// The function prototypes this module includes. In the case of external declarations,
|
||||
// there will not be a corresponding fn_defs entry.
|
||||
ZigList<FnTableEntry *> fn_protos;
|
||||
ZigList<VariableTableEntry *> global_vars;
|
||||
|
||||
OutType out_type;
|
||||
FnTableEntry *cur_fn;
|
||||
BlockContext *cur_block_context;
|
||||
ZigList<LLVMBasicBlockRef> break_block_stack;
|
||||
ZigList<LLVMBasicBlockRef> continue_block_stack;
|
||||
bool c_stdint_used;
|
||||
AstNode *root_export_decl;
|
||||
int version_major;
|
||||
int version_minor;
|
||||
int version_patch;
|
||||
bool verbose;
|
||||
ErrColor err_color;
|
||||
ImportTableEntry *root_import;
|
||||
ImportTableEntry *bootstrap_import;
|
||||
LLVMValueRef memcpy_fn_val;
|
||||
bool error_during_imports;
|
||||
};
|
||||
|
||||
struct VariableTableEntry {
|
||||
Buf name;
|
||||
TypeTableEntry *type;
|
||||
LLVMValueRef value_ref;
|
||||
bool is_const;
|
||||
bool is_ptr; // if true, value_ref is a pointer
|
||||
AstNode *decl_node;
|
||||
LLVMZigDILocalVariable *di_loc_var;
|
||||
int arg_index;
|
||||
};
|
||||
|
||||
struct BlockContext {
|
||||
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
|
||||
FnTableEntry *fn_entry; // null at the module scope
|
||||
BlockContext *parent; // null when this is the root
|
||||
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
|
||||
ZigList<Cast *> cast_expr_alloca_list;
|
||||
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
|
||||
AstNode *parent_loop_node;
|
||||
AstNode *next_child_parent_loop_node;
|
||||
LLVMZigDIScope *di_scope;
|
||||
};
|
||||
|
||||
#endif
|
530
src/analyze.cpp
530
src/analyze.cpp
File diff suppressed because it is too large
Load Diff
406
src/analyze.hpp
406
src/analyze.hpp
|
@ -8,414 +8,16 @@
|
|||
#ifndef ZIG_ANALYZE_HPP
|
||||
#define ZIG_ANALYZE_HPP
|
||||
|
||||
#include "codegen.hpp"
|
||||
#include "hash_map.hpp"
|
||||
#include "zig_llvm.hpp"
|
||||
#include "errmsg.hpp"
|
||||
|
||||
struct FnTableEntry;
|
||||
struct BlockContext;
|
||||
struct TypeTableEntry;
|
||||
struct VariableTableEntry;
|
||||
struct CastNode;
|
||||
struct StructValExprNode;
|
||||
|
||||
struct TypeTableEntryPointer {
|
||||
TypeTableEntry *child_type;
|
||||
bool is_const;
|
||||
bool is_noalias;
|
||||
};
|
||||
|
||||
struct TypeTableEntryInt {
|
||||
bool is_signed;
|
||||
};
|
||||
|
||||
struct TypeTableEntryArray {
|
||||
TypeTableEntry *child_type;
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
struct TypeStructField {
|
||||
Buf *name;
|
||||
TypeTableEntry *type_entry;
|
||||
};
|
||||
|
||||
struct TypeTableEntryStruct {
|
||||
AstNode *decl_node;
|
||||
bool is_packed;
|
||||
int field_count;
|
||||
TypeStructField *fields;
|
||||
uint64_t size_bytes;
|
||||
bool is_invalid; // true if any fields are invalid
|
||||
bool is_unknown_size_array;
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
|
||||
|
||||
// set this flag temporarily to detect infinite loops
|
||||
bool embedded_in_current;
|
||||
bool reported_infinite_err;
|
||||
};
|
||||
|
||||
struct TypeTableEntryNumLit {
|
||||
NumLit kind;
|
||||
};
|
||||
|
||||
struct TypeTableEntryMaybe {
|
||||
TypeTableEntry *child_type;
|
||||
};
|
||||
|
||||
enum TypeTableEntryId {
|
||||
TypeTableEntryIdInvalid,
|
||||
TypeTableEntryIdVoid,
|
||||
TypeTableEntryIdBool,
|
||||
TypeTableEntryIdUnreachable,
|
||||
TypeTableEntryIdInt,
|
||||
TypeTableEntryIdFloat,
|
||||
TypeTableEntryIdPointer,
|
||||
TypeTableEntryIdArray,
|
||||
TypeTableEntryIdStruct,
|
||||
TypeTableEntryIdNumberLiteral,
|
||||
TypeTableEntryIdMaybe,
|
||||
};
|
||||
|
||||
struct TypeTableEntry {
|
||||
TypeTableEntryId id;
|
||||
|
||||
LLVMTypeRef type_ref;
|
||||
LLVMZigDIType *di_type;
|
||||
uint64_t size_in_bits;
|
||||
uint64_t align_in_bits;
|
||||
|
||||
Buf name;
|
||||
|
||||
union {
|
||||
TypeTableEntryPointer pointer;
|
||||
TypeTableEntryInt integral;
|
||||
TypeTableEntryArray array;
|
||||
TypeTableEntryStruct structure;
|
||||
TypeTableEntryNumLit num_lit;
|
||||
TypeTableEntryMaybe maybe;
|
||||
} data;
|
||||
|
||||
// use these fields to make sure we don't duplicate type table entries for the same type
|
||||
TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
|
||||
TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
|
||||
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
|
||||
TypeTableEntry *maybe_parent;
|
||||
|
||||
};
|
||||
|
||||
struct ImporterInfo {
|
||||
ImportTableEntry *import;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
struct ImportTableEntry {
|
||||
AstNode *root;
|
||||
Buf *path; // relative to root_source_dir
|
||||
LLVMZigDIFile *di_file;
|
||||
Buf *source_code;
|
||||
ZigList<int> *line_offsets;
|
||||
BlockContext *block_context;
|
||||
ZigList<ImporterInfo> importers;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
|
||||
};
|
||||
|
||||
struct LabelTableEntry {
|
||||
AstNode *label_node;
|
||||
LLVMBasicBlockRef basic_block;
|
||||
bool used;
|
||||
bool entered_from_fallthrough;
|
||||
};
|
||||
|
||||
enum FnAttrId {
|
||||
FnAttrIdNaked,
|
||||
FnAttrIdAlwaysInline,
|
||||
};
|
||||
|
||||
struct FnTableEntry {
|
||||
LLVMValueRef fn_value;
|
||||
AstNode *proto_node;
|
||||
AstNode *fn_def_node;
|
||||
bool is_extern;
|
||||
bool internal_linkage;
|
||||
unsigned calling_convention;
|
||||
ImportTableEntry *import_entry;
|
||||
ZigList<FnAttrId> fn_attr_list;
|
||||
// Required to be a pre-order traversal of the AST. (parents must come before children)
|
||||
ZigList<BlockContext *> all_block_contexts;
|
||||
TypeTableEntry *member_of_struct;
|
||||
Buf symbol_name;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
};
|
||||
|
||||
enum BuiltinFnId {
|
||||
BuiltinFnIdInvalid,
|
||||
BuiltinFnIdArithmeticWithOverflow,
|
||||
BuiltinFnIdMemcpy,
|
||||
BuiltinFnIdMemset,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
BuiltinFnId id;
|
||||
Buf name;
|
||||
int param_count;
|
||||
TypeTableEntry *return_type;
|
||||
TypeTableEntry **param_types;
|
||||
LLVMValueRef fn_val;
|
||||
};
|
||||
|
||||
struct CodeGen {
|
||||
LLVMModuleRef module;
|
||||
ZigList<ErrorMsg*> errors;
|
||||
LLVMBuilderRef builder;
|
||||
LLVMZigDIBuilder *dbuilder;
|
||||
LLVMZigDICompileUnit *compile_unit;
|
||||
|
||||
ZigList<Buf *> lib_search_paths;
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
|
||||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
|
||||
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
|
||||
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
|
||||
|
||||
uint32_t next_unresolved_index;
|
||||
|
||||
struct {
|
||||
TypeTableEntry *entry_bool;
|
||||
TypeTableEntry *entry_u8;
|
||||
TypeTableEntry *entry_u16;
|
||||
TypeTableEntry *entry_u32;
|
||||
TypeTableEntry *entry_u64;
|
||||
TypeTableEntry *entry_i8;
|
||||
TypeTableEntry *entry_i16;
|
||||
TypeTableEntry *entry_i32;
|
||||
TypeTableEntry *entry_i64;
|
||||
TypeTableEntry *entry_isize;
|
||||
TypeTableEntry *entry_usize;
|
||||
TypeTableEntry *entry_f32;
|
||||
TypeTableEntry *entry_f64;
|
||||
TypeTableEntry *entry_c_string_literal;
|
||||
TypeTableEntry *entry_void;
|
||||
TypeTableEntry *entry_unreachable;
|
||||
TypeTableEntry *entry_invalid;
|
||||
} builtin_types;
|
||||
|
||||
TypeTableEntry *num_lit_types[NumLitCount];
|
||||
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
unsigned pointer_size_bytes;
|
||||
bool is_static;
|
||||
bool strip_debug_symbols;
|
||||
bool have_exported_main;
|
||||
bool link_libc;
|
||||
Buf *libc_path;
|
||||
CodeGenBuildType build_type;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
LLVMZigDIFile *dummy_di_file;
|
||||
bool is_native_target;
|
||||
Buf *root_source_dir;
|
||||
Buf *root_out_name;
|
||||
|
||||
// The function definitions this module includes. There must be a corresponding
|
||||
// fn_protos entry.
|
||||
ZigList<FnTableEntry *> fn_defs;
|
||||
// The function prototypes this module includes. In the case of external declarations,
|
||||
// there will not be a corresponding fn_defs entry.
|
||||
ZigList<FnTableEntry *> fn_protos;
|
||||
ZigList<VariableTableEntry *> global_vars;
|
||||
|
||||
OutType out_type;
|
||||
FnTableEntry *cur_fn;
|
||||
BlockContext *cur_block_context;
|
||||
ZigList<LLVMBasicBlockRef> break_block_stack;
|
||||
ZigList<LLVMBasicBlockRef> continue_block_stack;
|
||||
bool c_stdint_used;
|
||||
AstNode *root_export_decl;
|
||||
int version_major;
|
||||
int version_minor;
|
||||
int version_patch;
|
||||
bool verbose;
|
||||
ErrColor err_color;
|
||||
ImportTableEntry *root_import;
|
||||
ImportTableEntry *bootstrap_import;
|
||||
LLVMValueRef memcpy_fn_val;
|
||||
bool error_during_imports;
|
||||
};
|
||||
|
||||
struct VariableTableEntry {
|
||||
Buf name;
|
||||
TypeTableEntry *type;
|
||||
LLVMValueRef value_ref;
|
||||
bool is_const;
|
||||
bool is_ptr; // if true, value_ref is a pointer
|
||||
AstNode *decl_node;
|
||||
LLVMZigDILocalVariable *di_loc_var;
|
||||
int arg_index;
|
||||
};
|
||||
|
||||
struct BlockContext {
|
||||
AstNode *node; // either NodeTypeFnDef or NodeTypeBlock or NodeTypeRoot
|
||||
FnTableEntry *fn_entry; // null at the module scope
|
||||
BlockContext *parent; // null when this is the root
|
||||
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
|
||||
ZigList<CastNode *> cast_expr_alloca_list;
|
||||
ZigList<StructValExprNode *> struct_val_expr_alloca_list;
|
||||
AstNode *parent_loop_node;
|
||||
AstNode *next_child_parent_loop_node;
|
||||
LLVMZigDIScope *di_scope;
|
||||
};
|
||||
|
||||
struct TypeNode {
|
||||
TypeTableEntry *entry;
|
||||
};
|
||||
|
||||
struct FnProtoNode {
|
||||
FnTableEntry *fn_table_entry;
|
||||
bool skip;
|
||||
};
|
||||
|
||||
struct FnDefNode {
|
||||
TypeTableEntry *implicit_return_type;
|
||||
BlockContext *block_context;
|
||||
};
|
||||
|
||||
|
||||
struct AssignNode {
|
||||
VariableTableEntry *var_entry;
|
||||
};
|
||||
|
||||
struct BlockNode {
|
||||
BlockContext *block_context;
|
||||
};
|
||||
|
||||
struct StructDeclNode {
|
||||
TypeTableEntry *type_entry;
|
||||
};
|
||||
|
||||
struct FieldAccessNode {
|
||||
int field_index;
|
||||
TypeStructField *type_struct_field;
|
||||
};
|
||||
|
||||
enum CastOp {
|
||||
CastOpNothing,
|
||||
CastOpPtrToInt,
|
||||
CastOpIntWidenOrShorten,
|
||||
CastOpToUnknownSizeArray,
|
||||
CastOpMaybeWrap,
|
||||
CastOpPointerReinterpret,
|
||||
};
|
||||
|
||||
struct CastNode {
|
||||
CastOp op;
|
||||
// if op is CastOpArrayToString, this will be a pointer to
|
||||
// the string struct on the stack
|
||||
LLVMValueRef ptr;
|
||||
TypeTableEntry *after_type;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
struct ExprNode {
|
||||
TypeTableEntry *type_entry;
|
||||
// the context in which this expression is evaluated.
|
||||
// for blocks, this points to the containing scope, not the block's own scope for its children.
|
||||
BlockContext *block_context;
|
||||
|
||||
// may be null for no cast
|
||||
CastNode implicit_cast; // happens first
|
||||
CastNode implicit_maybe_cast; // happens second
|
||||
};
|
||||
|
||||
struct NumberLiteralNode {
|
||||
TypeTableEntry *resolved_type;
|
||||
};
|
||||
|
||||
struct VarDeclNode {
|
||||
TypeTableEntry *type;
|
||||
};
|
||||
|
||||
struct StructValFieldNode {
|
||||
int index;
|
||||
};
|
||||
|
||||
struct StructValExprNode {
|
||||
TypeTableEntry *type_entry;
|
||||
LLVMValueRef ptr;
|
||||
AstNode *source_node;
|
||||
};
|
||||
|
||||
struct IfVarNode {
|
||||
BlockContext *block_context;
|
||||
};
|
||||
|
||||
struct ParamDeclNode {
|
||||
VariableTableEntry *variable;
|
||||
};
|
||||
|
||||
struct ImportNode {
|
||||
ImportTableEntry *import;
|
||||
};
|
||||
|
||||
struct WhileNode {
|
||||
bool condition_always_true;
|
||||
bool contains_break;
|
||||
};
|
||||
|
||||
struct FnCallNode {
|
||||
BuiltinFnEntry *builtin_fn;
|
||||
};
|
||||
|
||||
struct DeclNode {
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps;
|
||||
Buf *name;
|
||||
ImportTableEntry *import;
|
||||
// set this flag temporarily to detect infinite loops
|
||||
bool in_current_deps;
|
||||
};
|
||||
|
||||
// TODO get rid of this structure and put the data directly in the appropriate AST node
|
||||
struct CodeGenNode {
|
||||
union {
|
||||
TypeNode type_node; // for NodeTypeType
|
||||
FnDefNode fn_def_node; // for NodeTypeFnDef
|
||||
FnProtoNode fn_proto_node; // for NodeTypeFnProto
|
||||
LabelTableEntry *label_entry; // for NodeTypeGoto and NodeTypeLabel
|
||||
AssignNode assign_node; // for NodeTypeBinOpExpr where op is BinOpTypeAssign
|
||||
BlockNode block_node; // for NodeTypeBlock
|
||||
StructDeclNode struct_decl_node; // for NodeTypeStructDecl
|
||||
FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
|
||||
CastNode cast_node; // for NodeTypeCastExpr
|
||||
// note: I've been using this field on some non-number literal nodes too.
|
||||
NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
|
||||
VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
|
||||
StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
|
||||
// note: I've been using this field on some non-struct val expressions too.
|
||||
StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
|
||||
IfVarNode if_var_node; // for NodeTypeStructValueExpr
|
||||
ParamDeclNode param_decl_node; // for NodeTypeParamDecl
|
||||
ImportNode import_node; // for NodeTypeUse
|
||||
WhileNode while_node; // for NodeTypeWhileExpr
|
||||
FnCallNode fn_call_node; // for NodeTypeFnCallExpr
|
||||
} data;
|
||||
ExprNode expr_node; // for all the expression nodes
|
||||
DeclNode decl_node; // for all top level decls
|
||||
};
|
||||
#include "all_types.hpp"
|
||||
|
||||
void semantic_analyze(CodeGen *g);
|
||||
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
void alloc_codegen_node(AstNode *node);
|
||||
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
|
||||
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias);
|
||||
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
|
||||
Expr *get_resolved_expr(AstNode *node);
|
||||
NumLitCodeGen *get_resolved_num_lit(AstNode *node);
|
||||
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
|
||||
|
||||
#endif
|
||||
|
|
111
src/codegen.cpp
111
src/codegen.cpp
|
@ -75,9 +75,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
|
|||
|
||||
static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
|
||||
assert(type_node->type == NodeTypeType);
|
||||
assert(type_node->codegen_node);
|
||||
assert(type_node->codegen_node->data.type_node.entry);
|
||||
return type_node->codegen_node->data.type_node.entry;
|
||||
return type_node->data.type.entry;
|
||||
}
|
||||
|
||||
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
|
||||
|
@ -138,15 +136,16 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
|
|||
}
|
||||
|
||||
static TypeTableEntry *get_expr_type(AstNode *node) {
|
||||
TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.after_type;
|
||||
return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
TypeTableEntry *cast_type = expr->implicit_cast.after_type;
|
||||
return cast_type ? cast_type : expr->type_entry;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
|
||||
assert(fn_ref_expr->type == NodeTypeSymbol);
|
||||
BuiltinFnEntry *builtin_fn = node->codegen_node->data.fn_call_node.builtin_fn;
|
||||
BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn;
|
||||
|
||||
switch (builtin_fn->id) {
|
||||
case BuiltinFnIdInvalid:
|
||||
|
@ -265,7 +264,7 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
|
|||
// Assume that the expression evaluates to a simple name and return the buf
|
||||
// TODO after we support function pointers we can make this generic
|
||||
assert(fn_ref_expr->type == NodeTypeSymbol);
|
||||
Buf *name = &fn_ref_expr->data.symbol;
|
||||
Buf *name = &fn_ref_expr->data.symbol_expr.symbol;
|
||||
|
||||
struct_type = nullptr;
|
||||
first_param_expr = nullptr;
|
||||
|
@ -388,8 +387,8 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
|
|||
|
||||
LLVMValueRef struct_ptr;
|
||||
if (struct_expr_node->type == NodeTypeSymbol) {
|
||||
VariableTableEntry *var = find_variable(struct_expr_node->codegen_node->expr_node.block_context,
|
||||
&struct_expr_node->data.symbol);
|
||||
VariableTableEntry *var = find_variable(get_resolved_expr(struct_expr_node)->block_context,
|
||||
&struct_expr_node->data.symbol_expr.symbol);
|
||||
assert(var);
|
||||
|
||||
if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) {
|
||||
|
@ -413,14 +412,12 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
|
|||
assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
|
||||
assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
|
||||
|
||||
FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
|
||||
assert(node->data.field_access_expr.field_index >= 0);
|
||||
|
||||
assert(codegen_field_access->field_index >= 0);
|
||||
|
||||
*out_type_entry = codegen_field_access->type_struct_field->type_entry;
|
||||
*out_type_entry = node->data.field_access_expr.type_struct_field->type_entry;
|
||||
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildStructGEP(g->builder, struct_ptr, codegen_field_access->field_index, "");
|
||||
return LLVMBuildStructGEP(g->builder, struct_ptr, node->data.field_access_expr.field_index, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
|
||||
|
@ -429,7 +426,7 @@ static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
|
|||
AstNode *array_ref_node = node->data.slice_expr.array_ref_expr;
|
||||
TypeTableEntry *array_type = get_expr_type(array_ref_node);
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr;
|
||||
LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr;
|
||||
LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node);
|
||||
|
||||
if (array_type->id == TypeTableEntryIdArray) {
|
||||
|
@ -545,8 +542,8 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
|
|||
LLVMValueRef target_ref;
|
||||
|
||||
if (node->type == NodeTypeSymbol) {
|
||||
VariableTableEntry *var = find_variable(expr_node->codegen_node->expr_node.block_context,
|
||||
&node->data.symbol);
|
||||
VariableTableEntry *var = find_variable(get_resolved_expr(expr_node)->block_context,
|
||||
&node->data.symbol_expr.symbol);
|
||||
assert(var);
|
||||
// semantic checking ensures no variables are constant
|
||||
assert(!var->is_const);
|
||||
|
@ -630,7 +627,7 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
|
|||
}
|
||||
|
||||
static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val,
|
||||
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, CastNode *cast_node)
|
||||
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node)
|
||||
{
|
||||
switch (cast_node->op) {
|
||||
case CastOpNothing:
|
||||
|
@ -705,7 +702,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
|
|||
TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
|
||||
TypeTableEntry *wanted_type = get_expr_type(node);
|
||||
|
||||
CastNode *cast_node = &node->codegen_node->data.cast_node;
|
||||
Cast *cast_node = &node->data.cast_expr.cast;
|
||||
|
||||
return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node);
|
||||
|
||||
|
@ -1218,7 +1215,7 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
|
|||
assert(node->data.if_var_expr.var_decl.expr);
|
||||
|
||||
BlockContext *old_block_context = g->cur_block_context;
|
||||
BlockContext *new_block_context = node->codegen_node->data.if_var_node.block_context;
|
||||
BlockContext *new_block_context = node->data.if_var_expr.block_context;
|
||||
|
||||
LLVMValueRef init_val;
|
||||
gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, new_block_context, true, &init_val);
|
||||
|
@ -1242,7 +1239,7 @@ static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *i
|
|||
assert(block_node->type == NodeTypeBlock);
|
||||
|
||||
BlockContext *old_block_context = g->cur_block_context;
|
||||
g->cur_block_context = block_node->codegen_node->data.block_node.block_context;
|
||||
g->cur_block_context = block_node->data.block.block_context;
|
||||
|
||||
LLVMValueRef return_value;
|
||||
for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
|
||||
|
@ -1347,7 +1344,7 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
|
|||
|
||||
if (!is_return) {
|
||||
VariableTableEntry *variable = find_variable(
|
||||
node->codegen_node->expr_node.block_context,
|
||||
get_resolved_expr(node)->block_context,
|
||||
&asm_output->variable_name);
|
||||
assert(variable);
|
||||
param_types[param_index] = LLVMTypeOf(variable->value_ref);
|
||||
|
@ -1396,7 +1393,7 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
|
|||
TypeTableEntry *type_entry = get_expr_type(node);
|
||||
assert(type_entry->id == TypeTableEntryIdMaybe);
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = node->codegen_node->data.struct_val_expr_node.ptr;
|
||||
LLVMValueRef tmp_struct_ptr = node->data.null_literal.resolved_struct_val_expr.ptr;
|
||||
|
||||
add_debug_source_node(g, node);
|
||||
LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
|
||||
|
@ -1416,12 +1413,13 @@ static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
|
|||
int field_count = type_entry->data.structure.field_count;
|
||||
assert(field_count == node->data.struct_val_expr.fields.length);
|
||||
|
||||
StructValExprNode *struct_val_expr_node = &node->codegen_node->data.struct_val_expr_node;
|
||||
StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen;
|
||||
LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
|
||||
|
||||
for (int i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_node = node->data.struct_val_expr.fields.at(i);
|
||||
int index = field_node->codegen_node->data.struct_val_field_node.index;
|
||||
assert(field_node->type == NodeTypeStructValueField);
|
||||
int index = field_node->data.struct_val_field.index;
|
||||
TypeStructField *type_struct_field = &type_entry->data.structure.fields[index];
|
||||
assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
|
||||
|
||||
|
@ -1439,8 +1437,8 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
|
|||
assert(node->data.while_expr.condition);
|
||||
assert(node->data.while_expr.body);
|
||||
|
||||
bool condition_always_true = node->codegen_node->data.while_node.condition_always_true;
|
||||
bool contains_break = node->codegen_node->data.while_node.contains_break;
|
||||
bool condition_always_true = node->data.while_expr.condition_always_true;
|
||||
bool contains_break = node->data.while_expr.contains_break;
|
||||
if (condition_always_true) {
|
||||
// generate a forever loop
|
||||
|
||||
|
@ -1559,17 +1557,17 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
|
|||
static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
|
||||
LLVMValueRef init_val;
|
||||
return gen_var_decl_raw(g, node, &node->data.variable_declaration,
|
||||
node->codegen_node->expr_node.block_context, false, &init_val);
|
||||
get_resolved_expr(node)->block_context, false, &init_val);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
|
||||
NumberLiteralNode *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
|
||||
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
|
||||
{
|
||||
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
|
||||
assert(type_entry);
|
||||
|
||||
// override the expression type for number literals
|
||||
source_node->codegen_node->expr_node.type_entry = type_entry;
|
||||
get_resolved_expr(source_node)->type_entry = type_entry;
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
// here the union has int64_t and uint64_t and we purposefully read
|
||||
|
@ -1594,7 +1592,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
|
|||
Buf *name = &node->data.compiler_fn_type.name;
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
|
||||
if (buf_eql_str(name, "sizeof")) {
|
||||
NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = type_entry->data.num_lit.kind;
|
||||
num_lit_node.overflow = false;
|
||||
|
@ -1632,7 +1630,7 @@ static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
|
|||
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeNumberLiteral);
|
||||
|
||||
NumberLiteralNode *codegen_num_lit = &node->codegen_node->data.num_lit_node;
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
assert(codegen_num_lit);
|
||||
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
|
||||
|
@ -1664,7 +1662,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
|||
case NodeTypeVoid:
|
||||
return nullptr;
|
||||
case NodeTypeBoolLiteral:
|
||||
if (node->data.bool_literal)
|
||||
if (node->data.bool_literal.value)
|
||||
return LLVMConstAllOnes(LLVMInt1Type());
|
||||
else
|
||||
return LLVMConstNull(LLVMInt1Type());
|
||||
|
@ -1696,8 +1694,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
|||
case NodeTypeSymbol:
|
||||
{
|
||||
VariableTableEntry *variable = find_variable(
|
||||
node->codegen_node->expr_node.block_context,
|
||||
&node->data.symbol);
|
||||
get_resolved_expr(node)->block_context,
|
||||
&node->data.symbol_expr.symbol);
|
||||
assert(variable);
|
||||
if (variable->type->id == TypeTableEntryIdVoid) {
|
||||
return nullptr;
|
||||
|
@ -1721,14 +1719,14 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
|
|||
return gen_block(g, node, nullptr);
|
||||
case NodeTypeGoto:
|
||||
add_debug_source_node(g, node);
|
||||
return LLVMBuildBr(g->builder, node->codegen_node->data.label_entry->basic_block);
|
||||
return LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block);
|
||||
case NodeTypeBreak:
|
||||
return gen_break(g, node);
|
||||
case NodeTypeContinue:
|
||||
return gen_continue(g, node);
|
||||
case NodeTypeLabel:
|
||||
{
|
||||
LabelTableEntry *label_entry = node->codegen_node->data.label_entry;
|
||||
LabelTableEntry *label_entry = node->data.label.label_entry;
|
||||
assert(label_entry);
|
||||
LLVMBasicBlockRef basic_block = label_entry->basic_block;
|
||||
if (label_entry->entered_from_fallthrough) {
|
||||
|
@ -1770,19 +1768,19 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
|
|||
return val;
|
||||
}
|
||||
|
||||
assert(node->codegen_node);
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
|
||||
TypeTableEntry *before_type = node->codegen_node->expr_node.type_entry;
|
||||
TypeTableEntry *before_type = expr->type_entry;
|
||||
if (before_type && before_type->id == TypeTableEntryIdUnreachable) {
|
||||
return val;
|
||||
}
|
||||
CastNode *cast_node = &node->codegen_node->expr_node.implicit_cast;
|
||||
Cast *cast_node = &expr->implicit_cast;
|
||||
if (cast_node->after_type) {
|
||||
val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node);
|
||||
before_type = cast_node->after_type;
|
||||
}
|
||||
|
||||
cast_node = &node->codegen_node->expr_node.implicit_maybe_cast;
|
||||
cast_node = &expr->implicit_maybe_cast;
|
||||
if (cast_node->after_type) {
|
||||
val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node);
|
||||
}
|
||||
|
@ -1798,7 +1796,7 @@ static void build_label_blocks(CodeGen *g, AstNode *block_node) {
|
|||
continue;
|
||||
|
||||
Buf *name = &label_node->data.label.name;
|
||||
label_node->codegen_node->data.label_entry->basic_block = LLVMAppendBasicBlock(
|
||||
label_node->data.label.label_entry->basic_block = LLVMAppendBasicBlock(
|
||||
g->cur_fn->fn_value, buf_ptr(name));
|
||||
}
|
||||
|
||||
|
@ -1944,13 +1942,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn, "entry");
|
||||
LLVMPositionBuilderAtEnd(g->builder, entry_block);
|
||||
|
||||
CodeGenNode *codegen_node = fn_def_node->codegen_node;
|
||||
assert(codegen_node);
|
||||
|
||||
FnDefNode *codegen_fn_def = &codegen_node->data.fn_def_node;
|
||||
assert(codegen_fn_def);
|
||||
|
||||
codegen_fn_def->block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
|
||||
fn_def_node->data.fn_def.block_context->di_scope = LLVMZigSubprogramToScope(subprogram);
|
||||
|
||||
int non_void_param_count = count_non_void_params(g, &fn_proto->params);
|
||||
assert(non_void_param_count == (int)LLVMCountParams(fn));
|
||||
|
@ -1963,7 +1955,7 @@ static void do_code_gen(CodeGen *g) {
|
|||
assert(param_decl->type == NodeTypeParamDecl);
|
||||
if (is_param_decl_type_void(g, param_decl))
|
||||
continue;
|
||||
VariableTableEntry *parameter_variable = fn_def_node->codegen_node->data.fn_def_node.block_context->variable_table.get(¶m_decl->data.param_decl.name);
|
||||
VariableTableEntry *parameter_variable = fn_def_node->data.fn_def.block_context->variable_table.get(¶m_decl->data.param_decl.name);
|
||||
parameter_variable->value_ref = params[non_void_index];
|
||||
non_void_index += 1;
|
||||
}
|
||||
|
@ -2019,14 +2011,14 @@ static void do_code_gen(CodeGen *g) {
|
|||
|
||||
// allocate structs which are the result of casts
|
||||
for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {
|
||||
CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i);
|
||||
Cast *cast_node = block_context->cast_expr_alloca_list.at(cea_i);
|
||||
add_debug_source_node(g, cast_node->source_node);
|
||||
cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, "");
|
||||
}
|
||||
|
||||
// allocate structs which are struct value expressions
|
||||
for (int alloca_i = 0; alloca_i < block_context->struct_val_expr_alloca_list.length; alloca_i += 1) {
|
||||
StructValExprNode *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i);
|
||||
StructValExprCodeGen *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i);
|
||||
add_debug_source_node(g, struct_val_expr_node->source_node);
|
||||
struct_val_expr_node->ptr = LLVMBuildAlloca(g->builder,
|
||||
struct_val_expr_node->type_entry->type_ref, "");
|
||||
|
@ -2041,15 +2033,15 @@ static void do_code_gen(CodeGen *g) {
|
|||
if (is_param_decl_type_void(g, param_decl))
|
||||
continue;
|
||||
|
||||
VariableTableEntry *variable = param_decl->codegen_node->data.param_decl_node.variable;
|
||||
VariableTableEntry *variable = param_decl->data.param_decl.variable;
|
||||
|
||||
LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(param_decl->line + 1, param_decl->column + 1,
|
||||
codegen_fn_def->block_context->di_scope);
|
||||
fn_def_node->data.fn_def.block_context->di_scope);
|
||||
LLVMZigInsertDeclareAtEnd(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc,
|
||||
entry_block);
|
||||
}
|
||||
|
||||
TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
|
||||
TypeTableEntry *implicit_return_type = fn_def_node->data.fn_def.implicit_return_type;
|
||||
gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type);
|
||||
|
||||
}
|
||||
|
@ -2549,8 +2541,6 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
|||
Buf *import_code = buf_alloc();
|
||||
bool found_it = false;
|
||||
|
||||
alloc_codegen_node(top_level_decl);
|
||||
|
||||
for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) {
|
||||
Buf *search_path = g->lib_search_paths.at(path_i);
|
||||
os_path_join(search_path, import_target_path, &full_path);
|
||||
|
@ -2570,7 +2560,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
|||
auto entry = g->import_table.maybe_get(abs_full_path);
|
||||
if (entry) {
|
||||
found_it = true;
|
||||
top_level_decl->codegen_node->data.import_node.import = entry->value;
|
||||
top_level_decl->data.use.import = entry->value;
|
||||
} else {
|
||||
if ((err = os_fetch_file_path(abs_full_path, import_code))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
|
@ -2582,7 +2572,7 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
|||
goto done_looking_at_imports;
|
||||
}
|
||||
}
|
||||
top_level_decl->codegen_node->data.import_node.import = codegen_add_code(g,
|
||||
top_level_decl->data.use.import = codegen_add_code(g,
|
||||
abs_full_path, search_path, &top_level_decl->data.use.path, import_code);
|
||||
found_it = true;
|
||||
}
|
||||
|
@ -2682,9 +2672,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
|
|||
|
||||
static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
|
||||
assert(type_node->type == NodeTypeType);
|
||||
assert(type_node->codegen_node);
|
||||
|
||||
TypeTableEntry *type_entry = type_node->codegen_node->data.type_node.entry;
|
||||
TypeTableEntry *type_entry = type_node->data.type.entry;
|
||||
assert(type_entry);
|
||||
|
||||
if (type_entry == g->builtin_types.entry_u8) {
|
||||
|
|
|
@ -11,21 +11,8 @@
|
|||
#include "parser.hpp"
|
||||
#include "errmsg.hpp"
|
||||
|
||||
struct CodeGen;
|
||||
|
||||
enum OutType {
|
||||
OutTypeUnknown,
|
||||
OutTypeExe,
|
||||
OutTypeLib,
|
||||
OutTypeObj,
|
||||
};
|
||||
|
||||
CodeGen *codegen_create(Buf *root_source_dir);
|
||||
|
||||
enum CodeGenBuildType {
|
||||
CodeGenBuildTypeDebug,
|
||||
CodeGenBuildTypeRelease,
|
||||
};
|
||||
void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
|
||||
void codegen_set_is_static(CodeGen *codegen, bool is_static);
|
||||
void codegen_set_strip(CodeGen *codegen, bool strip);
|
||||
|
|
|
@ -356,8 +356,7 @@ void ast_print(AstNode *node, int indent) {
|
|||
fprintf(stderr, "Unreachable\n");
|
||||
break;
|
||||
case NodeTypeSymbol:
|
||||
fprintf(stderr, "Symbol %s\n",
|
||||
buf_ptr(&node->data.symbol));
|
||||
fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol));
|
||||
break;
|
||||
case NodeTypeUse:
|
||||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));
|
||||
|
@ -366,7 +365,8 @@ void ast_print(AstNode *node, int indent) {
|
|||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
break;
|
||||
case NodeTypeBoolLiteral:
|
||||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), node->data.bool_literal ? "true" : "false");
|
||||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type),
|
||||
node->data.bool_literal.value ? "true" : "false");
|
||||
break;
|
||||
case NodeTypeNullLiteral:
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
|
@ -401,7 +401,7 @@ void ast_print(AstNode *node, int indent) {
|
|||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name));
|
||||
break;
|
||||
case NodeTypeGoto:
|
||||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.go_to.name));
|
||||
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.goto_expr.name));
|
||||
break;
|
||||
case NodeTypeBreak:
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
|
@ -1369,12 +1369,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
|||
return node;
|
||||
} else if (token->id == TokenIdKeywordTrue) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token);
|
||||
node->data.bool_literal = true;
|
||||
node->data.bool_literal.value = true;
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordFalse) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token);
|
||||
node->data.bool_literal = false;
|
||||
node->data.bool_literal.value = false;
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordNull) {
|
||||
|
@ -1385,7 +1385,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
|||
*token_index += 1;
|
||||
Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
|
||||
AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok);
|
||||
ast_buf_from_token(pc, name_tok, &name_node->data.symbol);
|
||||
ast_buf_from_token(pc, name_tok, &name_node->data.symbol_expr.symbol);
|
||||
|
||||
AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
|
||||
node->data.fn_call_expr.fn_ref_expr = name_node;
|
||||
|
@ -1401,7 +1401,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
|||
} else {
|
||||
*token_index += 1;
|
||||
AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
|
||||
ast_buf_from_token(pc, token, &node->data.symbol);
|
||||
ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
|
||||
return node;
|
||||
}
|
||||
} else if (token->id == TokenIdKeywordGoto) {
|
||||
|
@ -1412,7 +1412,7 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
|
|||
*token_index += 1;
|
||||
ast_expect_token(pc, dest_symbol, TokenIdSymbol);
|
||||
|
||||
ast_buf_from_token(pc, dest_symbol, &node->data.go_to.name);
|
||||
ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
|
||||
return node;
|
||||
} else if (token->id == TokenIdKeywordBreak) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
|
||||
|
|
442
src/parser.hpp
442
src/parser.hpp
|
@ -8,450 +8,10 @@
|
|||
#ifndef ZIG_PARSER_HPP
|
||||
#define ZIG_PARSER_HPP
|
||||
|
||||
#include "list.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "all_types.hpp"
|
||||
#include "tokenizer.hpp"
|
||||
#include "errmsg.hpp"
|
||||
|
||||
struct AstNode;
|
||||
struct CodeGenNode;
|
||||
struct ImportTableEntry;
|
||||
struct AsmToken;
|
||||
|
||||
enum NodeType {
|
||||
NodeTypeRoot,
|
||||
NodeTypeRootExportDecl,
|
||||
NodeTypeFnProto,
|
||||
NodeTypeFnDef,
|
||||
NodeTypeFnDecl,
|
||||
NodeTypeParamDecl,
|
||||
NodeTypeType,
|
||||
NodeTypeBlock,
|
||||
NodeTypeExternBlock,
|
||||
NodeTypeDirective,
|
||||
NodeTypeReturnExpr,
|
||||
NodeTypeVariableDeclaration,
|
||||
NodeTypeBinOpExpr,
|
||||
NodeTypeCastExpr,
|
||||
NodeTypeNumberLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
NodeTypeCharLiteral,
|
||||
NodeTypeUnreachable,
|
||||
NodeTypeSymbol,
|
||||
NodeTypePrefixOpExpr,
|
||||
NodeTypeFnCallExpr,
|
||||
NodeTypeArrayAccessExpr,
|
||||
NodeTypeSliceExpr,
|
||||
NodeTypeFieldAccessExpr,
|
||||
NodeTypeUse,
|
||||
NodeTypeVoid,
|
||||
NodeTypeBoolLiteral,
|
||||
NodeTypeNullLiteral,
|
||||
NodeTypeIfBoolExpr,
|
||||
NodeTypeIfVarExpr,
|
||||
NodeTypeWhileExpr,
|
||||
NodeTypeLabel,
|
||||
NodeTypeGoto,
|
||||
NodeTypeBreak,
|
||||
NodeTypeContinue,
|
||||
NodeTypeAsmExpr,
|
||||
NodeTypeStructDecl,
|
||||
NodeTypeStructField,
|
||||
NodeTypeStructValueExpr,
|
||||
NodeTypeStructValueField,
|
||||
NodeTypeEnumDecl,
|
||||
NodeTypeEnumField,
|
||||
NodeTypeCompilerFnExpr,
|
||||
NodeTypeCompilerFnType,
|
||||
};
|
||||
|
||||
struct AstNodeRoot {
|
||||
ZigList<AstNode *> top_level_decls;
|
||||
};
|
||||
|
||||
enum VisibMod {
|
||||
VisibModPrivate,
|
||||
VisibModPub,
|
||||
VisibModExport,
|
||||
};
|
||||
|
||||
struct AstNodeFnProto {
|
||||
ZigList<AstNode *> *directives;
|
||||
VisibMod visib_mod;
|
||||
Buf name;
|
||||
ZigList<AstNode *> params;
|
||||
AstNode *return_type;
|
||||
bool is_var_args;
|
||||
|
||||
// the extern block this fn proto is inside. can be null.
|
||||
// populated by semantic analyzer.
|
||||
AstNode *extern_node;
|
||||
// the struct decl node this fn proto is inside. can be null.
|
||||
// populated by semantic analyzer.
|
||||
AstNode *struct_node;
|
||||
// the function definition this fn proto is inside. can be null.
|
||||
// populated by semantic analyzer.
|
||||
AstNode *fn_def_node;
|
||||
};
|
||||
|
||||
struct AstNodeFnDef {
|
||||
AstNode *fn_proto;
|
||||
AstNode *body;
|
||||
};
|
||||
|
||||
struct AstNodeFnDecl {
|
||||
AstNode *fn_proto;
|
||||
};
|
||||
|
||||
struct AstNodeParamDecl {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
};
|
||||
|
||||
enum AstNodeTypeType {
|
||||
AstNodeTypeTypePrimitive,
|
||||
AstNodeTypeTypePointer,
|
||||
AstNodeTypeTypeArray,
|
||||
AstNodeTypeTypeMaybe,
|
||||
AstNodeTypeTypeCompilerExpr,
|
||||
};
|
||||
|
||||
struct AstNodeType {
|
||||
AstNodeTypeType type;
|
||||
Buf primitive_name;
|
||||
AstNode *child_type;
|
||||
AstNode *array_size; // can be null
|
||||
bool is_const;
|
||||
bool is_noalias;
|
||||
AstNode *compiler_expr;
|
||||
};
|
||||
|
||||
struct AstNodeBlock {
|
||||
ZigList<AstNode *> statements;
|
||||
};
|
||||
|
||||
struct AstNodeReturnExpr {
|
||||
// might be null in case of return void;
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct AstNodeVariableDeclaration {
|
||||
Buf symbol;
|
||||
bool is_const;
|
||||
VisibMod visib_mod;
|
||||
// one or both of type and expr will be non null
|
||||
AstNode *type;
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
enum BinOpType {
|
||||
BinOpTypeInvalid,
|
||||
BinOpTypeAssign,
|
||||
BinOpTypeAssignTimes,
|
||||
BinOpTypeAssignDiv,
|
||||
BinOpTypeAssignMod,
|
||||
BinOpTypeAssignPlus,
|
||||
BinOpTypeAssignMinus,
|
||||
BinOpTypeAssignBitShiftLeft,
|
||||
BinOpTypeAssignBitShiftRight,
|
||||
BinOpTypeAssignBitAnd,
|
||||
BinOpTypeAssignBitXor,
|
||||
BinOpTypeAssignBitOr,
|
||||
BinOpTypeAssignBoolAnd,
|
||||
BinOpTypeAssignBoolOr,
|
||||
BinOpTypeBoolOr,
|
||||
BinOpTypeBoolAnd,
|
||||
BinOpTypeCmpEq,
|
||||
BinOpTypeCmpNotEq,
|
||||
BinOpTypeCmpLessThan,
|
||||
BinOpTypeCmpGreaterThan,
|
||||
BinOpTypeCmpLessOrEq,
|
||||
BinOpTypeCmpGreaterOrEq,
|
||||
BinOpTypeBinOr,
|
||||
BinOpTypeBinXor,
|
||||
BinOpTypeBinAnd,
|
||||
BinOpTypeBitShiftLeft,
|
||||
BinOpTypeBitShiftRight,
|
||||
BinOpTypeAdd,
|
||||
BinOpTypeSub,
|
||||
BinOpTypeMult,
|
||||
BinOpTypeDiv,
|
||||
BinOpTypeMod,
|
||||
BinOpTypeUnwrapMaybe,
|
||||
};
|
||||
|
||||
struct AstNodeBinOpExpr {
|
||||
AstNode *op1;
|
||||
BinOpType bin_op;
|
||||
AstNode *op2;
|
||||
};
|
||||
|
||||
struct AstNodeFnCallExpr {
|
||||
AstNode *fn_ref_expr;
|
||||
ZigList<AstNode *> params;
|
||||
bool is_builtin;
|
||||
};
|
||||
|
||||
struct AstNodeArrayAccessExpr {
|
||||
AstNode *array_ref_expr;
|
||||
AstNode *subscript;
|
||||
};
|
||||
|
||||
struct AstNodeSliceExpr {
|
||||
AstNode *array_ref_expr;
|
||||
AstNode *start;
|
||||
AstNode *end;
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct AstNodeFieldAccessExpr {
|
||||
AstNode *struct_expr;
|
||||
Buf field_name;
|
||||
};
|
||||
|
||||
struct AstNodeExternBlock {
|
||||
ZigList<AstNode *> *directives;
|
||||
ZigList<AstNode *> fn_decls;
|
||||
};
|
||||
|
||||
struct AstNodeDirective {
|
||||
Buf name;
|
||||
Buf param;
|
||||
};
|
||||
|
||||
struct AstNodeRootExportDecl {
|
||||
Buf type;
|
||||
Buf name;
|
||||
ZigList<AstNode *> *directives;
|
||||
};
|
||||
|
||||
struct AstNodeCastExpr {
|
||||
AstNode *expr;
|
||||
AstNode *type;
|
||||
};
|
||||
|
||||
enum PrefixOp {
|
||||
PrefixOpInvalid,
|
||||
PrefixOpBoolNot,
|
||||
PrefixOpBinNot,
|
||||
PrefixOpNegation,
|
||||
PrefixOpAddressOf,
|
||||
PrefixOpConstAddressOf,
|
||||
PrefixOpDereference,
|
||||
};
|
||||
|
||||
struct AstNodePrefixOpExpr {
|
||||
PrefixOp prefix_op;
|
||||
AstNode *primary_expr;
|
||||
};
|
||||
|
||||
struct AstNodeUse {
|
||||
Buf path;
|
||||
ZigList<AstNode *> *directives;
|
||||
};
|
||||
|
||||
struct AstNodeIfBoolExpr {
|
||||
AstNode *condition;
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
};
|
||||
|
||||
struct AstNodeIfVarExpr {
|
||||
AstNodeVariableDeclaration var_decl;
|
||||
AstNode *then_block;
|
||||
AstNode *else_node; // null, block node, or other if expr node
|
||||
};
|
||||
|
||||
struct AstNodeWhileExpr {
|
||||
AstNode *condition;
|
||||
AstNode *body;
|
||||
};
|
||||
|
||||
struct AstNodeLabel {
|
||||
Buf name;
|
||||
};
|
||||
|
||||
struct AstNodeGoto {
|
||||
Buf name;
|
||||
};
|
||||
|
||||
struct AsmOutput {
|
||||
Buf asm_symbolic_name;
|
||||
Buf constraint;
|
||||
Buf variable_name;
|
||||
AstNode *return_type; // null unless "=r" and return
|
||||
};
|
||||
|
||||
struct AsmInput {
|
||||
Buf asm_symbolic_name;
|
||||
Buf constraint;
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct SrcPos {
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
struct AstNodeAsmExpr {
|
||||
bool is_volatile;
|
||||
Buf asm_template;
|
||||
ZigList<SrcPos> offset_map;
|
||||
ZigList<AsmToken> token_list;
|
||||
ZigList<AsmOutput*> output_list;
|
||||
ZigList<AsmInput*> input_list;
|
||||
ZigList<Buf*> clobber_list;
|
||||
int return_count; // populated by analyze
|
||||
};
|
||||
|
||||
struct AstNodeStructDecl {
|
||||
Buf name;
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> fns;
|
||||
ZigList<AstNode *> *directives;
|
||||
VisibMod visib_mod;
|
||||
};
|
||||
|
||||
struct AstNodeStructField {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
ZigList<AstNode *> *directives;
|
||||
};
|
||||
|
||||
struct AstNodeEnumDecl {
|
||||
Buf name;
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> *directives;
|
||||
VisibMod visib_mod;
|
||||
};
|
||||
|
||||
struct AstNodeEnumField {
|
||||
Buf name;
|
||||
ZigList<AstNode *> fields; // length 0 means simple enum
|
||||
AstNode *val_expr;
|
||||
};
|
||||
|
||||
struct AstNodeStringLiteral {
|
||||
Buf buf;
|
||||
bool c;
|
||||
};
|
||||
|
||||
struct AstNodeCharLiteral {
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
enum NumLit {
|
||||
NumLitF32,
|
||||
NumLitF64,
|
||||
NumLitF128,
|
||||
NumLitU8,
|
||||
NumLitU16,
|
||||
NumLitU32,
|
||||
NumLitU64,
|
||||
NumLitI8,
|
||||
NumLitI16,
|
||||
NumLitI32,
|
||||
NumLitI64,
|
||||
|
||||
NumLitCount
|
||||
};
|
||||
|
||||
struct AstNodeNumberLiteral {
|
||||
NumLit kind;
|
||||
|
||||
// overflow is true if when parsing the number, we discovered it would not
|
||||
// fit without losing data in a uint64_t, int64_t, or double
|
||||
bool overflow;
|
||||
|
||||
union {
|
||||
uint64_t x_uint;
|
||||
int64_t x_int;
|
||||
double x_float;
|
||||
} data;
|
||||
};
|
||||
|
||||
struct AstNodeStructValueField {
|
||||
Buf name;
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct AstNodeStructValueExpr {
|
||||
AstNode *type;
|
||||
ZigList<AstNode *> fields;
|
||||
};
|
||||
|
||||
struct AstNodeCompilerFnExpr {
|
||||
Buf name;
|
||||
AstNode *expr;
|
||||
};
|
||||
|
||||
struct AstNodeCompilerFnType {
|
||||
Buf name;
|
||||
AstNode *type;
|
||||
};
|
||||
|
||||
struct AstNode {
|
||||
enum NodeType type;
|
||||
int line;
|
||||
int column;
|
||||
uint32_t create_index; // for determinism purposes
|
||||
CodeGenNode *codegen_node;
|
||||
ImportTableEntry *owner;
|
||||
union {
|
||||
AstNodeRoot root;
|
||||
AstNodeRootExportDecl root_export_decl;
|
||||
AstNodeFnDef fn_def;
|
||||
AstNodeFnDecl fn_decl;
|
||||
AstNodeFnProto fn_proto;
|
||||
AstNodeType type;
|
||||
AstNodeParamDecl param_decl;
|
||||
AstNodeBlock block;
|
||||
AstNodeReturnExpr return_expr;
|
||||
AstNodeVariableDeclaration variable_declaration;
|
||||
AstNodeBinOpExpr bin_op_expr;
|
||||
AstNodeExternBlock extern_block;
|
||||
AstNodeDirective directive;
|
||||
AstNodeCastExpr cast_expr;
|
||||
AstNodePrefixOpExpr prefix_op_expr;
|
||||
AstNodeFnCallExpr fn_call_expr;
|
||||
AstNodeArrayAccessExpr array_access_expr;
|
||||
AstNodeSliceExpr slice_expr;
|
||||
AstNodeUse use;
|
||||
AstNodeIfBoolExpr if_bool_expr;
|
||||
AstNodeIfVarExpr if_var_expr;
|
||||
AstNodeWhileExpr while_expr;
|
||||
AstNodeLabel label;
|
||||
AstNodeGoto go_to;
|
||||
AstNodeAsmExpr asm_expr;
|
||||
AstNodeFieldAccessExpr field_access_expr;
|
||||
AstNodeStructDecl struct_decl;
|
||||
AstNodeStructField struct_field;
|
||||
AstNodeEnumDecl enum_decl;
|
||||
AstNodeEnumField enum_field;
|
||||
AstNodeStringLiteral string_literal;
|
||||
AstNodeCharLiteral char_literal;
|
||||
AstNodeNumberLiteral number_literal;
|
||||
AstNodeStructValueExpr struct_val_expr;
|
||||
AstNodeStructValueField struct_val_field;
|
||||
AstNodeCompilerFnExpr compiler_fn_expr;
|
||||
AstNodeCompilerFnType compiler_fn_type;
|
||||
Buf symbol;
|
||||
bool bool_literal;
|
||||
} data;
|
||||
};
|
||||
|
||||
enum AsmTokenId {
|
||||
AsmTokenIdTemplate,
|
||||
AsmTokenIdPercent,
|
||||
AsmTokenIdVar,
|
||||
};
|
||||
|
||||
struct AsmToken {
|
||||
enum AsmTokenId id;
|
||||
int start;
|
||||
int end;
|
||||
};
|
||||
|
||||
__attribute__ ((format (printf, 2, 3)))
|
||||
void ast_token_error(Token *token, const char *format, ...);
|
||||
|
||||
|
|
Loading…
Reference in New Issue