1690 lines
64 KiB
C++
1690 lines
64 KiB
C++
#ifndef LIB_COMPILER_HEADER
|
|
#define LIB_COMPILER_HEADER
|
|
|
|
#define LIB_COMPILER_MAJOR 0
|
|
#define LIB_COMPILER_MINOR 6
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
|
|
#ifndef LC_THREAD_LOCAL // @override
|
|
#if defined(__cplusplus) && __cplusplus >= 201103L
|
|
#define LC_THREAD_LOCAL thread_local
|
|
#elif defined(__GNUC__)
|
|
#define LC_THREAD_LOCAL __thread
|
|
#elif defined(_MSC_VER)
|
|
#define LC_THREAD_LOCAL __declspec(thread)
|
|
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
|
|
#define LC_THREAD_LOCAL _Thread_local
|
|
#elif defined(__TINYC__)
|
|
#define LC_THREAD_LOCAL _Thread_local
|
|
#else
|
|
#error Couldnt figure out thread local, needs to be provided manually
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef LC_FUNCTION // @override
|
|
#define LC_FUNCTION
|
|
#endif
|
|
|
|
#ifndef LC_String // @override
|
|
typedef struct {
|
|
char *str;
|
|
int64_t len;
|
|
} LC_String;
|
|
#endif
|
|
|
|
#ifndef LC_USE_CUSTOM_ARENA // @override
|
|
typedef struct LC_VMemory LC_VMemory;
|
|
typedef struct LC_TempArena LC_TempArena;
|
|
typedef struct LC_Arena LC_Arena;
|
|
typedef struct LC_SourceLoc LC_SourceLoc;
|
|
|
|
struct LC_VMemory {
|
|
size_t commit;
|
|
size_t reserve;
|
|
uint8_t *data;
|
|
};
|
|
|
|
struct LC_Arena {
|
|
LC_VMemory memory;
|
|
int alignment;
|
|
size_t len;
|
|
size_t base_len; // When popping to 0 this is the minimum "len" value
|
|
// It's so that Bootstrapped arena won't delete itself when Reseting.
|
|
};
|
|
|
|
struct LC_TempArena {
|
|
LC_Arena *arena;
|
|
size_t pos;
|
|
};
|
|
#endif
|
|
|
|
typedef struct LC_MapEntry LC_MapEntry;
|
|
typedef struct LC_Map LC_Map;
|
|
typedef struct LC_AST LC_AST;
|
|
typedef struct LC_ASTPackage LC_ASTPackage;
|
|
typedef struct LC_ASTNoteList LC_ASTNoteList;
|
|
typedef struct LC_ExprCompo LC_ExprCompo;
|
|
typedef union LC_Val LC_Val;
|
|
typedef struct LC_ExprIdent LC_ExprIdent;
|
|
typedef struct LC_ExprUnary LC_ExprUnary;
|
|
typedef struct LC_ExprBinary LC_ExprBinary;
|
|
typedef struct LC_ExprField LC_ExprField;
|
|
typedef struct LC_ExprIndex LC_ExprIndex;
|
|
typedef struct LC_ExprCompoItem LC_ExprCompoItem;
|
|
typedef struct LC_ExprType LC_ExprType;
|
|
typedef struct LC_ExprCast LC_ExprCast;
|
|
typedef struct LC_ExprNote LC_ExprNote;
|
|
typedef struct LC_StmtBlock LC_StmtBlock;
|
|
typedef struct LC_StmtFor LC_StmtFor;
|
|
typedef struct LC_StmtDefer LC_StmtDefer;
|
|
typedef struct LC_StmtSwitch LC_StmtSwitch;
|
|
typedef struct LC_StmtCase LC_StmtCase;
|
|
typedef struct LC_StmtIf LC_StmtIf;
|
|
typedef struct LC_StmtBreak LC_StmtBreak;
|
|
typedef struct LC_StmtAssign LC_StmtAssign;
|
|
typedef struct LC_StmtExpr LC_StmtExpr;
|
|
typedef struct LC_StmtVar LC_StmtVar;
|
|
typedef struct LC_StmtConst LC_StmtConst;
|
|
typedef struct LC_StmtReturn LC_StmtReturn;
|
|
typedef struct LC_StmtNote LC_StmtNote;
|
|
typedef struct LC_TypespecArray LC_TypespecArray;
|
|
typedef struct LC_TypespecProc LC_TypespecProc;
|
|
typedef struct LC_TypespecAggMem LC_TypespecAggMem;
|
|
typedef struct LC_TypespecProcArg LC_TypespecProcArg;
|
|
typedef struct LC_DeclBase LC_DeclBase;
|
|
typedef struct LC_DeclProc LC_DeclProc;
|
|
typedef struct LC_DeclTypedef LC_DeclTypedef;
|
|
typedef struct LC_DeclAgg LC_DeclAgg;
|
|
typedef struct LC_DeclVar LC_DeclVar;
|
|
typedef struct LC_DeclConst LC_DeclConst;
|
|
typedef struct LC_DeclNote LC_DeclNote;
|
|
typedef union LC_ASTValue LC_ASTValue;
|
|
typedef struct LC_TypeAndVal LC_TypeAndVal;
|
|
typedef struct LC_TypeArray LC_TypeArray;
|
|
typedef struct LC_TypePtr LC_TypePtr;
|
|
typedef struct LC_TypeMemberList LC_TypeMemberList;
|
|
typedef struct LC_TypeProc LC_TypeProc;
|
|
typedef struct LC_TypeAgg LC_TypeAgg;
|
|
typedef union LC_TypeValue LC_TypeValue;
|
|
typedef struct LC_Type LC_Type;
|
|
typedef struct LC_TypeMember LC_TypeMember;
|
|
typedef struct LC_Decl LC_Decl;
|
|
typedef struct LC_DeclStack LC_DeclStack;
|
|
typedef struct LC_Map DeclScope;
|
|
typedef struct LC_ResolvedCompo LC_ResolvedCompo;
|
|
typedef struct LC_ResolvedCompoItem LC_ResolvedCompoItem;
|
|
typedef struct LC_ResolvedCompoArrayItem LC_ResolvedCompoArrayItem;
|
|
typedef struct LC_ResolvedArrayCompo LC_ResolvedArrayCompo;
|
|
typedef union LC_TokenVal LC_TokenVal;
|
|
typedef struct LC_Token LC_Token;
|
|
typedef struct LC_Lex LC_Lex;
|
|
typedef struct LC_Parser LC_Parser;
|
|
typedef struct LC_Resolver LC_Resolver;
|
|
typedef struct LC_Lang LC_Lang;
|
|
typedef struct LC_ASTRef LC_ASTRef;
|
|
typedef struct LC_ASTRefList LC_ASTRefList;
|
|
typedef struct LC_ASTFile LC_ASTFile;
|
|
typedef LC_Val Expr_Atom;
|
|
typedef LC_TypespecArray Typespec_Pointer;
|
|
typedef uintptr_t LC_Intern;
|
|
typedef struct LC_GlobImport LC_GlobImport;
|
|
typedef struct LC_UTF32Result LC_UTF32Result;
|
|
typedef struct LC_UTF8Result LC_UTF8Result;
|
|
typedef struct LC_UTF16Result LC_UTF16Result;
|
|
|
|
typedef struct LC_StringNode LC_StringNode;
|
|
struct LC_StringNode {
|
|
LC_StringNode *next;
|
|
LC_String string;
|
|
};
|
|
|
|
typedef struct LC_StringList LC_StringList;
|
|
struct LC_StringList {
|
|
int64_t node_count;
|
|
int64_t char_count;
|
|
LC_StringNode *first;
|
|
LC_StringNode *last;
|
|
};
|
|
|
|
typedef struct LC_String16 {
|
|
wchar_t *str;
|
|
int64_t len;
|
|
} LC_String16;
|
|
|
|
struct LC_MapEntry {
|
|
uint64_t key;
|
|
uint64_t value;
|
|
};
|
|
|
|
struct LC_Map {
|
|
LC_Arena *arena;
|
|
LC_MapEntry *entries;
|
|
int cap;
|
|
int len;
|
|
};
|
|
|
|
typedef struct LC_BigInt LC_BigInt;
|
|
struct LC_BigInt {
|
|
unsigned digit_count;
|
|
bool is_negative;
|
|
union {
|
|
uint64_t digit;
|
|
uint64_t *digits;
|
|
};
|
|
};
|
|
|
|
typedef enum LC_ASTKind {
|
|
LC_ASTKind_Null,
|
|
LC_ASTKind_Error,
|
|
LC_ASTKind_Note,
|
|
LC_ASTKind_NoteList,
|
|
LC_ASTKind_File,
|
|
LC_ASTKind_Package,
|
|
LC_ASTKind_Ignore,
|
|
LC_ASTKind_TypespecProcArg,
|
|
LC_ASTKind_TypespecAggMem,
|
|
LC_ASTKind_ExprCallItem,
|
|
LC_ASTKind_ExprCompoundItem,
|
|
LC_ASTKind_ExprNote, // a: int = #`sizeof(int)`;
|
|
LC_ASTKind_StmtSwitchCase,
|
|
LC_ASTKind_StmtSwitchDefault,
|
|
LC_ASTKind_StmtElseIf,
|
|
LC_ASTKind_StmtElse,
|
|
LC_ASTKind_GlobImport,
|
|
LC_ASTKind_DeclNote,
|
|
LC_ASTKind_DeclProc,
|
|
LC_ASTKind_DeclStruct,
|
|
LC_ASTKind_DeclUnion,
|
|
LC_ASTKind_DeclVar,
|
|
LC_ASTKind_DeclConst,
|
|
LC_ASTKind_DeclTypedef,
|
|
LC_ASTKind_TypespecIdent,
|
|
LC_ASTKind_TypespecField,
|
|
LC_ASTKind_TypespecPointer,
|
|
LC_ASTKind_TypespecArray,
|
|
LC_ASTKind_TypespecProc,
|
|
LC_ASTKind_StmtBlock,
|
|
LC_ASTKind_StmtNote,
|
|
LC_ASTKind_StmtReturn,
|
|
LC_ASTKind_StmtBreak,
|
|
LC_ASTKind_StmtContinue,
|
|
LC_ASTKind_StmtDefer,
|
|
LC_ASTKind_StmtFor,
|
|
LC_ASTKind_StmtIf,
|
|
LC_ASTKind_StmtSwitch,
|
|
LC_ASTKind_StmtAssign,
|
|
LC_ASTKind_StmtExpr,
|
|
LC_ASTKind_StmtVar,
|
|
LC_ASTKind_StmtConst,
|
|
LC_ASTKind_ExprIdent,
|
|
LC_ASTKind_ExprString,
|
|
LC_ASTKind_ExprInt,
|
|
LC_ASTKind_ExprFloat,
|
|
LC_ASTKind_ExprBool,
|
|
LC_ASTKind_ExprType,
|
|
LC_ASTKind_ExprBinary,
|
|
LC_ASTKind_ExprUnary,
|
|
LC_ASTKind_ExprBuiltin,
|
|
LC_ASTKind_ExprCall,
|
|
LC_ASTKind_ExprCompound,
|
|
LC_ASTKind_ExprCast,
|
|
LC_ASTKind_ExprField,
|
|
LC_ASTKind_ExprIndex,
|
|
LC_ASTKind_ExprAddPtr,
|
|
LC_ASTKind_ExprGetValueOfPointer,
|
|
LC_ASTKind_ExprGetPointerOfValue,
|
|
LC_ASTKind_Count,
|
|
LC_ASTKind_FirstExpr = LC_ASTKind_ExprIdent,
|
|
LC_ASTKind_LastExpr = LC_ASTKind_ExprGetPointerOfValue,
|
|
LC_ASTKind_FirstStmt = LC_ASTKind_StmtBlock,
|
|
LC_ASTKind_LastStmt = LC_ASTKind_StmtConst,
|
|
LC_ASTKind_FirstTypespec = LC_ASTKind_TypespecIdent,
|
|
LC_ASTKind_LastTypespec = LC_ASTKind_TypespecProc,
|
|
LC_ASTKind_FirstDecl = LC_ASTKind_DeclProc,
|
|
LC_ASTKind_LastDecl = LC_ASTKind_DeclTypedef,
|
|
} LC_ASTKind;
|
|
|
|
typedef enum LC_TypeKind {
|
|
LC_TypeKind_char,
|
|
LC_TypeKind_uchar,
|
|
LC_TypeKind_short,
|
|
LC_TypeKind_ushort,
|
|
LC_TypeKind_bool,
|
|
LC_TypeKind_int,
|
|
LC_TypeKind_uint,
|
|
LC_TypeKind_long,
|
|
LC_TypeKind_ulong,
|
|
LC_TypeKind_llong,
|
|
LC_TypeKind_ullong,
|
|
LC_TypeKind_float,
|
|
LC_TypeKind_double,
|
|
LC_TypeKind_void,
|
|
LC_TypeKind_Struct,
|
|
LC_TypeKind_Union,
|
|
LC_TypeKind_Pointer,
|
|
LC_TypeKind_Array,
|
|
LC_TypeKind_Proc,
|
|
LC_TypeKind_UntypedInt,
|
|
LC_TypeKind_UntypedFloat,
|
|
LC_TypeKind_UntypedString,
|
|
LC_TypeKind_Incomplete,
|
|
LC_TypeKind_Completing,
|
|
LC_TypeKind_Error,
|
|
T_TotalCount,
|
|
T_NumericCount = LC_TypeKind_void,
|
|
T_Count = LC_TypeKind_void + 1,
|
|
} LC_TypeKind;
|
|
|
|
typedef enum LC_DeclState {
|
|
LC_DeclState_Unresolved,
|
|
LC_DeclState_Resolving,
|
|
LC_DeclState_Resolved,
|
|
LC_DeclState_ResolvedBody, // proc
|
|
LC_DeclState_Error,
|
|
LC_DeclState_Count,
|
|
} LC_DeclState;
|
|
|
|
typedef enum LC_DeclKind {
|
|
LC_DeclKind_Error,
|
|
LC_DeclKind_Type,
|
|
LC_DeclKind_Const,
|
|
LC_DeclKind_Var,
|
|
LC_DeclKind_Proc,
|
|
LC_DeclKind_Import,
|
|
LC_DeclKind_Count,
|
|
} LC_DeclKind;
|
|
|
|
typedef enum LC_TokenKind {
|
|
LC_TokenKind_EOF,
|
|
LC_TokenKind_Error,
|
|
LC_TokenKind_Comment,
|
|
LC_TokenKind_DocComment,
|
|
LC_TokenKind_FileDocComment,
|
|
LC_TokenKind_PackageDocComment,
|
|
LC_TokenKind_Note,
|
|
LC_TokenKind_Hash,
|
|
LC_TokenKind_Ident,
|
|
LC_TokenKind_Keyword,
|
|
LC_TokenKind_String,
|
|
LC_TokenKind_RawString,
|
|
LC_TokenKind_Int,
|
|
LC_TokenKind_Float,
|
|
LC_TokenKind_Unicode,
|
|
LC_TokenKind_OpenParen,
|
|
LC_TokenKind_CloseParen,
|
|
LC_TokenKind_OpenBrace,
|
|
LC_TokenKind_CloseBrace,
|
|
LC_TokenKind_OpenBracket,
|
|
LC_TokenKind_CloseBracket,
|
|
LC_TokenKind_Comma,
|
|
LC_TokenKind_Question,
|
|
LC_TokenKind_Semicolon,
|
|
LC_TokenKind_Dot,
|
|
LC_TokenKind_ThreeDots,
|
|
LC_TokenKind_Colon,
|
|
LC_TokenKind_Mul,
|
|
LC_TokenKind_Div,
|
|
LC_TokenKind_Mod,
|
|
LC_TokenKind_LeftShift,
|
|
LC_TokenKind_RightShift,
|
|
LC_TokenKind_Add,
|
|
LC_TokenKind_Sub,
|
|
LC_TokenKind_Equals,
|
|
LC_TokenKind_LesserThen,
|
|
LC_TokenKind_GreaterThen,
|
|
LC_TokenKind_LesserThenEq,
|
|
LC_TokenKind_GreaterThenEq,
|
|
LC_TokenKind_NotEquals,
|
|
LC_TokenKind_BitAnd,
|
|
LC_TokenKind_BitOr,
|
|
LC_TokenKind_BitXor,
|
|
LC_TokenKind_And,
|
|
LC_TokenKind_Or,
|
|
LC_TokenKind_AddPtr,
|
|
LC_TokenKind_Neg,
|
|
LC_TokenKind_Not,
|
|
LC_TokenKind_Assign,
|
|
LC_TokenKind_DivAssign,
|
|
LC_TokenKind_MulAssign,
|
|
LC_TokenKind_ModAssign,
|
|
LC_TokenKind_SubAssign,
|
|
LC_TokenKind_AddAssign,
|
|
LC_TokenKind_BitAndAssign,
|
|
LC_TokenKind_BitOrAssign,
|
|
LC_TokenKind_BitXorAssign,
|
|
LC_TokenKind_LeftShiftAssign,
|
|
LC_TokenKind_RightShiftAssign,
|
|
LC_TokenKind_Count,
|
|
} LC_TokenKind;
|
|
|
|
struct LC_ASTFile {
|
|
LC_AST *package;
|
|
LC_Lex *x;
|
|
|
|
LC_AST *fimport;
|
|
LC_AST *limport;
|
|
LC_AST *fdecl;
|
|
LC_AST *ldecl;
|
|
|
|
LC_Token *doc_comment;
|
|
};
|
|
|
|
// This extension thing is only to minimize package ast size!
|
|
// I want all nodes to be equal in size, this way a lot of things are
|
|
// easier. You can loop through all the ast nodes easily and stuff like that.
|
|
typedef struct LC_ASTPackageExt LC_ASTPackageExt;
|
|
struct LC_ASTPackageExt {
|
|
LC_StringList injected_filepaths; // to sidestep regular file finding, implement single file packages etc.
|
|
LC_Token *doc_comment;
|
|
LC_DeclState state;
|
|
LC_String path;
|
|
|
|
// These are resolved later:
|
|
// @todo: add foreign name?
|
|
LC_Decl *first_ordered;
|
|
LC_Decl *last_ordered;
|
|
DeclScope *scope;
|
|
};
|
|
|
|
struct LC_ASTPackage {
|
|
LC_AST *ffile;
|
|
LC_AST *lfile;
|
|
LC_Intern name;
|
|
LC_ASTPackageExt *ext;
|
|
};
|
|
|
|
struct LC_ASTNoteList {
|
|
LC_AST *first;
|
|
LC_AST *last;
|
|
};
|
|
|
|
struct LC_ResolvedCompo {
|
|
int count;
|
|
LC_ResolvedCompoItem *first;
|
|
LC_ResolvedCompoItem *last;
|
|
};
|
|
|
|
struct LC_ResolvedCompoItem {
|
|
LC_ResolvedCompoItem *next;
|
|
LC_AST *comp; // for proc this may be null because we might match default value
|
|
LC_AST *expr; // for proc this is very important, the result, ordered expression
|
|
LC_TypeMember *t;
|
|
bool varg;
|
|
bool defaultarg;
|
|
};
|
|
|
|
struct LC_ResolvedCompoArrayItem {
|
|
LC_ResolvedCompoArrayItem *next;
|
|
LC_AST *comp;
|
|
int index;
|
|
};
|
|
|
|
struct LC_ResolvedArrayCompo {
|
|
int count;
|
|
LC_ResolvedCompoArrayItem *first;
|
|
LC_ResolvedCompoArrayItem *last;
|
|
};
|
|
|
|
struct LC_ExprCompo {
|
|
LC_AST *name; // :name{thing} or name(thing)
|
|
LC_AST *first; // {LC_ExprCompoItem, LC_ExprCompoItem}
|
|
LC_AST *last;
|
|
int size;
|
|
union {
|
|
LC_ResolvedCompo *resolved_items;
|
|
LC_ResolvedArrayCompo *resolved_array_items;
|
|
};
|
|
};
|
|
|
|
struct LC_ExprCompoItem {
|
|
LC_Intern name;
|
|
LC_AST *index;
|
|
LC_AST *expr;
|
|
};
|
|
|
|
// clang-format off
|
|
union LC_Val { LC_BigInt i; double d; LC_Intern name; };
|
|
struct LC_ExprIdent { LC_Intern name; LC_Decl *resolved_decl; };
|
|
struct LC_ExprUnary { LC_TokenKind op; LC_AST *expr; };
|
|
struct LC_ExprBinary { LC_TokenKind op; LC_AST *left; LC_AST *right; };
|
|
struct LC_ExprField { LC_AST *left; LC_Intern right; LC_Decl *resolved_decl; LC_Decl *parent_decl; };
|
|
struct LC_ExprIndex { LC_AST *base; LC_AST *index; };
|
|
struct LC_ExprType { LC_AST *type; };
|
|
struct LC_ExprCast { LC_AST *type; LC_AST *expr; };
|
|
struct LC_ExprNote { LC_AST *expr; }; // v := #c(``)
|
|
|
|
typedef enum { SBLK_Norm, SBLK_Loop, SBLK_Proc, SBLK_Defer } LC_StmtBlockKind;
|
|
struct LC_StmtBlock { LC_AST *first; LC_AST *last; LC_AST *first_defer; LC_StmtBlockKind kind; LC_Intern name; };
|
|
struct LC_StmtFor { LC_AST *init; LC_AST *cond; LC_AST *inc; LC_AST *body; };
|
|
struct LC_StmtDefer { LC_AST *next; LC_AST *body; };
|
|
struct LC_StmtSwitch { LC_AST *first; LC_AST *last; LC_AST *expr; int total_switch_case_count; };
|
|
struct LC_StmtCase { LC_AST *first; LC_AST *last; LC_AST *body; };
|
|
// 'else if' and 'else' is avaialable from 'first'.
|
|
// The else_if and else are also LC_StmtIf but
|
|
// have different kinds and don't use 'first', 'last'
|
|
struct LC_StmtIf { LC_AST *expr; LC_AST *body; LC_AST *first; LC_AST *last; };
|
|
struct LC_StmtBreak { LC_Intern name; };
|
|
struct LC_StmtAssign { LC_TokenKind op; LC_AST *left; LC_AST *right; };
|
|
struct LC_StmtExpr { LC_AST *expr; };
|
|
struct LC_StmtVar { LC_AST *expr; LC_AST *type; LC_Intern name; LC_Decl *resolved_decl; };
|
|
struct LC_StmtConst { LC_AST *expr; LC_Intern name; };
|
|
struct LC_StmtReturn { LC_AST *expr; };
|
|
struct LC_StmtNote { LC_AST *expr; }; // #c(``) in block
|
|
struct LC_TypespecArray { LC_AST *base; LC_AST *index; };
|
|
struct LC_TypespecProc { LC_AST *first; LC_AST *last; LC_AST *ret; bool vargs; bool vargs_any_promotion; };
|
|
struct LC_TypespecAggMem { LC_Intern name; LC_AST *type; };
|
|
struct LC_TypespecProcArg { LC_Intern name; LC_AST *type; LC_AST *expr; LC_Decl *resolved_decl; };
|
|
struct LC_DeclBase { LC_Intern name; LC_Token *doc_comment; LC_Decl *resolved_decl; };
|
|
struct LC_DeclProc { LC_DeclBase base; LC_AST *body; LC_AST *type; };
|
|
struct LC_DeclTypedef { LC_DeclBase base; LC_AST *type; };
|
|
struct LC_DeclAgg { LC_DeclBase base; LC_AST *first; LC_AST *last; };
|
|
struct LC_DeclVar { LC_DeclBase base; LC_AST *expr; LC_AST *type; };
|
|
struct LC_DeclConst { LC_DeclBase base; LC_AST *expr; };
|
|
struct LC_DeclNote { LC_DeclBase base; LC_AST *expr; bool processed; }; // #c(``) in file note list
|
|
struct LC_GlobImport { LC_Intern name; LC_Intern path; bool resolved; LC_Decl *resolved_decl; };
|
|
|
|
struct LC_ASTRef { LC_ASTRef *next; LC_ASTRef *prev; LC_AST *ast; };
|
|
struct LC_ASTRefList { LC_ASTRef *first; LC_ASTRef *last; };
|
|
// clang-format on
|
|
|
|
struct LC_TypeAndVal {
|
|
LC_Type *type;
|
|
union {
|
|
LC_Val v;
|
|
union {
|
|
LC_BigInt i;
|
|
double d;
|
|
LC_Intern name;
|
|
};
|
|
};
|
|
};
|
|
|
|
struct LC_AST {
|
|
LC_ASTKind kind;
|
|
uint32_t id;
|
|
LC_AST *next;
|
|
LC_AST *prev;
|
|
LC_AST *notes;
|
|
LC_Token *pos;
|
|
|
|
LC_TypeAndVal const_val;
|
|
LC_Type *type;
|
|
union {
|
|
LC_ASTFile afile;
|
|
LC_ASTPackage apackage;
|
|
LC_ASTNoteList anote_list;
|
|
LC_ExprCompo anote;
|
|
LC_Val eatom;
|
|
LC_ExprIdent eident;
|
|
LC_ExprUnary eunary;
|
|
LC_ExprBinary ebinary;
|
|
LC_ExprField efield;
|
|
LC_ExprIndex eindex;
|
|
LC_ExprCompo ecompo;
|
|
LC_ExprCompoItem ecompo_item;
|
|
LC_ExprType etype;
|
|
LC_ExprCast ecast;
|
|
LC_ExprNote enote;
|
|
LC_StmtBlock sblock;
|
|
LC_StmtFor sfor;
|
|
LC_StmtDefer sdefer;
|
|
LC_StmtSwitch sswitch;
|
|
LC_StmtCase scase;
|
|
LC_StmtIf sif;
|
|
LC_StmtBreak sbreak;
|
|
LC_StmtBreak scontinue;
|
|
LC_StmtAssign sassign;
|
|
LC_StmtExpr sexpr;
|
|
LC_StmtVar svar;
|
|
LC_StmtConst sconst;
|
|
LC_StmtReturn sreturn;
|
|
LC_StmtNote snote;
|
|
LC_ExprIdent tident;
|
|
LC_TypespecArray tarray;
|
|
LC_TypespecArray tpointer;
|
|
LC_TypespecProc tproc;
|
|
LC_TypespecAggMem tagg_mem;
|
|
LC_TypespecProcArg tproc_arg;
|
|
LC_DeclBase dbase;
|
|
LC_DeclProc dproc;
|
|
LC_DeclTypedef dtypedef;
|
|
LC_DeclAgg dagg;
|
|
LC_DeclVar dvar;
|
|
LC_DeclConst dconst;
|
|
LC_DeclNote dnote;
|
|
LC_GlobImport gimport;
|
|
};
|
|
};
|
|
|
|
struct LC_TypeArray {
|
|
LC_Type *base;
|
|
int size;
|
|
};
|
|
|
|
struct LC_TypePtr {
|
|
LC_Type *base;
|
|
};
|
|
|
|
struct LC_TypeMemberList {
|
|
LC_TypeMember *first;
|
|
LC_TypeMember *last;
|
|
int count;
|
|
};
|
|
|
|
struct LC_TypeProc {
|
|
LC_TypeMemberList args;
|
|
LC_Type *ret;
|
|
bool vargs;
|
|
bool vargs_any_promotion;
|
|
};
|
|
|
|
struct LC_TypeAgg {
|
|
LC_TypeMemberList mems;
|
|
};
|
|
|
|
struct LC_Type {
|
|
LC_TypeKind kind;
|
|
int size;
|
|
int align;
|
|
int is_unsigned;
|
|
int id;
|
|
int padding;
|
|
LC_Decl *decl;
|
|
union {
|
|
LC_TypeArray tarray;
|
|
LC_TypePtr tptr;
|
|
LC_TypeProc tproc;
|
|
LC_TypeAgg tagg;
|
|
LC_Type *tbase;
|
|
LC_Type *tutdefault;
|
|
};
|
|
};
|
|
|
|
struct LC_TypeMember {
|
|
LC_TypeMember *next;
|
|
LC_TypeMember *prev;
|
|
LC_Intern name;
|
|
LC_Type *type;
|
|
LC_AST *default_value_expr;
|
|
LC_AST *ast;
|
|
int offset;
|
|
};
|
|
|
|
struct LC_Decl {
|
|
LC_DeclKind kind;
|
|
LC_DeclState state;
|
|
uint8_t is_foreign;
|
|
|
|
LC_Decl *next;
|
|
LC_Decl *prev;
|
|
LC_Intern name;
|
|
LC_Intern foreign_name;
|
|
LC_AST *ast;
|
|
LC_AST *package;
|
|
|
|
LC_TypeMember *type_member;
|
|
DeclScope *scope;
|
|
LC_Decl *typedef_renamed_type_decl;
|
|
union {
|
|
LC_TypeAndVal val;
|
|
struct {
|
|
LC_Type *type;
|
|
LC_Val v;
|
|
};
|
|
};
|
|
};
|
|
|
|
typedef struct {
|
|
LC_Arena *arena;
|
|
LC_AST **data;
|
|
int cap;
|
|
int len;
|
|
} LC_ASTArray;
|
|
|
|
typedef struct LC_ASTWalker LC_ASTWalker;
|
|
typedef void LC_ASTWalkProc(LC_ASTWalker *, LC_AST *);
|
|
struct LC_ASTWalker {
|
|
LC_ASTArray stack;
|
|
|
|
int inside_builtin;
|
|
int inside_note;
|
|
|
|
uint8_t visit_notes;
|
|
uint8_t depth_first;
|
|
uint8_t dont_recurse; // breathfirst only
|
|
void *user_data;
|
|
LC_ASTWalkProc *proc;
|
|
};
|
|
|
|
struct LC_DeclStack {
|
|
LC_Decl **stack;
|
|
int len;
|
|
int cap;
|
|
};
|
|
|
|
union LC_TokenVal {
|
|
LC_BigInt i;
|
|
double f64;
|
|
LC_Intern ident;
|
|
};
|
|
|
|
struct LC_Token {
|
|
LC_TokenKind kind;
|
|
int line;
|
|
int column;
|
|
int len;
|
|
char *str;
|
|
LC_Lex *lex;
|
|
union {
|
|
LC_BigInt i;
|
|
double f64;
|
|
LC_Intern ident;
|
|
};
|
|
};
|
|
|
|
struct LC_Lex {
|
|
char *at;
|
|
char *begin;
|
|
LC_Intern file;
|
|
int line;
|
|
int column;
|
|
LC_Token *tokens;
|
|
int token_count;
|
|
bool insert_semicolon;
|
|
};
|
|
|
|
struct LC_Parser {
|
|
LC_Token *at;
|
|
LC_Token *begin;
|
|
LC_Token *end;
|
|
LC_Lex *x;
|
|
};
|
|
|
|
struct LC_Resolver {
|
|
LC_Type *compo_context_type;
|
|
int compo_context_array_size;
|
|
LC_Type *expected_ret_type;
|
|
LC_AST *package;
|
|
DeclScope *active_scope;
|
|
LC_DeclStack locals;
|
|
LC_Map duplicate_map; // currently used for finding duplicates in compos
|
|
LC_ASTArray stmt_block_stack;
|
|
};
|
|
|
|
typedef struct LC_Printer LC_Printer;
|
|
struct LC_Printer {
|
|
LC_Arena *arena;
|
|
LC_StringList list;
|
|
int indent;
|
|
LC_Intern last_filename;
|
|
int last_line_num;
|
|
LC_ASTArray out_block_stack;
|
|
};
|
|
|
|
const int LC_OPF_Error = 1;
|
|
const int LC_OPF_UTConst = 2;
|
|
const int LC_OPF_LValue = 4;
|
|
const int LC_OPF_Const = 8;
|
|
const int LC_OPF_Returned = 16;
|
|
|
|
// warning: I introduced a null compare using the values in the operand
|
|
// make sure to revisit that when modifying the struct
|
|
typedef struct {
|
|
int flags;
|
|
union {
|
|
LC_Decl *decl;
|
|
LC_TypeAndVal val;
|
|
struct {
|
|
LC_Type *type;
|
|
LC_Val v;
|
|
};
|
|
};
|
|
} LC_Operand;
|
|
|
|
typedef enum {
|
|
LC_ARCH_Invalid,
|
|
LC_ARCH_X64,
|
|
LC_ARCH_X86,
|
|
LC_ARCH_Count,
|
|
} LC_ARCH;
|
|
|
|
typedef enum {
|
|
LC_GEN_Invalid,
|
|
LC_GEN_C,
|
|
LC_GEN_Count,
|
|
} LC_GEN;
|
|
|
|
typedef enum {
|
|
LC_OS_Invalid,
|
|
LC_OS_WINDOWS,
|
|
LC_OS_LINUX,
|
|
LC_OS_MAC,
|
|
LC_OS_Count,
|
|
} LC_OS;
|
|
|
|
typedef struct {
|
|
LC_String path;
|
|
LC_String content;
|
|
int line;
|
|
} LoadedFile;
|
|
|
|
typedef enum {
|
|
LC_OPResult_Error,
|
|
LC_OPResult_Ok,
|
|
LC_OPResult_Bool,
|
|
} LC_OPResult;
|
|
|
|
typedef struct {
|
|
int left;
|
|
int right;
|
|
} LC_Precedence;
|
|
|
|
typedef enum {
|
|
LC_PrecedenceKind_Prefix,
|
|
LC_PrecedenceKind_Infix,
|
|
LC_PrecedenceKind_Postfix,
|
|
} LC_PrecedenceKind;
|
|
|
|
typedef enum {
|
|
LC_CmpRes_LT,
|
|
LC_CmpRes_GT,
|
|
LC_CmpRes_EQ,
|
|
} LC_CmpRes;
|
|
|
|
typedef struct LC_FileIter LC_FileIter;
|
|
struct LC_FileIter {
|
|
bool is_valid;
|
|
bool is_directory;
|
|
LC_String absolute_path;
|
|
LC_String relative_path;
|
|
LC_String filename;
|
|
|
|
LC_String path;
|
|
LC_Arena *arena;
|
|
union {
|
|
struct LC_Win32_FileIter *w32;
|
|
void *dir;
|
|
};
|
|
};
|
|
|
|
#define LC_LIST_KEYWORDS \
|
|
X(for) \
|
|
X(import) \
|
|
X(if) \
|
|
X(else) \
|
|
X(return) \
|
|
X(defer) \
|
|
X(continue) \
|
|
X(break) \
|
|
X(default) \
|
|
X(case) \
|
|
X(typedef) \
|
|
X(switch) \
|
|
X(proc) \
|
|
X(struct) \
|
|
X(union) \
|
|
X(addptr) \
|
|
X(true) \
|
|
X(false)
|
|
|
|
#define LC_LIST_INTERNS \
|
|
X(foreign, true) \
|
|
X(api, true) \
|
|
X(weak, true) \
|
|
X(c, true) \
|
|
X(fallthrough, true) \
|
|
X(packed, true) \
|
|
X(not_init, true) \
|
|
X(unused, true) \
|
|
X(static_assert, true) \
|
|
X(str, true) \
|
|
X(thread_local, true) \
|
|
X(dont_mangle, true) \
|
|
X(build_if, true) \
|
|
X(Any, false) \
|
|
X(main, false) \
|
|
X(debug_break, false) \
|
|
X(sizeof, false) \
|
|
X(alignof, false) \
|
|
X(typeof, false) \
|
|
X(lengthof, false) \
|
|
X(offsetof, false)
|
|
|
|
#define LC_LIST_TYPES \
|
|
X(char, false) \
|
|
X(uchar, true) \
|
|
X(short, false) \
|
|
X(ushort, true) \
|
|
X(bool, false) \
|
|
X(int, false) \
|
|
X(uint, true) \
|
|
X(long, false) \
|
|
X(ulong, true) \
|
|
X(llong, false) \
|
|
X(ullong, true) \
|
|
X(float, false) \
|
|
X(double, false)
|
|
|
|
struct LC_Lang {
|
|
LC_Arena *arena;
|
|
|
|
LC_Arena *lex_arena;
|
|
|
|
LC_Arena *ast_arena;
|
|
int ast_count;
|
|
|
|
LC_Arena *decl_arena;
|
|
int decl_count;
|
|
|
|
LC_Arena *type_arena;
|
|
int type_count;
|
|
|
|
int errors;
|
|
|
|
int typeids;
|
|
LC_Map type_map;
|
|
|
|
LC_AST *builtin_package;
|
|
LC_Resolver resolver;
|
|
LC_Parser *parser;
|
|
|
|
// Package registry
|
|
LC_AST *fpackage;
|
|
LC_AST *lpackage;
|
|
LC_Intern first_package;
|
|
LC_ASTRefList ordered_packages;
|
|
LC_StringList package_dirs;
|
|
LC_ASTRefList discarded;
|
|
|
|
LC_Map interns;
|
|
LC_Map declared_notes;
|
|
LC_Map foreign_names;
|
|
LC_Map implicit_any;
|
|
unsigned unique_counter;
|
|
|
|
LC_Intern first_keyword;
|
|
LC_Intern last_keyword;
|
|
|
|
#define X(x) LC_Intern k##x;
|
|
LC_LIST_KEYWORDS
|
|
#undef X
|
|
|
|
#define X(x, declare) LC_Intern i##x;
|
|
LC_LIST_INTERNS
|
|
#undef X
|
|
|
|
LC_Type types[14]; // be careful when changing
|
|
#define X(TNAME, IS_UNSIGNED) LC_Type *t##TNAME;
|
|
LC_LIST_TYPES
|
|
#undef X
|
|
|
|
// When adding new special pointer types make sure to
|
|
// also update LC_SetPointerSizeAndAlign so that it properly
|
|
// updates the types after LC_LangBegin
|
|
int pointer_size;
|
|
int pointer_align;
|
|
LC_Type *tvoid;
|
|
LC_Type *tpvoid;
|
|
LC_Type *tpchar;
|
|
|
|
LC_Type ttstring;
|
|
LC_Type *tstring;
|
|
LC_Type *tuntypednil;
|
|
LC_Type *tuntypedbool;
|
|
LC_Type *tuntypedint;
|
|
LC_Type ttuntypedfloat;
|
|
LC_Type *tuntypedfloat;
|
|
LC_Type ttuntypedstring;
|
|
LC_Type *tuntypedstring;
|
|
LC_Type ttany;
|
|
LC_Type *tany;
|
|
|
|
LC_Token NullToken;
|
|
LC_AST NullAST;
|
|
LC_Token BuiltinToken;
|
|
LC_Lex NullLEX;
|
|
|
|
LC_Printer printer;
|
|
LC_Parser quick_parser;
|
|
|
|
// @configurable
|
|
LC_ARCH arch;
|
|
LC_GEN gen;
|
|
LC_OS os;
|
|
|
|
bool emit_line_directives;
|
|
bool breakpoint_on_error;
|
|
bool use_colored_terminal_output;
|
|
|
|
void (*on_tokens_lexed)(LC_Lex *x);
|
|
void (*on_tokens_interned)(LC_Lex *x);
|
|
void (*on_decl_parsed)(LC_AST *n);
|
|
void (*on_expr_parsed)(LC_AST *n);
|
|
void (*on_stmt_parsed)(LC_AST *n);
|
|
void (*on_typespec_parsed)(LC_AST *n);
|
|
void (*on_decl_type_resolved)(LC_Decl *decl);
|
|
void (*on_proc_body_resolved)(LC_Decl *decl);
|
|
void (*on_expr_resolved)(LC_AST *expr, LC_Operand *op);
|
|
void (*on_stmt_resolved)(LC_AST *n);
|
|
void (*before_call_args_resolved)(LC_AST *n, LC_Type *type);
|
|
void (*on_file_load)(LC_AST *package, LoadedFile *file);
|
|
void (*on_message)(LC_Token *pos, char *str, int len); // pos and x can be null
|
|
void (*on_fatal_error)(void);
|
|
void *user_data;
|
|
};
|
|
|
|
extern LC_THREAD_LOCAL LC_Lang *L;
|
|
|
|
//
|
|
// Main @api
|
|
//
|
|
|
|
LC_FUNCTION LC_Lang *LC_LangAlloc(void); // This allocates memory for LC_Lang which can be used to register callbacks and set configurables
|
|
LC_FUNCTION void LC_LangBegin(LC_Lang *l); // Prepare for compilation: init types, init builtins, set architecture variables stuff like that
|
|
LC_FUNCTION void LC_LangEnd(LC_Lang *lang); // Deallocate language memory
|
|
|
|
LC_FUNCTION void LC_RegisterPackageDir(char *dir); // Add a package search directory
|
|
LC_FUNCTION void LC_ParseAndResolve(LC_Intern name); // Fully resolve a package and all it's dependences
|
|
LC_FUNCTION LC_String LC_GenerateUnityBuild(void); // Generate the C program and return as a string
|
|
|
|
// Smaller passes for AST modification
|
|
LC_FUNCTION void LC_ParsePackagesPass(LC_Intern name); // These functions are equivalent to LC_ParseAndResolve,
|
|
LC_FUNCTION void LC_BuildIfPass(void); // you can use them to hook into the compilation process - you can modify the AST
|
|
LC_FUNCTION void LC_OrderAndResolveTopLevelPass(LC_Intern name); // before resolving or use resolved top declarations to generate some code.
|
|
LC_FUNCTION void LC_ResolveProcBodiesPass(void); // The Parse and Order functions can be called multiple times to accommodate this.
|
|
|
|
// Extended pass / optimization
|
|
LC_FUNCTION void LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass(void); // Extended pass that you can execute once you have resolved all packages
|
|
|
|
// These three functions are used to implement LC_FindUnusedLocalsAndRemoveUnusedGlobalDeclsPass
|
|
LC_FUNCTION void LC_CountDeclRefs(LC_Arena *arena, LC_Map *map, LC_AST *ast);
|
|
LC_FUNCTION LC_Decl *LC_RemoveUnreferencedGlobalDeclsPass(LC_Map *map_of_visits);
|
|
LC_FUNCTION void LC_ErrorOnUnreferencedLocalsPass(LC_Map *map_of_visits);
|
|
|
|
// Notes
|
|
LC_FUNCTION void LC_DeclareNote(LC_Intern intern);
|
|
LC_FUNCTION bool LC_IsNoteDeclared(LC_Intern intern);
|
|
LC_FUNCTION LC_AST *LC_HasNote(LC_AST *ast, LC_Intern i);
|
|
|
|
// Quick parse functions
|
|
LC_FUNCTION LC_AST *LC_ParseStmtf(const char *str, ...);
|
|
LC_FUNCTION LC_AST *LC_ParseExprf(const char *str, ...);
|
|
LC_FUNCTION LC_AST *LC_ParseDeclf(const char *str, ...);
|
|
|
|
// AST Walking and copy
|
|
LC_FUNCTION LC_AST *LC_CopyAST(LC_Arena *arena, LC_AST *n); // Deep copy the AST
|
|
LC_FUNCTION LC_ASTArray LC_FlattenAST(LC_Arena *arena, LC_AST *n); // This walks the passed down tree and generates a flat array of pointers, very nice to use for traversing AST
|
|
LC_FUNCTION void LC_WalkAST(LC_ASTWalker *ctx, LC_AST *n);
|
|
LC_FUNCTION LC_ASTWalker LC_GetDefaultWalker(LC_Arena *arena, LC_ASTWalkProc *proc);
|
|
|
|
LC_FUNCTION void LC_ReserveAST(LC_ASTArray *arr, int size);
|
|
LC_FUNCTION void LC_PushAST(LC_ASTArray *arr, LC_AST *ast);
|
|
LC_FUNCTION void LC_PopAST(LC_ASTArray *arr);
|
|
LC_FUNCTION LC_AST *LC_GetLastAST(LC_ASTArray *arr);
|
|
|
|
// Interning API
|
|
LC_FUNCTION LC_Intern LC_ILit(char *str);
|
|
LC_FUNCTION void LC_InternTokens(LC_Lex *x);
|
|
|
|
LC_FUNCTION LC_Intern LC_InternStrLen(char *str, int len);
|
|
LC_FUNCTION LC_Intern LC_GetUniqueIntern(const char *name_for_debug);
|
|
LC_FUNCTION char *LC_GetUniqueName(const char *name_for_debug);
|
|
|
|
//
|
|
// Package functions
|
|
//
|
|
LC_FUNCTION LC_Operand LC_ImportPackage(LC_AST *import, LC_AST *dst, LC_AST *src);
|
|
LC_FUNCTION LC_Intern LC_MakePackageNameFromPath(LC_String path);
|
|
LC_FUNCTION bool LC_PackageNameValid(LC_Intern name);
|
|
LC_FUNCTION bool LC_PackageNameDuplicate(LC_Intern name);
|
|
LC_FUNCTION void LC_AddPackageToList(LC_AST *n);
|
|
LC_FUNCTION LC_AST *LC_RegisterPackage(LC_String path);
|
|
LC_FUNCTION void LC_AddFileToPackage(LC_AST *pkg, LC_AST *f);
|
|
LC_FUNCTION LC_AST *LC_FindImportInRefList(LC_ASTRefList *arr, LC_Intern path);
|
|
LC_FUNCTION void LC_AddASTToRefList(LC_ASTRefList *refs, LC_AST *ast);
|
|
LC_FUNCTION LC_ASTRefList LC_GetPackageImports(LC_AST *package);
|
|
LC_FUNCTION LC_AST *LC_GetPackageByName(LC_Intern name);
|
|
LC_FUNCTION LC_StringList LC_ListFilesInPackage(LC_Arena *arena, LC_String path);
|
|
LC_FUNCTION LoadedFile LC_ReadFileHook(LC_AST *package, LC_String path);
|
|
LC_FUNCTION void LC_ParsePackage(LC_AST *n);
|
|
LC_FUNCTION void LC_AddOrderedPackageToRefList(LC_AST *n);
|
|
LC_FUNCTION LC_AST *LC_OrderPackagesAndBasicResolve(LC_AST *pos, LC_Intern name);
|
|
LC_FUNCTION void LC_AddSingleFilePackage(LC_Intern name, LC_String path);
|
|
|
|
//
|
|
// Lexing functions
|
|
//
|
|
LC_FUNCTION LC_Lex *LC_LexStream(char *file, char *str, int line);
|
|
LC_FUNCTION LC_String LC_GetTokenLine(LC_Token *token);
|
|
|
|
LC_FUNCTION void LC_LexingError(LC_Token *pos, const char *str, ...);
|
|
LC_FUNCTION bool LC_IsAssign(LC_TokenKind kind);
|
|
LC_FUNCTION bool LC_IsHexDigit(char c);
|
|
LC_FUNCTION bool LC_IsBinDigit(char c);
|
|
LC_FUNCTION uint64_t LC_MapCharToNumber(char c);
|
|
LC_FUNCTION uint64_t LC_GetEscapeCode(char c);
|
|
LC_FUNCTION LC_String LC_GetEscapeString(char c);
|
|
LC_FUNCTION void LC_LexAdvance(LC_Lex *x);
|
|
LC_FUNCTION void LC_EatWhitespace(LC_Lex *x);
|
|
LC_FUNCTION void LC_EatIdent(LC_Lex *x);
|
|
LC_FUNCTION void LC_SetTokenLen(LC_Lex *x, LC_Token *t);
|
|
LC_FUNCTION void LC_EatUntilIncluding(LC_Lex *x, char c);
|
|
LC_FUNCTION LC_BigInt LC_LexBigInt(char *string, int len, uint64_t base);
|
|
LC_FUNCTION void LC_LexNestedComments(LC_Lex *x, LC_Token *t);
|
|
LC_FUNCTION void LC_LexStringLiteral(LC_Lex *x, LC_Token *t, LC_TokenKind kind);
|
|
LC_FUNCTION void LC_LexUnicodeLiteral(LC_Lex *x, LC_Token *t);
|
|
LC_FUNCTION void LC_LexIntOrFloat(LC_Lex *x, LC_Token *t);
|
|
LC_FUNCTION void LC_LexCase2(LC_Lex *x, LC_Token *t, LC_TokenKind tk0, char c, LC_TokenKind tk1);
|
|
LC_FUNCTION void LC_LexCase3(LC_Lex *x, LC_Token *t, LC_TokenKind tk, char c0, LC_TokenKind tk0, char c1, LC_TokenKind tk1);
|
|
LC_FUNCTION void LC_LexCase4(LC_Lex *x, LC_Token *t, LC_TokenKind tk, char c0, LC_TokenKind tk0, char c1, LC_TokenKind tk1, char c2, LC_TokenKind tk2);
|
|
LC_FUNCTION void LC_LexNext(LC_Lex *x, LC_Token *t);
|
|
|
|
//
|
|
// LC_Map API
|
|
//
|
|
LC_FUNCTION void LC_MapReserve(LC_Map *map, int size);
|
|
LC_FUNCTION int LC_NextPow2(int v);
|
|
LC_FUNCTION LC_MapEntry *LC_GetMapEntryEx(LC_Map *map, uint64_t key);
|
|
LC_FUNCTION bool LC_InsertWithoutReplace(LC_Map *map, void *key, void *value);
|
|
LC_FUNCTION LC_MapEntry *LC_InsertMapEntry(LC_Map *map, uint64_t key, uint64_t value);
|
|
LC_FUNCTION LC_MapEntry *LC_GetMapEntry(LC_Map *map, uint64_t key);
|
|
LC_FUNCTION void LC_MapInsert(LC_Map *map, LC_String keystr, void *value);
|
|
LC_FUNCTION void *LC_MapGet(LC_Map *map, LC_String keystr);
|
|
LC_FUNCTION void LC_MapInsertU64(LC_Map *map, uint64_t key, void *value);
|
|
LC_FUNCTION void *LC_MapGetU64(LC_Map *map, uint64_t key);
|
|
LC_FUNCTION void *LC_MapGetP(LC_Map *map, void *key);
|
|
LC_FUNCTION void LC_MapInsertP(LC_Map *map, void *key, void *value);
|
|
LC_FUNCTION void LC_MapClear(LC_Map *map);
|
|
|
|
//
|
|
// LC_AST Creation
|
|
//
|
|
LC_FUNCTION LC_AST *LC_CreateAST(LC_Token *pos, LC_ASTKind kind);
|
|
LC_FUNCTION LC_AST *LC_CreateUnary(LC_Token *pos, LC_TokenKind op, LC_AST *expr);
|
|
LC_FUNCTION LC_AST *LC_CreateBinary(LC_Token *pos, LC_AST *left, LC_AST *right, LC_TokenKind op);
|
|
LC_FUNCTION LC_AST *LC_CreateIndex(LC_Token *pos, LC_AST *left, LC_AST *index);
|
|
|
|
LC_FUNCTION bool LC_ContainsCallExpr(LC_AST *ast);
|
|
LC_FUNCTION void LC_SetASTPosOnAll(LC_AST *n, LC_Token *pos);
|
|
LC_FUNCTION bool LC_ContainsCBuiltin(LC_AST *n);
|
|
|
|
//
|
|
// LC_Type functions
|
|
//
|
|
LC_FUNCTION void LC_SetPointerSizeAndAlign(int size, int align);
|
|
LC_FUNCTION LC_Type *LC_CreateType(LC_TypeKind kind);
|
|
LC_FUNCTION LC_Type *LC_CreateTypedef(LC_Decl *decl, LC_Type *base);
|
|
LC_FUNCTION LC_Type *LC_CreatePointerType(LC_Type *type);
|
|
LC_FUNCTION LC_Type *LC_CreateArrayType(LC_Type *type, int size);
|
|
LC_FUNCTION LC_Type *LC_CreateProcType(LC_TypeMemberList args, LC_Type *ret, bool has_vargs, bool has_vargs_any_promotion);
|
|
LC_FUNCTION LC_Type *LC_CreateIncompleteType(LC_Decl *decl);
|
|
LC_FUNCTION LC_Type *LC_CreateUntypedIntEx(LC_Type *base, LC_Decl *decl);
|
|
LC_FUNCTION LC_Type *LC_CreateUntypedInt(LC_Type *base);
|
|
LC_FUNCTION LC_TypeMember *LC_AddTypeToList(LC_TypeMemberList *list, LC_Intern name, LC_Type *type, LC_AST *ast);
|
|
LC_FUNCTION int LC_GetLevelsOfIndirection(LC_Type *type);
|
|
LC_FUNCTION bool LC_BigIntFits(LC_BigInt i, LC_Type *type);
|
|
LC_FUNCTION LC_Type *LC_StripPointer(LC_Type *type);
|
|
|
|
//
|
|
// Parsing functions
|
|
//
|
|
LC_FUNCTION LC_AST *LC_ParseFile(LC_AST *package, char *filename, char *content, int line);
|
|
LC_FUNCTION LC_AST *LC_ParseTokens(LC_AST *package, LC_Lex *x);
|
|
|
|
LC_FUNCTION LC_Parser LC_MakeParser(LC_Lex *x);
|
|
LC_FUNCTION LC_Parser *LC_MakeParserQuick(char *str);
|
|
LC_FUNCTION LC_Token *LC_Next(void);
|
|
LC_FUNCTION LC_Token *LC_Get(void);
|
|
LC_FUNCTION LC_Token *LC_GetI(int i);
|
|
LC_FUNCTION LC_Token *LC_Is(LC_TokenKind kind);
|
|
LC_FUNCTION LC_Token *LC_IsKeyword(LC_Intern intern);
|
|
LC_FUNCTION LC_Token *LC_Match(LC_TokenKind kind);
|
|
LC_FUNCTION LC_Token *LC_MatchKeyword(LC_Intern intern);
|
|
LC_FUNCTION LC_Precedence LC_GetPrecedence(LC_PrecedenceKind binding, LC_TokenKind kind);
|
|
LC_FUNCTION LC_AST *LC_ParseExprEx(int min_bp);
|
|
LC_FUNCTION LC_AST *LC_ParseCompo(LC_Token *pos, LC_AST *left);
|
|
LC_FUNCTION LC_AST *LC_ParseExpr(void);
|
|
LC_FUNCTION LC_AST *LC_ParseProcType(LC_Token *pos);
|
|
LC_FUNCTION LC_AST *LC_ParseType(void);
|
|
LC_FUNCTION LC_AST *LC_ParseForStmt(LC_Token *pos);
|
|
LC_FUNCTION LC_AST *LC_ParseSwitchStmt(LC_Token *pos);
|
|
LC_FUNCTION LC_AST *LC_ParseStmt(bool check_semicolon);
|
|
LC_FUNCTION LC_AST *LC_ParseStmtBlock(int flags);
|
|
LC_FUNCTION LC_AST *LC_ParseProcDecl(LC_Token *name);
|
|
LC_FUNCTION LC_AST *LC_ParseStruct(LC_ASTKind kind, LC_Token *ident);
|
|
LC_FUNCTION LC_AST *LC_ParseTypedef(LC_Token *ident);
|
|
LC_FUNCTION LC_AST *LC_CreateNote(LC_Token *pos, LC_Intern ident);
|
|
LC_FUNCTION LC_AST *LC_ParseNote(void);
|
|
LC_FUNCTION LC_AST *LC_ParseNotes(void);
|
|
LC_FUNCTION bool LC_ResolveBuildIf(LC_AST *build_if);
|
|
LC_FUNCTION LC_AST *LC_ParseImport(void);
|
|
LC_FUNCTION LC_AST *LC_ParseDecl(LC_AST *file);
|
|
LC_FUNCTION bool LC_EatUntilNextValidDecl(void);
|
|
LC_FUNCTION bool LC_ParseHashBuildOn(LC_AST *n);
|
|
LC_FUNCTION LC_AST *LC_ParseFileEx(LC_AST *package);
|
|
|
|
//
|
|
// Resolution functions
|
|
//
|
|
LC_FUNCTION void LC_AddDecl(LC_DeclStack *scope, LC_Decl *decl);
|
|
LC_FUNCTION void LC_InitDeclStack(LC_DeclStack *stack, int size);
|
|
LC_FUNCTION LC_DeclStack *LC_CreateDeclStack(int size);
|
|
LC_FUNCTION LC_Decl *LC_FindDeclOnStack(LC_DeclStack *scp, LC_Intern name);
|
|
|
|
LC_FUNCTION DeclScope *LC_CreateScope(int size);
|
|
LC_FUNCTION LC_Decl *LC_CreateDecl(LC_DeclKind kind, LC_Intern name, LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_AddDeclToScope(DeclScope *scp, LC_Decl *decl);
|
|
LC_FUNCTION LC_Decl *LC_FindDeclInScope(DeclScope *scope, LC_Intern name);
|
|
LC_FUNCTION LC_Operand LC_ThereIsNoDecl(DeclScope *scp, LC_Decl *decl, bool check_locals);
|
|
LC_FUNCTION void LC_MarkDeclError(LC_Decl *decl);
|
|
LC_FUNCTION LC_Decl *LC_GetLocalOrGlobalDecl(LC_Intern name);
|
|
LC_FUNCTION LC_Operand LC_PutGlobalDecl(LC_Decl *decl);
|
|
LC_FUNCTION LC_Operand LC_CreateLocalDecl(LC_DeclKind kind, LC_Intern name, LC_AST *ast);
|
|
LC_FUNCTION LC_Decl *LC_AddConstIntDecl(char *key, int64_t value);
|
|
LC_FUNCTION LC_Decl *LC_GetBuiltin(LC_Intern name);
|
|
LC_FUNCTION void LC_AddBuiltinConstInt(char *key, int64_t value);
|
|
|
|
LC_FUNCTION void LC_RegisterDeclsFromFile(LC_AST *file);
|
|
LC_FUNCTION void LC_ResolveDeclsFromFile(LC_AST *file);
|
|
LC_FUNCTION void LC_PackageDecls(LC_AST *package);
|
|
LC_FUNCTION void LC_ResolveProcBodies(LC_AST *package);
|
|
LC_FUNCTION void LC_ResolveIncompleteTypes(LC_AST *package);
|
|
LC_FUNCTION LC_Operand LC_ResolveNote(LC_AST *n, bool is_decl);
|
|
LC_FUNCTION LC_Operand LC_ResolveProcBody(LC_Decl *decl);
|
|
LC_FUNCTION LC_ResolvedCompoItem *LC_AddResolvedCallItem(LC_ResolvedCompo *list, LC_TypeMember *t, LC_AST *comp, LC_AST *expr);
|
|
LC_FUNCTION LC_Operand LC_ResolveCompoCall(LC_AST *n, LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_ResolveCompoAggregate(LC_AST *n, LC_Type *type);
|
|
LC_FUNCTION LC_ResolvedCompoArrayItem *LC_AddResolvedCompoArrayItem(LC_ResolvedArrayCompo *arr, int index, LC_AST *comp);
|
|
LC_FUNCTION LC_Operand LC_ResolveCompoArray(LC_AST *n, LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_ResolveTypeOrExpr(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ExpectBuiltinWithOneArg(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ResolveBuiltin(LC_AST *n);
|
|
LC_FUNCTION bool LC_TryTyping(LC_AST *n, LC_Operand op);
|
|
LC_FUNCTION bool LC_TryDefaultTyping(LC_AST *n, LC_Operand *o);
|
|
LC_FUNCTION LC_Operand LC_ResolveNameInScope(LC_AST *n, LC_Decl *parent_decl);
|
|
LC_FUNCTION LC_Operand LC_ResolveExpr(LC_AST *expr);
|
|
LC_FUNCTION LC_Operand LC_ResolveExprAndPushCompoContext(LC_AST *expr, LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_ResolveExprEx(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ResolveStmtBlock(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ResolveVarDecl(LC_Decl *decl);
|
|
LC_FUNCTION LC_Operand LC_MakeSureNoDeferBlock(LC_AST *n, char *str);
|
|
LC_FUNCTION LC_Operand LC_MakeSureInsideLoopBlock(LC_AST *n, char *str);
|
|
LC_FUNCTION LC_Operand LC_MatchLabeledBlock(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ResolveStmt(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ResolveConstDecl(LC_Decl *decl);
|
|
LC_FUNCTION LC_Operand LC_ResolveName(LC_AST *pos, LC_Intern intern);
|
|
LC_FUNCTION LC_Operand LC_ResolveConstInt(LC_AST *n, LC_Type *int_type, uint64_t *out_size);
|
|
LC_FUNCTION LC_Operand LC_ResolveType(LC_AST *n);
|
|
LC_FUNCTION LC_Operand LC_ResolveBinaryExpr(LC_AST *n, LC_Operand l, LC_Operand r);
|
|
LC_FUNCTION LC_Operand LC_ResolveTypeVargs(LC_AST *pos, LC_Operand v);
|
|
LC_FUNCTION LC_Operand LC_ResolveTypeCast(LC_AST *pos, LC_Operand t, LC_Operand v);
|
|
LC_FUNCTION LC_Operand LC_ResolveTypeVarDecl(LC_AST *pos, LC_Operand t, LC_Operand v);
|
|
LC_FUNCTION LC_Operand LC_ResolveTypeAggregate(LC_AST *pos, LC_Type *type);
|
|
|
|
extern LC_Operand LC_OPNull;
|
|
LC_FUNCTION LC_Operand LC_OPError(void);
|
|
LC_FUNCTION LC_Operand LC_OPConstType(LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_OPDecl(LC_Decl *decl);
|
|
LC_FUNCTION LC_Operand LC_OPType(LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_OPLValueAndType(LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_ConstCastFloat(LC_AST *pos, LC_Operand op);
|
|
LC_FUNCTION LC_Operand LC_ConstCastInt(LC_AST *pos, LC_Operand op);
|
|
LC_FUNCTION LC_Operand LC_OPInt(int64_t v);
|
|
LC_FUNCTION LC_Operand LC_OPIntT(LC_Type *type, int64_t v);
|
|
LC_FUNCTION LC_Operand LC_OPModDefaultUT(LC_Operand val);
|
|
LC_FUNCTION LC_Operand LC_OPModType(LC_Operand op, LC_Type *type);
|
|
LC_FUNCTION LC_Operand LC_OPModBool(LC_Operand op);
|
|
LC_FUNCTION LC_Operand LC_OPModBoolV(LC_Operand op, int v);
|
|
LC_FUNCTION LC_Operand LC_EvalBinary(LC_AST *pos, LC_Operand a, LC_TokenKind op, LC_Operand b);
|
|
LC_FUNCTION LC_Operand LC_EvalUnary(LC_AST *pos, LC_TokenKind op, LC_Operand a);
|
|
LC_FUNCTION LC_OPResult LC_IsBinaryExprValidForType(LC_TokenKind op, LC_Type *type);
|
|
LC_FUNCTION LC_OPResult LC_IsUnaryOpValidForType(LC_TokenKind op, LC_Type *type);
|
|
LC_FUNCTION LC_OPResult LC_IsAssignValidForType(LC_TokenKind op, LC_Type *type);
|
|
|
|
//
|
|
// Error
|
|
//
|
|
LC_FUNCTION void LC_IgnoreMessage(LC_Token *pos, char *str, int len);
|
|
LC_FUNCTION void LC_SendErrorMessage(LC_Token *pos, LC_String s8);
|
|
LC_FUNCTION void LC_SendErrorMessagef(LC_Lex *x, LC_Token *pos, const char *str, ...);
|
|
LC_FUNCTION LC_AST *LC_ReportParseError(LC_Token *pos, const char *str, ...);
|
|
LC_FUNCTION LC_Operand LC_ReportASTError(LC_AST *n, const char *str, ...);
|
|
LC_FUNCTION LC_Operand LC_ReportASTErrorEx(LC_AST *n1, LC_AST *n2, const char *str, ...);
|
|
LC_FUNCTION void LC_HandleFatalError(void);
|
|
|
|
#define LC_ASSERT(n, cond) \
|
|
if (!(cond)) { \
|
|
LC_ReportASTError(n, "internal compiler error: assert condition failed: %s, inside of %s", #cond, __FUNCTION__); \
|
|
LC_HandleFatalError(); \
|
|
}
|
|
|
|
//
|
|
// Code generation and printing helpers
|
|
//
|
|
LC_FUNCTION LC_StringList *LC_BeginStringGen(LC_Arena *arena);
|
|
LC_FUNCTION LC_String LC_EndStringGen(LC_Arena *arena);
|
|
|
|
// clang-format off
|
|
#define LC_Genf(...) LC_Addf(L->printer.arena, &L->printer.list, __VA_ARGS__)
|
|
#define LC_GenLinef(...) do { LC_Genf("\n"); LC_GenIndent(); LC_Genf(__VA_ARGS__); } while (0)
|
|
// clang-format on
|
|
|
|
LC_FUNCTION void LC_GenIndent(void);
|
|
LC_FUNCTION void LC_GenLine(void);
|
|
LC_FUNCTION char *LC_Strf(const char *str, ...);
|
|
LC_FUNCTION char *LC_GenLCType(LC_Type *type);
|
|
LC_FUNCTION char *LC_GenLCTypeVal(LC_TypeAndVal v);
|
|
LC_FUNCTION char *LC_GenLCAggName(LC_Type *t);
|
|
LC_FUNCTION void LC_GenLCNode(LC_AST *n);
|
|
|
|
// C code generation
|
|
LC_FUNCTION void LC_GenCHeader(LC_AST *package);
|
|
LC_FUNCTION void LC_GenCImpl(LC_AST *package);
|
|
|
|
LC_FUNCTION void LC_GenCLineDirective(LC_AST *node);
|
|
LC_FUNCTION void LC_GenLastCLineDirective(void);
|
|
LC_FUNCTION void LC_GenCLineDirectiveNum(int num);
|
|
|
|
LC_FUNCTION char *LC_GenCTypeParen(char *str, char c);
|
|
LC_FUNCTION char *LC_GenCType(LC_Type *type, char *str);
|
|
LC_FUNCTION LC_Intern LC_GetStringFromSingleArgNote(LC_AST *note);
|
|
LC_FUNCTION void LC_GenCCompound(LC_AST *n);
|
|
LC_FUNCTION void LC_GenCString(char *s, LC_Type *type);
|
|
LC_FUNCTION char *LC_GenCVal(LC_TypeAndVal v, LC_Type *type);
|
|
LC_FUNCTION void LC_GenCExpr(LC_AST *n);
|
|
LC_FUNCTION void LC_GenCNote(LC_AST *note);
|
|
LC_FUNCTION void LC_GenCVarExpr(LC_AST *n, bool is_declaration);
|
|
LC_FUNCTION void LC_GenCDefers(LC_AST *block);
|
|
LC_FUNCTION void LC_GenCDefersLoopBreak(LC_AST *n);
|
|
LC_FUNCTION void LC_GenCDefersReturn(LC_AST *n);
|
|
LC_FUNCTION void LC_GenCStmt2(LC_AST *n, int flags);
|
|
LC_FUNCTION void LC_GenCStmt(LC_AST *n);
|
|
LC_FUNCTION void LC_GenCExprParen(LC_AST *expr);
|
|
LC_FUNCTION void LC_GenCStmtBlock(LC_AST *n);
|
|
LC_FUNCTION void LC_GenCProcDecl(LC_Decl *decl);
|
|
LC_FUNCTION void LC_GenCAggForwardDecl(LC_Decl *decl);
|
|
LC_FUNCTION void LC_GenCTypeDecl(LC_Decl *decl);
|
|
LC_FUNCTION void LC_GenCVarFDecl(LC_Decl *decl);
|
|
|
|
//
|
|
// Inline helpers
|
|
//
|
|
static inline bool LC_IsUTInt(LC_Type *x) { return x->kind == LC_TypeKind_UntypedInt; }
|
|
static inline bool LC_IsUTFloat(LC_Type *x) { return x->kind == LC_TypeKind_UntypedFloat; }
|
|
static inline bool LC_IsUTStr(LC_Type *x) { return x->kind == LC_TypeKind_UntypedString; }
|
|
static inline bool LC_IsUntyped(LC_Type *x) { return (x)->kind >= LC_TypeKind_UntypedInt && x->kind <= LC_TypeKind_UntypedString; }
|
|
|
|
static inline bool LC_IsNum(LC_Type *x) { return x->kind >= LC_TypeKind_char && x->kind <= LC_TypeKind_double; }
|
|
static inline bool LC_IsInt(LC_Type *x) { return (x->kind >= LC_TypeKind_char && x->kind <= LC_TypeKind_ullong) || LC_IsUTInt(x); }
|
|
static inline bool LC_IsIntLike(LC_Type *x) { return LC_IsInt(x) || x->kind == LC_TypeKind_Pointer || x->kind == LC_TypeKind_Proc; }
|
|
static inline bool LC_IsFloat(LC_Type *x) { return ((x)->kind == LC_TypeKind_float || (x->kind == LC_TypeKind_double)) || LC_IsUTFloat(x); }
|
|
static inline bool LC_IsSmallerThenInt(LC_Type *x) { return x->kind < LC_TypeKind_int; }
|
|
|
|
static inline bool LC_IsAggType(LC_Type *x) { return ((x)->kind == LC_TypeKind_Struct || (x)->kind == LC_TypeKind_Union); }
|
|
static inline bool LC_IsArray(LC_Type *x) { return (x)->kind == LC_TypeKind_Array; }
|
|
static inline bool LC_IsProc(LC_Type *x) { return (x)->kind == LC_TypeKind_Proc; }
|
|
static inline bool LC_IsVoidPtr(LC_Type *x) { return (x) == L->tpvoid; }
|
|
static inline bool LC_IsPtr(LC_Type *x) { return (x)->kind == LC_TypeKind_Pointer; }
|
|
static inline bool LC_IsPtrLike(LC_Type *x) { return (x)->kind == LC_TypeKind_Pointer || x->kind == LC_TypeKind_Proc; }
|
|
static inline bool LC_IsStr(LC_Type *x) { return x == L->tpchar || x == L->tstring; }
|
|
|
|
static inline bool LC_IsDecl(LC_AST *x) { return (x->kind >= LC_ASTKind_FirstDecl && x->kind <= LC_ASTKind_LastDecl); }
|
|
static inline bool LC_IsStmt(LC_AST *x) { return (x->kind >= LC_ASTKind_FirstStmt && x->kind <= LC_ASTKind_LastStmt); }
|
|
static inline bool LC_IsExpr(LC_AST *x) { return (x->kind >= LC_ASTKind_FirstExpr && x->kind <= LC_ASTKind_LastExpr); }
|
|
static inline bool LC_IsType(LC_AST *x) { return (x->kind >= LC_ASTKind_FirstTypespec && x->kind <= LC_ASTKind_LastTypespec); }
|
|
static inline bool LC_IsAgg(LC_AST *x) { return (x->kind == LC_ASTKind_DeclStruct || x->kind == LC_ASTKind_DeclUnion); }
|
|
|
|
// I tried removing this because I thought it's redundant
|
|
// but this reminded me that "Untyped bool" can appear from normal expressions: (a == b)
|
|
// This is required, maybe there is a way around it, not sure
|
|
static inline bool LC_IsUTConst(LC_Operand op) { return (op.flags & LC_OPF_UTConst) != 0; }
|
|
static inline bool LC_IsConst(LC_Operand op) { return (op.flags & LC_OPF_Const) != 0; }
|
|
static inline bool LC_IsLValue(LC_Operand op) { return (op.flags & LC_OPF_LValue) != 0; }
|
|
static inline bool LC_IsError(LC_Operand op) { return (op.flags & LC_OPF_Error) != 0; }
|
|
|
|
static inline LC_Type *LC_GetBase(LC_Type *x) { return (x)->tbase; }
|
|
|
|
//
|
|
// Stringifying functions
|
|
//
|
|
LC_FUNCTION const char *LC_OSToString(LC_OS os);
|
|
LC_FUNCTION const char *LC_GENToString(LC_GEN os);
|
|
LC_FUNCTION const char *LC_ARCHToString(LC_ARCH arch);
|
|
LC_FUNCTION const char *LC_ASTKindToString(LC_ASTKind kind);
|
|
LC_FUNCTION const char *LC_TypeKindToString(LC_TypeKind kind);
|
|
LC_FUNCTION const char *LC_DeclKindToString(LC_DeclKind decl_kind);
|
|
LC_FUNCTION const char *LC_TokenKindToString(LC_TokenKind token_kind);
|
|
LC_FUNCTION const char *LC_TokenKindToOperator(LC_TokenKind token_kind);
|
|
|
|
/*
|
|
The bigint code was written by Christoffer Lerno, he is the programmer
|
|
behind C3. He allowed me to use this code without any restrictions. Great guy!
|
|
You can check out C3 compiler: https://github.com/c3lang/c3c
|
|
He also writes very helpful blogs about compilers: https://c3.handmade.network/blog
|
|
*/
|
|
LC_FUNCTION LC_BigInt LC_Bigint_u64(uint64_t val);
|
|
LC_FUNCTION uint64_t *LC_Bigint_ptr(LC_BigInt *big_int);
|
|
LC_FUNCTION size_t LC_Bigint_bits_needed(LC_BigInt *big_int);
|
|
LC_FUNCTION void LC_Bigint_init_unsigned(LC_BigInt *big_int, uint64_t value);
|
|
LC_FUNCTION void LC_Bigint_init_signed(LC_BigInt *dest, int64_t value);
|
|
LC_FUNCTION void LC_Bigint_init_bigint(LC_BigInt *dest, LC_BigInt *src);
|
|
LC_FUNCTION void LC_Bigint_negate(LC_BigInt *dest, LC_BigInt *source);
|
|
LC_FUNCTION size_t LC_Bigint_clz(LC_BigInt *big_int, size_t bit_count);
|
|
LC_FUNCTION bool LC_Bigint_eql(LC_BigInt a, LC_BigInt b);
|
|
LC_FUNCTION bool LC_Bigint_fits_in_bits(LC_BigInt *big_int, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION uint64_t LC_Bigint_as_unsigned(LC_BigInt *bigint);
|
|
LC_FUNCTION void LC_Bigint_add(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_add_wrap(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION void LC_Bigint_sub(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_sub_wrap(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION void LC_Bigint_mul(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_mul_wrap(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION void LC_Bigint_unsigned_division(LC_BigInt *op1, LC_BigInt *op2, LC_BigInt *Quotient, LC_BigInt *Remainder);
|
|
LC_FUNCTION void LC_Bigint_div_trunc(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_div_floor(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_rem(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_mod(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_or(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_and(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_xor(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_shl(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_shl_int(LC_BigInt *dest, LC_BigInt *op1, uint64_t shift);
|
|
LC_FUNCTION void LC_Bigint_shl_trunc(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION void LC_Bigint_shr(LC_BigInt *dest, LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION void LC_Bigint_not(LC_BigInt *dest, LC_BigInt *op, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION void LC_Bigint_truncate(LC_BigInt *dst, LC_BigInt *op, size_t bit_count, bool is_signed);
|
|
LC_FUNCTION LC_CmpRes LC_Bigint_cmp(LC_BigInt *op1, LC_BigInt *op2);
|
|
LC_FUNCTION char *LC_Bigint_str(LC_BigInt *bigint, uint64_t base);
|
|
LC_FUNCTION int64_t LC_Bigint_as_signed(LC_BigInt *bigint);
|
|
LC_FUNCTION LC_CmpRes LC_Bigint_cmp_zero(LC_BigInt *op);
|
|
LC_FUNCTION double LC_Bigint_as_float(LC_BigInt *bigint);
|
|
|
|
//
|
|
// Unicode API
|
|
//
|
|
struct LC_UTF32Result {
|
|
uint32_t out_str;
|
|
int advance;
|
|
int error;
|
|
};
|
|
|
|
struct LC_UTF8Result {
|
|
uint8_t out_str[4];
|
|
int len;
|
|
int error;
|
|
};
|
|
|
|
struct LC_UTF16Result {
|
|
uint16_t out_str[2];
|
|
int len;
|
|
int error;
|
|
};
|
|
|
|
LC_FUNCTION LC_UTF32Result LC_ConvertUTF16ToUTF32(uint16_t *c, int max_advance);
|
|
LC_FUNCTION LC_UTF8Result LC_ConvertUTF32ToUTF8(uint32_t codepoint);
|
|
LC_FUNCTION LC_UTF32Result LC_ConvertUTF8ToUTF32(char *c, int max_advance);
|
|
LC_FUNCTION LC_UTF16Result LC_ConvertUTF32ToUTF16(uint32_t codepoint);
|
|
LC_FUNCTION int64_t LC_CreateCharFromWidechar(char *buffer, int64_t buffer_size, wchar_t *in, int64_t inlen);
|
|
LC_FUNCTION int64_t LC_CreateWidecharFromChar(wchar_t *buffer, int64_t buffer_size, char *in, int64_t inlen);
|
|
|
|
//
|
|
// Filesystem API
|
|
//
|
|
LC_FUNCTION bool LC_IsDir(LC_Arena *temp, LC_String path);
|
|
LC_FUNCTION LC_String LC_GetAbsolutePath(LC_Arena *arena, LC_String relative);
|
|
LC_FUNCTION bool LC_EnableTerminalColors(void);
|
|
LC_FUNCTION LC_String LC_ReadFile(LC_Arena *arena, LC_String path);
|
|
|
|
LC_FUNCTION bool LC_IsValid(LC_FileIter it);
|
|
LC_FUNCTION void LC_Advance(LC_FileIter *it);
|
|
LC_FUNCTION LC_FileIter LC_IterateFiles(LC_Arena *scratch_arena, LC_String path);
|
|
|
|
//
|
|
// Arena API
|
|
//
|
|
#define LC_PushSize(a, size) LC__PushSize(a, size)
|
|
#define LC_PushSizeNonZeroed(a, size) LC__PushSizeNonZeroed(a, size)
|
|
|
|
#define LC_PushArrayNonZeroed(a, T, c) (T *)LC__PushSizeNonZeroed(a, sizeof(T) * (c))
|
|
#define LC_PushStructNonZeroed(a, T) (T *)LC__PushSizeNonZeroed(a, sizeof(T))
|
|
#define LC_PushStruct(a, T) (T *)LC__PushSize(a, sizeof(T))
|
|
#define LC_PushArray(a, T, c) (T *)LC__PushSize(a, sizeof(T) * (c))
|
|
|
|
#define LC_Assertf(cond, ...) LC_ASSERT(NULL, cond)
|
|
|
|
#ifndef LC_USE_CUSTOM_ARENA
|
|
LC_FUNCTION void LC_InitArenaEx(LC_Arena *a, size_t reserve);
|
|
LC_FUNCTION void LC_InitArena(LC_Arena *a);
|
|
LC_FUNCTION void LC_InitArenaFromBuffer(LC_Arena *arena, void *buffer, size_t size);
|
|
LC_FUNCTION LC_Arena *LC_BootstrapArena(void);
|
|
LC_FUNCTION LC_Arena LC_PushArena(LC_Arena *arena, size_t size);
|
|
LC_FUNCTION LC_Arena *LC_PushArenaP(LC_Arena *arena, size_t size);
|
|
|
|
LC_FUNCTION void *LC__PushSizeNonZeroed(LC_Arena *a, size_t size);
|
|
LC_FUNCTION void *LC__PushSize(LC_Arena *arena, size_t size);
|
|
LC_FUNCTION LC_TempArena LC_BeginTemp(LC_Arena *arena);
|
|
LC_FUNCTION void LC_EndTemp(LC_TempArena checkpoint);
|
|
|
|
LC_FUNCTION void LC_PopToPos(LC_Arena *arena, size_t pos);
|
|
LC_FUNCTION void LC_PopSize(LC_Arena *arena, size_t size);
|
|
LC_FUNCTION void LC_DeallocateArena(LC_Arena *arena);
|
|
LC_FUNCTION void LC_ResetArena(LC_Arena *arena);
|
|
|
|
LC_FUNCTION LC_VMemory LC_VReserve(size_t size);
|
|
LC_FUNCTION bool LC_VCommit(LC_VMemory *m, size_t commit);
|
|
LC_FUNCTION void LC_VDeallocate(LC_VMemory *m);
|
|
LC_FUNCTION bool LC_VDecommitPos(LC_VMemory *m, size_t pos);
|
|
#endif // LC_USE_CUSTOM_ARENA
|
|
|
|
LC_FUNCTION size_t LC_GetAlignOffset(size_t size, size_t align);
|
|
LC_FUNCTION size_t LC_AlignUp(size_t size, size_t align);
|
|
LC_FUNCTION size_t LC_AlignDown(size_t size, size_t align);
|
|
|
|
#define LC_IS_POW2(x) (((x) & ((x)-1)) == 0)
|
|
#define LC_MIN(x, y) ((x) <= (y) ? (x) : (y))
|
|
#define LC_MAX(x, y) ((x) >= (y) ? (x) : (y))
|
|
#define LC_StrLenof(x) ((int64_t)((sizeof(x) / sizeof((x)[0]))))
|
|
|
|
#define LC_CLAMP_TOP(x, max) ((x) >= (max) ? (max) : (x))
|
|
#define LC_CLAMP_BOT(x, min) ((x) <= (min) ? (min) : (x))
|
|
#define LC_CLAMP(x, min, max) ((x) >= (max) ? (max) : (x) <= (min) ? (min) \
|
|
: (x))
|
|
#define LC_KIB(x) ((x##ull) * 1024ull)
|
|
#define LC_MIB(x) (LC_KIB(x) * 1024ull)
|
|
#define LC_GIB(x) (LC_MIB(x) * 1024ull)
|
|
#define LC_TIB(x) (LC_GIB(x) * 1024ull)
|
|
|
|
//
|
|
// String API
|
|
//
|
|
|
|
typedef int LC_FindFlag;
|
|
enum {
|
|
LC_FindFlag_None = 0,
|
|
LC_FindFlag_IgnoreCase = 1,
|
|
LC_FindFlag_MatchFindLast = 2,
|
|
};
|
|
|
|
typedef int LC_SplitFlag;
|
|
enum {
|
|
LC_SplitFlag_None = 0,
|
|
LC_SplitFlag_IgnoreCase = 1,
|
|
LC_SplitFlag_SplitInclusive = 2,
|
|
};
|
|
|
|
static const bool LC_IgnoreCase = true;
|
|
|
|
#if defined(__has_attribute)
|
|
#if __has_attribute(format)
|
|
#define LC__PrintfFormat(fmt, va) __attribute__((format(printf, fmt, va)))
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef LC__PrintfFormat
|
|
#define LC__PrintfFormat(fmt, va)
|
|
#endif
|
|
|
|
#define LC_Lit(string) LC_MakeString((char *)string, sizeof(string) - 1)
|
|
#define LC_Expand(string) (int)(string).len, (string).str
|
|
|
|
#define LC_FORMAT(allocator, str, result) \
|
|
va_list args1; \
|
|
va_start(args1, str); \
|
|
LC_String result = LC_FormatV(allocator, str, args1); \
|
|
va_end(args1)
|
|
|
|
#ifdef __cplusplus
|
|
#define LC_IF_CPP(x) x
|
|
#else
|
|
#define LC_IF_CPP(x)
|
|
#endif
|
|
|
|
LC_FUNCTION char LC_ToLowerCase(char a);
|
|
LC_FUNCTION char LC_ToUpperCase(char a);
|
|
LC_FUNCTION bool LC_IsWhitespace(char w);
|
|
LC_FUNCTION bool LC_IsAlphabetic(char a);
|
|
LC_FUNCTION bool LC_IsIdent(char a);
|
|
LC_FUNCTION bool LC_IsDigit(char a);
|
|
LC_FUNCTION bool LC_IsAlphanumeric(char a);
|
|
|
|
LC_FUNCTION int64_t LC_StrLen(char *string);
|
|
LC_FUNCTION bool LC_AreEqual(LC_String a, LC_String b, unsigned ignore_case LC_IF_CPP(= false));
|
|
LC_FUNCTION bool LC_EndsWith(LC_String a, LC_String end, unsigned ignore_case LC_IF_CPP(= false));
|
|
LC_FUNCTION bool LC_StartsWith(LC_String a, LC_String start, unsigned ignore_case LC_IF_CPP(= false));
|
|
LC_FUNCTION LC_String LC_MakeString(char *str, int64_t len);
|
|
LC_FUNCTION LC_String LC_CopyString(LC_Arena *allocator, LC_String string);
|
|
LC_FUNCTION LC_String LC_CopyChar(LC_Arena *allocator, char *s);
|
|
LC_FUNCTION LC_String LC_NormalizePath(LC_Arena *allocator, LC_String s);
|
|
LC_FUNCTION void LC_NormalizePathUnsafe(LC_String s); // make sure there is no way string is const etc.
|
|
LC_FUNCTION LC_String LC_Chop(LC_String string, int64_t len);
|
|
LC_FUNCTION LC_String LC_Skip(LC_String string, int64_t len);
|
|
LC_FUNCTION LC_String LC_GetPostfix(LC_String string, int64_t len);
|
|
LC_FUNCTION LC_String LC_GetPrefix(LC_String string, int64_t len);
|
|
LC_FUNCTION bool LC_Seek(LC_String string, LC_String find, LC_FindFlag flags LC_IF_CPP(= LC_FindFlag_None), int64_t *index_out LC_IF_CPP(= 0));
|
|
LC_FUNCTION int64_t LC_Find(LC_String string, LC_String find, LC_FindFlag flags LC_IF_CPP(= LC_FindFlag_None));
|
|
LC_FUNCTION LC_String LC_ChopLastSlash(LC_String s);
|
|
LC_FUNCTION LC_String LC_ChopLastPeriod(LC_String s);
|
|
LC_FUNCTION LC_String LC_SkipToLastSlash(LC_String s);
|
|
LC_FUNCTION LC_String LC_SkipToLastPeriod(LC_String s);
|
|
LC_FUNCTION LC_String LC_GetNameNoExt(LC_String s);
|
|
LC_FUNCTION LC_String LC_MakeFromChar(char *string);
|
|
LC_FUNCTION LC_String LC_MakeEmptyString(void);
|
|
LC_FUNCTION LC_StringList LC_MakeEmptyList(void);
|
|
LC_FUNCTION LC_String LC_FormatV(LC_Arena *allocator, const char *str, va_list args1);
|
|
LC_FUNCTION LC_String LC_Format(LC_Arena *allocator, const char *str, ...) LC__PrintfFormat(2, 3);
|
|
|
|
LC_FUNCTION LC_StringList LC_Split(LC_Arena *allocator, LC_String string, LC_String find, LC_SplitFlag flags LC_IF_CPP(= LC_SplitFlag_None));
|
|
LC_FUNCTION LC_String LC_MergeWithSeparator(LC_Arena *allocator, LC_StringList list, LC_String separator LC_IF_CPP(= LC_Lit(" ")));
|
|
LC_FUNCTION LC_String LC_MergeString(LC_Arena *allocator, LC_StringList list);
|
|
|
|
LC_FUNCTION LC_StringNode *LC_CreateNode(LC_Arena *allocator, LC_String string);
|
|
LC_FUNCTION void LC_ReplaceNodeString(LC_StringList *list, LC_StringNode *node, LC_String new_string);
|
|
LC_FUNCTION void LC_AddExistingNode(LC_StringList *list, LC_StringNode *node);
|
|
LC_FUNCTION void LC_AddArray(LC_Arena *allocator, LC_StringList *list, char **array, int count);
|
|
LC_FUNCTION void LC_AddArrayWithPrefix(LC_Arena *allocator, LC_StringList *list, char *prefix, char **array, int count);
|
|
LC_FUNCTION LC_StringList LC_MakeList(LC_Arena *allocator, LC_String a);
|
|
LC_FUNCTION LC_StringList LC_CopyList(LC_Arena *allocator, LC_StringList a);
|
|
LC_FUNCTION LC_StringList LC_ConcatLists(LC_Arena *allocator, LC_StringList a, LC_StringList b);
|
|
LC_FUNCTION LC_StringNode *LC_AddNode(LC_Arena *allocator, LC_StringList *list, LC_String string);
|
|
LC_FUNCTION LC_StringNode *LC_Add(LC_Arena *allocator, LC_StringList *list, LC_String string);
|
|
LC_FUNCTION LC_String LC_Addf(LC_Arena *allocator, LC_StringList *list, const char *str, ...) LC__PrintfFormat(3, 4);
|
|
|
|
LC_FUNCTION wchar_t *LC_ToWidechar(LC_Arena *allocator, LC_String string);
|
|
|
|
//
|
|
// Linked list API
|
|
//
|
|
#define LC_SLLAddMod(f, l, n, next) \
|
|
do { \
|
|
(n)->next = 0; \
|
|
if ((f) == 0) { \
|
|
(f) = (l) = (n); \
|
|
} else { \
|
|
(l) = (l)->next = (n); \
|
|
} \
|
|
} while (0)
|
|
#define LC_AddSLL(f, l, n) LC_SLLAddMod(f, l, n, next)
|
|
|
|
#define LC_SLLPopFirstMod(f, l, next) \
|
|
do { \
|
|
if ((f) == (l)) { \
|
|
(f) = (l) = 0; \
|
|
} else { \
|
|
(f) = (f)->next; \
|
|
} \
|
|
} while (0)
|
|
#define LC_SLLPopFirst(f, l) LC_SLLPopFirstMod(f, l, next)
|
|
|
|
#define LC_SLLStackAddMod(stack_base, new_stack_base, next) \
|
|
do { \
|
|
(new_stack_base)->next = (stack_base); \
|
|
(stack_base) = (new_stack_base); \
|
|
} while (0)
|
|
|
|
#define LC_DLLAddMod(f, l, node, next, prev) \
|
|
do { \
|
|
if ((f) == 0) { \
|
|
(f) = (l) = (node); \
|
|
(node)->prev = 0; \
|
|
(node)->next = 0; \
|
|
} else { \
|
|
(l)->next = (node); \
|
|
(node)->prev = (l); \
|
|
(node)->next = 0; \
|
|
(l) = (node); \
|
|
} \
|
|
} while (0)
|
|
#define LC_DLLAdd(f, l, node) LC_DLLAddMod(f, l, node, next, prev)
|
|
#define LC_DLLAddFront(f, l, node) LC_DLLAddMod(l, f, node, prev, next)
|
|
#define LC_DLLRemoveMod(first, last, node, next, prev) \
|
|
do { \
|
|
if ((first) == (last)) { \
|
|
(first) = (last) = 0; \
|
|
} else if ((last) == (node)) { \
|
|
(last) = (last)->prev; \
|
|
(last)->next = 0; \
|
|
} else if ((first) == (node)) { \
|
|
(first) = (first)->next; \
|
|
(first)->prev = 0; \
|
|
} else { \
|
|
(node)->prev->next = (node)->next; \
|
|
(node)->next->prev = (node)->prev; \
|
|
} \
|
|
} while (0)
|
|
#define LC_DLLRemove(first, last, node) LC_DLLRemoveMod(first, last, node, next, prev)
|
|
|
|
#define LC_ASTFor(it, x) for (LC_AST *it = x; it; it = it->next)
|
|
#define LC_DeclFor(it, x) for (LC_Decl *it = x; it; it = it->next)
|
|
#define LC_TypeFor(it, x) for (LC_TypeMember *it = x; it; it = it->next)
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
#define LC_OPERATING_SYSTEM_MAC 1
|
|
#define LC_OPERATING_SYSTEM_UNIX 1
|
|
#elif defined(_WIN32)
|
|
#define LC_OPERATING_SYSTEM_WINDOWS 1
|
|
#elif defined(__linux__)
|
|
#define LC_OPERATING_SYSTEM_UNIX 1
|
|
#define LC_OPERATING_SYSTEM_LINUX 1
|
|
#endif
|
|
|
|
#ifndef LC_OPERATING_SYSTEM_MAC
|
|
#define LC_OPERATING_SYSTEM_MAC 0
|
|
#endif
|
|
|
|
#ifndef LC_OPERATING_SYSTEM_UNIX
|
|
#define LC_OPERATING_SYSTEM_UNIX 0
|
|
#endif
|
|
|
|
#ifndef LC_OPERATING_SYSTEM_WINDOWS
|
|
#define LC_OPERATING_SYSTEM_WINDOWS 0
|
|
#endif
|
|
|
|
#ifndef LC_OPERATING_SYSTEM_LINUX
|
|
#define LC_OPERATING_SYSTEM_LINUX 0
|
|
#endif
|
|
|
|
#endif |