Files
corelang/core_compiler_interface.hpp
2023-04-22 13:28:21 +02:00

680 lines
14 KiB
C++

#pragma once
#include <stdint.h>
struct Ast;
struct Ast_Scope;
struct Ast_Decl;
struct Ast_File_Namespace;
struct Ast_File;
struct Ast_Module;
struct Ast_Lambda;
struct Ast_Type;
struct Ast_Expr;
#ifndef CORE_BASE
#define CORE_BASE
struct Allocator {
typedef void *Allocate(Allocator *, size_t);
typedef void Deallocate(Allocator *, void *p);
Allocate *allocate;
Deallocate *deallocate;
};
struct String {
uint8_t *str;
int64_t len;
};
typedef String Intern_String;
template <class T>
struct Array {
void *allocator;
T *data;
int64_t cap;
int64_t len;
};
template <class T>
struct List_Node {
List_Node<T> *next;
List_Node<T> *prev;
int cap;
int len;
T data[];
};
template <class T>
struct List {
int block_size = 0;
int allocation_multiplier = 0;
List_Node<T> *first = 0;
List_Node<T> *last = 0;
List_Node<T> *first_free = 0;
};
#endif
enum Token_Kind {
TK_End,
/*#
import meta
for i in meta.token_kinds:
print(" TK_" + i[0] + ",")
*/
TK_Mul,
TK_Div,
TK_Mod,
TK_LeftShift,
TK_RightShift,
TK_FirstMul = TK_Mul,
TK_LastMul = TK_RightShift,
TK_Add,
TK_Sub,
TK_FirstAdd = TK_Add,
TK_LastAdd = TK_Sub,
TK_Equals,
TK_LesserThenOrEqual,
TK_GreaterThenOrEqual,
TK_LesserThen,
TK_GreaterThen,
TK_NotEquals,
TK_FirstCompare = TK_Equals,
TK_LastCompare = TK_NotEquals,
TK_BitAnd,
TK_BitOr,
TK_BitXor,
TK_And,
TK_Or,
TK_FirstLogical = TK_BitAnd,
TK_LastLogical = TK_Or,
TK_Neg,
TK_Not,
TK_Decrement,
TK_Increment,
TK_PostDecrement,
TK_PostIncrement,
TK_Assign,
TK_ColonAssign,
TK_DivAssign,
TK_MulAssign,
TK_ModAssign,
TK_SubAssign,
TK_AddAssign,
TK_AndAssign,
TK_OrAssign,
TK_XorAssign,
TK_LeftShiftAssign,
TK_RightShiftAssign,
TK_FirstAssign = TK_Assign,
TK_LastAssign = TK_RightShiftAssign,
TK_OpenParen,
TK_CloseParen,
TK_OpenBrace,
TK_CloseBrace,
TK_OpenBracket,
TK_CloseBracket,
TK_Comma,
TK_Pound,
TK_Question,
TK_ThreeDots,
TK_Semicolon,
TK_Dot,
TK_TwoDots,
TK_NewLine,
TK_Colon,
TK_DoubleColon,
TK_At,
TK_Arrow,
TK_Polymorph,
TK_ExprSizeof,
TK_DocComment,
TK_Comment,
TK_Identifier,
TK_UnicodeLit,
TK_StringLit,
TK_Error,
TK_Float,
TK_Integer,
TK_Keyword,
/*END*/
TK_Pointer = TK_Mul,
TK_Dereference = TK_BitAnd,
OPEN_SCOPE = 128,
CLOSE_SCOPE,
SAME_SCOPE,
};
struct BigInt {
unsigned digit_count;
bool is_negative;
union {
uint64_t digit;
uint64_t *digits;
};
};
struct Token {
Token_Kind kind;
uint32_t di; // debug_id
union {
String string;
struct {
uint8_t *str;
int64_t len;
};
};
union {
uint32_t unicode;
BigInt int_val;
double f64_val;
String error_val;
Intern_String intern_val;
int64_t indent;
};
Intern_String file;
int32_t line;
uint8_t *line_begin;
};
enum Ast_Type_Kind {
TYPE_NONE,
TYPE_S64, // FIRST_NUMERIC is_int start
TYPE_S32,
TYPE_S16,
TYPE_S8,
TYPE_INT,
TYPE_UINT,
TYPE_LONG,
TYPE_ULONG,
TYPE_LLONG,
TYPE_ULLONG,
TYPE_SHORT,
TYPE_USHORT,
TYPE_CHAR,
TYPE_UCHAR,
TYPE_U64,
TYPE_U32,
TYPE_U16,
TYPE_U8, // is_int end
TYPE_F32,
TYPE_F64,
TYPE_POINTER,
TYPE_BOOL, // LAST_NUMERIC
TYPE_STRING,
TYPE_VOID,
TYPE_ARRAY,
TYPE_LAMBDA,
TYPE_STRUCT,
TYPE_UNION,
TYPE_ENUM,
TYPE_TYPE,
TYPE_SLICE,
TYPE_COMPLETING,
TYPE_INCOMPLETE,
TYPE_POLYMORPH,
TYPE_VARGS,
TYPE_UNTYPED_BOOL, // FIRST_TYPED_NUMERIC, FIRST_NUMERIC
TYPE_UNTYPED_INT,
TYPE_UNTYPED_FLOAT, // LAST_TYPED_NUMERIC
TYPE_UNTYPED_STRING,
TYPE_UNTYPED_FIRST = TYPE_UNTYPED_BOOL,
TYPE_UNTYPED_LAST = TYPE_UNTYPED_STRING,
TYPE_UNTYPED_FIRST_NUMERIC = TYPE_UNTYPED_BOOL,
TYPE_UNTYPED_LAST_NUMERIC = TYPE_UNTYPED_FLOAT,
TYPE_FIRST_NUMERIC = TYPE_S64,
TYPE_LAST_NUMERIC = TYPE_BOOL,
};
struct Value {
/*#import meta
print(meta.value_struct_content)
*/
Ast_Type *type;
Ast_Decl *resolved_decl;
union {
bool bool_val;
double f64_val;
Intern_String intern_val;
BigInt big_int_val;
Ast_Type *type_val;
};
/*END*/
};
struct Ast_Resolved_Member {
Intern_String name;
int32_t offset;
bool visited;
/*#import meta
meta.inline_value_fields()
*/
union {
Value value;
struct {
Ast_Type *type;
Ast_Decl *resolved_decl;
union {
bool bool_val;
double f64_val;
Intern_String intern_val;
BigInt big_int_val;
Ast_Type *type_val;
};
};
};
/*END*/
};
struct Ast_Type {
Ast_Type_Kind kind;
int32_t size;
int32_t align;
int32_t is_unsigned;
int32_t type_id;
int32_t padding;
Ast *ast;
union {
Ast_Type *base;
struct {
Ast_Type *base;
int32_t size;
// @note: if you have array with size "[32]"
// you still want to pass that array into
// a function that expects an array of size "[]"
// so we want also should check this
uint64_t slice_hash;
} arr;
struct {
Array<Ast_Resolved_Member> members;
} agg;
struct {
Ast_Type *ret;
Array<Ast_Type *> args;
uint64_t hash_without_ret;
} func;
};
};
enum Ast_Kind : uint32_t {
AST_NONE,
AST_NAMESPACE,
AST_MODULE,
AST_FILE,
AST_SCOPE,
AST_VALUE,
AST_IDENT,
AST_INDEX,
AST_UNARY,
AST_BINARY,
AST_CALL_ITEM,
AST_CALL,
AST_CONSTANT_ASSERT,
AST_RUNTIME_ASSERT,
AST_SIZE_OF,
AST_LENGTH_OF,
AST_ALIGN_OF,
AST_TYPE_OF,
AST_VARGS_LAMBDA_PARAM,
AST_LABEL,
AST_SWITCH,
AST_SWITCH_CASE,
AST_VAR_UNPACK,
AST_BREAK,
AST_COMPILER_BREAKPOINT_STMT,
AST_CONTINUE,
AST_COMPOUND,
AST_TYPE,
AST_VAR,
AST_CONST,
AST_ARRAY,
AST_FOR,
AST_IF,
AST_IF_NODE,
AST_RETURN,
AST_PASS,
AST_LAMBDA,
AST_LAMBDA_EXPR,
AST_ENUM,
AST_STRUCT,
AST_UNION,
};
typedef uint32_t Ast_Flag;
enum {
AST_EXPR = 1 << 1,
AST_STMT = 1 << 2,
AST_STRICT = 1 << 3,
AST_AGGREGATE = 1 << 4,
AST_AGGREGATE_CHILD = 1 << 5,
AST_ATOM = 1 << 7,
AST_FOREIGN = 1 << 8,
AST_DECL = 1 << 9,
AST_GLOBAL = 1 << 10,
AST_FLAG = 1 << 11,
AST_VAR_IS_CONST = 1 << 12,
AST_OPERATOR_OVERLOAD = 1 << 13,
AST_IS_LVALUE = 1 << 14,
AST_IDENT_POLYMORPH = 1 << 15,
AST_TYPE_POLYMORPH = 1 << 16,
AST_POLYMORPH = AST_IDENT_POLYMORPH | AST_TYPE_POLYMORPH,
AST_PARENT_POLYMORPH = 1 << 17,
AST_POLYMORPH_INSTANCE = 1 << 18,
AST_TYPESPEC = 1 << 19,
AST_COMPILER_BREAKPOINT = 1 << 20,
};
struct Ast {
uint64_t di; // Debug id, shouldn't ever be used in the program
Token *pos;
Ast_Kind kind;
uint32_t visit_id;
Ast_Scope *parent_scope;
Ast_Flag flags;
};
struct Ast_Expr : Ast {
Ast_Type *resolved_type;
Ast_Decl *resolved_operator_overload;
union {
Ast_Type *index_original_type;
Ast_Type *cast_after_type;
Ast_Type *dot_access_step_resolution;
};
};
struct Ast_Atom : Ast_Expr {
// We have a field type here
// it has a different purpose from the
// resolved_type of Ast_Expr, it describes
// the inherent type of a value
//
// resolved_type is a solid type that
// can be use during code generation
// it cannot be untyped. (or at least thats the hope :)
/*#import meta
meta.inline_value_fields()
*/
union {
Value value;
struct {
Ast_Type *type;
Ast_Decl *resolved_decl;
union {
bool bool_val;
double f64_val;
Intern_String intern_val;
BigInt big_int_val;
Ast_Type *type_val;
};
};
};
/*END*/
};
typedef uint32_t Ast_Call_Item_Flag;
enum {
CALL_INDEX = 1ull << 1,
CALL_NAME = 1ull << 2,
};
struct Ast_Call_Item : Ast_Expr {
Ast_Call_Item_Flag call_flags;
int32_t resolved_index; // This is probably for compound array
Ast_Expr *item;
union {
Ast_Atom *name;
Ast_Expr *index;
};
Intern_String resolved_name; // This is probably for compound struct
};
struct Ast_Call : Ast_Expr {
union {
Ast_Expr *name;
Ast_Expr *typespec;
};
Array<Ast_Call_Item *> exprs;
Ast_Decl *resolved_decl;
};
struct Ast_Var_Unpack : Ast_Expr {
Array<Ast_Decl *> vars;
Ast_Expr *expr;
};
struct Ast_Unary : Ast_Expr {
Token_Kind op;
Ast_Expr *expr;
uint64_t padding[2]; // For folding constants into atoms
};
struct Ast_Index : Ast_Expr {
Ast_Expr *expr;
Ast_Expr *index;
};
struct Ast_Binary : Ast_Expr {
Token_Kind op;
Ast_Expr *left;
Ast_Expr *right;
Ast_Type *before_type;
};
struct Ast_Builtin : Ast_Expr {
Ast_Expr *expr;
Intern_String assert_message;
uint64_t padding[1]; // For folding constants into atoms
};
// Problem: We are parsing out of order, in the middle of parsing a function
// we can jump down a different function, we cant therfore use global map.
// Because it would have symbols from previous function we were in middle of resolving.
//
// On top of that in the future we want a way to inject scopes, for convenience.
// Each scope needs to have it's checked locals list. To lookup syms we need to
// look into global scope and to the locals list.
//
//
// This seems slow though, would be nice to have a simpler scheme that's more flat.
// Would be nice to just reuse single map while resolving that would keep track of which
// function we are resolving.
//
// Also would be nice to have a more flat module scheme. The Ion approach seemed
// very straight forward when I looked at it. It used a single locals list with
// an index that signified from where we should consider declarations. Not really
// sure how the packages worked though.
//
// The idea that you have a flat list of packages, each package has a flat list of declarations.
// Seems nice.
//
struct Ast_Return : Ast {
Ast_Type *resolved_type;
Ast_Expr *expr;
};
struct Ast_If_Node : Ast {
Ast_Expr *expr;
Ast_Scope *scope;
Ast_Binary *init;
};
struct Ast_If : Ast {
Array<Ast_If_Node *> ifs;
};
// @todo: Ast_Simple_Stmt
#define Ast_Pass Ast
#define Ast_Break Ast
struct Ast_For : Ast {
Ast_Expr *init;
Ast_Expr *cond;
Ast_Expr *iter;
Ast_Scope *scope;
Ast_Decl *array_traversal_var;
bool is_array_traversal;
bool is_also_slice_traversal;
};
struct Ast_Lambda : Ast_Expr {
Array<Ast_Decl *> args;
Ast_Expr *ret;
Ast_Scope *scope;
};
struct Ast_Array : Ast_Expr {
Ast_Expr *base;
Ast_Expr *expr;
uint64_t padding[2];
};
struct Ast_Switch_Case : Ast {
Array<Ast_Expr *> labels;
Ast_Scope *scope;
bool fallthrough;
};
struct Ast_Switch : Ast {
Ast_Expr *value;
Array<Ast_Switch_Case *> cases;
Ast_Scope *default_scope;
};
struct Ast_Scope : Ast {
String debug_name; // Only for debug purposes, dont depend on it
Intern_String first_namespace_name;
List<Ast_Scope *> implicit_imports;
List<Ast_Decl *> decls;
Array<Ast *> stmts;
uint32_t scope_id;
Ast_Scope *file; // Self referential for file and module
Ast_Module *module;
union {
Ast *parent_ast; // @language_todo: add parent decl
Ast_Decl *parent_decl;
};
};
enum Ast_Module_State {
MODULE_REGISTERED,
MODULE_PARSED,
MODULE_RESOLVED,
};
struct Ast_Module : Ast_Scope {
Ast_Module_State state;
String absolute_base_folder;
String absolute_file_path;
List<Ast_File *> all_loaded_files;
};
struct Ast_File : Ast_Scope {
String absolute_base_folder;
String absolute_file_path;
String filecontent;
};
enum Ast_Decl_State {
DECL_NOT_RESOLVED,
DECL_RESOLVED,
DECL_RESOLVED_TYPE,
DECL_RESOLVING,
};
struct Ast_Operator_Info {
Intern_String op;
String name;
Token_Kind op_kind;
bool valid_binary_expr;
bool valid_unary_expr;
};
struct Ast_Decl : Ast {
Ast_Decl_State state;
Intern_String name;
Intern_String unique_name; // For code generation, currently only present on lambdas
// @todo: Move this to Ast_Operator_Overload
uint64_t operator_overload_arguments_hash;
Ast_Operator_Info *overload_op_info;
// @todo: move this to Ast_Poly
uint64_t polymorph_hash;
Array<Ast_Type *> polymorph_resolved_parameter_types;
Array<Ast_Decl *> polymorph_parameters;
Array<Ast_Decl *> polymorphs; // instantiated polymorphs
Ast_Scope *scope;
Ast_Expr *typespec;
union {
Ast_Expr *expr;
Ast_Lambda *lambda;
};
/*#import meta
meta.inline_value_fields()
*/
union {
Value value;
struct {
Ast_Type *type;
Ast_Decl *resolved_decl;
union {
bool bool_val;
double f64_val;
Intern_String intern_val;
BigInt big_int_val;
Ast_Type *type_val;
};
};
};
/*END*/
};
struct Ast_Label : Ast_Decl {
bool enable_goto;
};
enum Core_Message_Kind {
CORE_ERROR,
CORE_WARNING,
CORE_TRACE,
};
struct Core_Message {
Core_Message *next;
Core_Message_Kind kind;
String string;
Token *tokens[2];
int trace_line;
char *trace_file;
};