mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
&&temp operator. Macro evaluation.
This commit is contained in:
committed by
Christoffer Lerno
parent
8680ce0684
commit
4222f2731e
@@ -4,60 +4,15 @@ import bar;
|
||||
struct Foo
|
||||
{
|
||||
int x;
|
||||
long z;
|
||||
int y;
|
||||
struct fe
|
||||
{
|
||||
int dd;
|
||||
int ee;
|
||||
}
|
||||
}
|
||||
struct Bar
|
||||
{
|
||||
int[1024] x;
|
||||
int y;
|
||||
}
|
||||
|
||||
public func Bar barCopy(Bar *bar)
|
||||
{
|
||||
Bar copy = *bar;
|
||||
copy.x[0] = copy.y;
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
||||
//define bar::blub(Foo, 1) as fooblub;
|
||||
|
||||
extern func int blurbi();
|
||||
extern func int oefk(int i);
|
||||
|
||||
public func void main()
|
||||
{
|
||||
Foo f = {};
|
||||
usize x = Foo.sizeof;
|
||||
usize y = int.sizeof;
|
||||
usize z = int.alignof;
|
||||
usize w = Foo.alignof;
|
||||
typeid t = Foo.x.typeid;
|
||||
typeid aa = Foo.typeid;
|
||||
typeid bb = int.typeid;
|
||||
typeid cc = Foo.fe.typeid;
|
||||
typeid dd = Foo.fe.dd.typeid;
|
||||
char* str = Foo.nameof;
|
||||
char* str2 = int.nameof;
|
||||
char* str3 = Foo.qnameof;
|
||||
char* str4 = int.qnameof;
|
||||
char* foo = (int*).nameof;
|
||||
int blurb = void;
|
||||
Foo foek = { x = blurbi() };
|
||||
Foo floed = void;
|
||||
if (foek.x != 2)
|
||||
{
|
||||
oefk(floed.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
oefk(foek.x);
|
||||
}
|
||||
//int fe = Foo.x.offsetof;
|
||||
// usize vv = Foo.x.offsetof;
|
||||
// f = fooblud(f);
|
||||
Foo f = { 3, 4 };
|
||||
//Foo g = fooblub(&f);
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
module bar;
|
||||
|
||||
struct Type { int x; }
|
||||
module bar(Type, i);
|
||||
|
||||
public func Type blub(Type type)
|
||||
{
|
||||
int i = 0;
|
||||
type.x = i;
|
||||
return type;
|
||||
}
|
||||
@@ -115,8 +115,6 @@ const char *decl_var_to_string(VarDeclKind kind)
|
||||
{
|
||||
case VARDECL_CONST:
|
||||
return "const";
|
||||
case VARDECL_CONST_CT:
|
||||
return "$const";
|
||||
case VARDECL_GLOBAL:
|
||||
return "global";
|
||||
case VARDECL_LOCAL:
|
||||
@@ -127,6 +125,14 @@ const char *decl_var_to_string(VarDeclKind kind)
|
||||
return "param";
|
||||
case VARDECL_ALIAS:
|
||||
return "alias";
|
||||
case VARDECL_PARAM_CT:
|
||||
return "$param";
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
return "$Param";
|
||||
case VARDECL_PARAM_EXPR:
|
||||
return "#param";
|
||||
case VARDECL_PARAM_REF:
|
||||
return "¶m";
|
||||
case VARDECL_LOCAL_CT:
|
||||
return "$local";
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
@@ -222,6 +228,7 @@ BinaryOp binaryop_assign_base_op(BinaryOp assign_binary_op)
|
||||
UnaryOp unary_op[TOKEN_LAST + 1] = {
|
||||
[TOKEN_STAR] = UNARYOP_DEREF,
|
||||
[TOKEN_AMP] = UNARYOP_ADDR,
|
||||
[TOKEN_AND] = UNARYOP_TADDR,
|
||||
[TOKEN_BIT_NOT] = UNARYOP_BITNEG,
|
||||
[TOKEN_BANG] = UNARYOP_NOT,
|
||||
[TOKEN_MINUS] = UNARYOP_NEG,
|
||||
@@ -495,9 +502,15 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent)
|
||||
if (!expr) return;
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_MEMBER_ACCESS:
|
||||
DUMP("(member access)");
|
||||
return;
|
||||
case EXPR_UNDEF:
|
||||
DUMP("(undef)");
|
||||
return;
|
||||
case EXPR_ENUM_CONSTANT:
|
||||
DUMP("(enumconstant)");
|
||||
return;
|
||||
case EXPR_TYPEINFO:
|
||||
TODO;
|
||||
case EXPR_SLICE_ASSIGN:
|
||||
@@ -520,15 +533,24 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent)
|
||||
DUMPEXPC(expr);
|
||||
DUMPEXPR(expr->failable_expr);
|
||||
DUMPEND();
|
||||
case EXPR_MACRO_IDENTIFIER:
|
||||
DUMPF("(ident @%s", expr->macro_identifier_expr.identifier);
|
||||
DUMPEXPC(expr);
|
||||
DUMPEND();
|
||||
case EXPR_IDENTIFIER:
|
||||
if (expr->identifier_expr.is_macro)
|
||||
{
|
||||
DUMPF("(ident @%s", expr->identifier_expr.identifier);
|
||||
}
|
||||
else
|
||||
{
|
||||
DUMPF("(ident %s", expr->identifier_expr.identifier);
|
||||
}
|
||||
DUMPF("(ident %s", expr->identifier_expr.identifier);
|
||||
DUMPEXPC(expr);
|
||||
DUMPEND();
|
||||
case EXPR_CT_IDENT:
|
||||
DUMPF("(ctident %s", expr->ct_ident_expr.identifier);
|
||||
DUMPEXPC(expr);
|
||||
DUMPEND();
|
||||
case EXPR_MACRO_CT_IDENTIFIER:
|
||||
DUMPF("(macroctident @%s", expr->ct_ident_expr.identifier);
|
||||
DUMPEXPC(expr);
|
||||
DUMPEND();
|
||||
case EXPR_CONST_IDENTIFIER:
|
||||
DUMPF("(ident %s", expr->identifier_expr.identifier);
|
||||
DUMPEXPC(expr);
|
||||
DUMPEND();
|
||||
case EXPR_MACRO_BLOCK:
|
||||
@@ -750,15 +772,18 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent)
|
||||
DUMPTI(decl->var.type_info);
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_CONST_CT:
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_PARAM:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_EXPR:
|
||||
case VARDECL_PARAM_REF:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
DUMPEXPR(decl->var.init_expr);
|
||||
break;
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
DUMPTI(decl->var.type_info);
|
||||
break;
|
||||
@@ -979,6 +1004,15 @@ static void fprint_ast_recursive(Context *context, FILE *file, Ast *ast, int ind
|
||||
DUMP("(compound\n");
|
||||
fprint_asts_recursive(context, file, ast->compound_stmt.stmts, indent + 1);
|
||||
DUMPEND();
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
if (!ast->compound_stmt.stmts)
|
||||
{
|
||||
DUMP("(ct-compound)");
|
||||
return;
|
||||
}
|
||||
DUMP("(ct-compound\n");
|
||||
fprint_asts_recursive(context, file, ast->ct_compound_stmt, indent + 1);
|
||||
DUMPEND();
|
||||
case AST_DEFINE_STMT:
|
||||
DUMP("(define");
|
||||
DUMPDECL(ast->define_stmt);
|
||||
|
||||
@@ -284,7 +284,11 @@ typedef struct _VarDecl
|
||||
Expr *init_expr;
|
||||
Decl *alias;
|
||||
};
|
||||
void *backend_debug_ref;
|
||||
union
|
||||
{
|
||||
void *backend_debug_ref;
|
||||
void *scope;
|
||||
};
|
||||
void *failable_ref;
|
||||
} VarDecl;
|
||||
|
||||
@@ -425,7 +429,8 @@ typedef struct _Decl
|
||||
Visibility visibility : 2;
|
||||
ResolveStatus resolve_status : 2;
|
||||
bool is_packed : 1;
|
||||
void *ref;
|
||||
bool has_addr : 1;
|
||||
void *backend_ref;
|
||||
const char *cname;
|
||||
uint32_t alignment;
|
||||
const char *section;
|
||||
@@ -573,11 +578,26 @@ typedef struct
|
||||
{
|
||||
Path *path;
|
||||
const char *identifier;
|
||||
bool is_ref;
|
||||
bool is_macro;
|
||||
bool is_ref : 1;
|
||||
bool is_rvalue : 1;
|
||||
Decl *decl;
|
||||
} ExprIdentifier;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *identifier;
|
||||
bool is_ref : 1;
|
||||
bool is_rvalue : 1;
|
||||
Decl *decl;
|
||||
} ExprIdentifierRaw;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *identifier;
|
||||
bool is_macro;
|
||||
Decl *decl;
|
||||
} ExprCtIdentifier;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -689,8 +709,12 @@ struct _Expr
|
||||
ExprSubscript subscript_expr;
|
||||
ExprAccess access_expr;
|
||||
ExprIdentifier identifier_expr;
|
||||
ExprIdentifier macro_identifier_expr;
|
||||
ExprIdentifierRaw ct_ident_expr;
|
||||
ExprIdentifierRaw ct_macro_ident_expr;
|
||||
TypeInfo *typeid_expr;
|
||||
ExprInitializer expr_initializer;
|
||||
Decl *expr_enum;
|
||||
ExprCompoundLiteral expr_compound_literal;
|
||||
Expr** expression_list;
|
||||
ExprScope expr_scope;
|
||||
@@ -946,6 +970,7 @@ typedef struct _Ast
|
||||
FlowCommon flow; // Shared struct
|
||||
AstAsmStmt asm_stmt; // 24
|
||||
AstCompoundStmt compound_stmt; // 16
|
||||
Ast** ct_compound_stmt;
|
||||
Decl *declare_stmt; // 8
|
||||
Expr *expr_stmt; // 8
|
||||
AstTryStmt try_stmt;
|
||||
@@ -1138,7 +1163,7 @@ extern Type *type_byte, *type_ushort, *type_uint, *type_ulong, *type_usize;
|
||||
extern Type *type_compint, *type_compfloat;
|
||||
extern Type *type_c_short, *type_c_int, *type_c_long, *type_c_longlong;
|
||||
extern Type *type_c_ushort, *type_c_uint, *type_c_ulong, *type_c_ulonglong;
|
||||
extern Type *type_typeid, *type_error, *type_typeinfo, *type_member;
|
||||
extern Type *type_typeid, *type_error, *type_typeinfo;
|
||||
|
||||
extern const char *attribute_list[NUMBER_OF_ATTRIBUTES];
|
||||
|
||||
@@ -1150,6 +1175,7 @@ extern const char *kw_kindof;
|
||||
extern const char *kw_nameof;
|
||||
extern const char *kw_qnameof;
|
||||
extern const char *kw_len;
|
||||
extern const char *kw_ordinal;
|
||||
|
||||
#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id(_token.id))
|
||||
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
|
||||
@@ -1240,6 +1266,7 @@ bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *lef
|
||||
bool sema_analyse_expr_of_required_type(Context *context, Type *to, Expr *expr, bool may_be_failable);
|
||||
bool sema_analyse_expr(Context *context, Type *to, Expr *expr);
|
||||
bool sema_analyse_decl(Context *context, Decl *decl);
|
||||
bool expr_is_constant_eval(Expr *expr);
|
||||
|
||||
void compiler_add_type(Type *type);
|
||||
Decl *compiler_find_symbol(const char *name);
|
||||
@@ -1440,7 +1467,8 @@ unsigned int type_abi_alignment(Type *type);
|
||||
const char *type_generate_qname(Type *type);
|
||||
void type_append_signature_name(Type *type, char *dst, size_t *offset);
|
||||
Type *type_find_max_type(Type *type, Type *other);
|
||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_FXX; }
|
||||
|
||||
static inline bool type_is_builtin(TypeKind kind) { return kind >= TYPE_VOID && kind <= TYPE_TYPEID; }
|
||||
static inline bool type_kind_is_signed(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_I64; }
|
||||
static inline bool type_kind_is_unsigned(TypeKind kind) { return kind >= TYPE_U8 && kind <= TYPE_U64; }
|
||||
static inline bool type_kind_is_any_integer(TypeKind kind) { return kind >= TYPE_I8 && kind <= TYPE_IXX; }
|
||||
@@ -1625,4 +1653,6 @@ static inline void advance_and_verify(Context *context, TokenType token_type)
|
||||
#define TRY_TYPE_REAL_OR(_type_stmt, _res) ({ Type* _type = (_type_stmt); if (!type_ok(_type)) return _res; _type; })
|
||||
#define TRY_DECL_OR(_decl_stmt, _res) ({ Decl* _decl = (_decl_stmt); if (!decl_ok(_decl)) return _res; _decl; })
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
|
||||
@@ -59,6 +59,7 @@ typedef enum
|
||||
AST_CONTINUE_STMT,
|
||||
AST_DEFINE_STMT,
|
||||
AST_CT_ASSERT,
|
||||
AST_CT_COMPOUND_STMT,
|
||||
AST_CT_IF_STMT,
|
||||
AST_CT_ELIF_STMT,
|
||||
AST_CT_ELSE_STMT,
|
||||
@@ -184,6 +185,10 @@ typedef enum
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_TYPEID,
|
||||
EXPR_IDENTIFIER,
|
||||
EXPR_MACRO_IDENTIFIER,
|
||||
EXPR_CT_IDENT,
|
||||
EXPR_CONST_IDENTIFIER,
|
||||
EXPR_MACRO_CT_IDENTIFIER,
|
||||
EXPR_CALL,
|
||||
EXPR_GROUP,
|
||||
EXPR_SUBSCRIPT,
|
||||
@@ -195,6 +200,7 @@ typedef enum
|
||||
EXPR_CAST,
|
||||
EXPR_TYPEINFO,
|
||||
EXPR_TYPEOF,
|
||||
EXPR_MEMBER_ACCESS,
|
||||
EXPR_SCOPED_EXPR,
|
||||
EXPR_EXPR_BLOCK,
|
||||
EXPR_MACRO_BLOCK,
|
||||
@@ -204,6 +210,7 @@ typedef enum
|
||||
EXPR_DECL_LIST,
|
||||
EXPR_LEN,
|
||||
EXPR_UNDEF,
|
||||
EXPR_ENUM_CONSTANT,
|
||||
} ExprKind;
|
||||
|
||||
typedef enum
|
||||
@@ -374,6 +381,11 @@ typedef enum
|
||||
TOKEN_CT_CONST_IDENT, // $FOOBAR
|
||||
TOKEN_CT_TYPE_IDENT, // $Foobar
|
||||
|
||||
// We want to parse #foo separately.
|
||||
TOKEN_HASH_IDENT, // #foobar
|
||||
TOKEN_HASH_CONST_IDENT, // #FOOBAR
|
||||
TOKEN_HASH_TYPE_IDENT, // #Foobar
|
||||
|
||||
TOKEN_STRING, // "Teststring"
|
||||
TOKEN_INTEGER, // 123 0x23 0b10010 0o327
|
||||
TOKEN_CHAR_LITERAL, // 'a' 'FO' 'BARS' '\u1232'
|
||||
@@ -433,6 +445,8 @@ typedef enum
|
||||
TOKEN_CT_FOR, // $for
|
||||
TOKEN_CT_ELIF, // $elif
|
||||
TOKEN_CT_ELSE, // $else
|
||||
TOKEN_CT_ENDIF, // $endif
|
||||
TOKEN_CT_ENDSWITCH, // $endswitch
|
||||
TOKEN_CT_IF, // $if
|
||||
TOKEN_CT_SWITCH, // $switch
|
||||
TOKEN_CT_UNREACHABLE, // $unreachable
|
||||
@@ -469,6 +483,7 @@ typedef enum
|
||||
TYPE_F32,
|
||||
TYPE_F64,
|
||||
TYPE_FXX,
|
||||
TYPE_TYPEID,
|
||||
TYPE_POINTER,
|
||||
TYPE_ENUM,
|
||||
TYPE_FUNC,
|
||||
@@ -483,8 +498,7 @@ typedef enum
|
||||
TYPE_SUBARRAY,
|
||||
TYPE_TYPEINFO,
|
||||
TYPE_MEMBER,
|
||||
TYPE_TYPEID,
|
||||
TYPE_LAST = TYPE_TYPEID
|
||||
TYPE_LAST = TYPE_MEMBER
|
||||
} TypeKind;
|
||||
|
||||
#define ALL_INTS TYPE_I8: case TYPE_I16: case TYPE_I32: case TYPE_I64: \
|
||||
@@ -506,6 +520,7 @@ typedef enum
|
||||
UNARYOP_NOT,
|
||||
UNARYOP_INC,
|
||||
UNARYOP_DEC,
|
||||
UNARYOP_TADDR,
|
||||
UNARYOP_LAST = UNARYOP_DEC
|
||||
} UnaryOp;
|
||||
|
||||
@@ -522,10 +537,13 @@ typedef enum
|
||||
VARDECL_LOCAL = 2,
|
||||
VARDECL_PARAM = 3,
|
||||
VARDECL_MEMBER = 4,
|
||||
VARDECL_LOCAL_CT = 5,
|
||||
VARDECL_LOCAL_CT_TYPE = 6,
|
||||
VARDECL_CONST_CT = 7,
|
||||
VARDECL_ALIAS = 8,
|
||||
VARDECL_PARAM_CT = 5,
|
||||
VARDECL_PARAM_CT_TYPE = 6,
|
||||
VARDECL_PARAM_REF = 7,
|
||||
VARDECL_PARAM_EXPR = 8,
|
||||
VARDECL_LOCAL_CT = 9,
|
||||
VARDECL_LOCAL_CT_TYPE = 10,
|
||||
VARDECL_ALIAS = 11,
|
||||
} VarDeclKind;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -745,7 +745,7 @@ static bool lexer_scan_token_inner(Lexer *lexer)
|
||||
case '"':
|
||||
return scan_string(lexer);
|
||||
case '#':
|
||||
return add_token(lexer, TOKEN_HASH, "#");
|
||||
return scan_ident(lexer, TOKEN_HASH_IDENT, TOKEN_HASH_CONST_IDENT, TOKEN_HASH_TYPE_IDENT, '$');
|
||||
case '$':
|
||||
return scan_ident(lexer, TOKEN_CT_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$');
|
||||
case ',':
|
||||
@@ -915,5 +915,10 @@ bool lexer_scan_ident_test(Lexer *lexer, const char *scan)
|
||||
next(lexer);
|
||||
return scan_ident(lexer, TOKEN_CT_IDENT, TOKEN_CT_CONST_IDENT, TOKEN_CT_TYPE_IDENT, '$');
|
||||
}
|
||||
if (scan[0] == '#')
|
||||
{
|
||||
next(lexer);
|
||||
return scan_ident(lexer, TOKEN_HASH_IDENT, TOKEN_HASH_CONST_IDENT, TOKEN_HASH_TYPE_IDENT, '#');
|
||||
}
|
||||
return scan_ident(lexer, TOKEN_IDENT, TOKEN_CONST_IDENT, TOKEN_TYPE_IDENT, 0);
|
||||
}
|
||||
|
||||
@@ -60,35 +60,36 @@ LLVMValueRef gencontext_emit_memclear(GenContext *context, LLVMValueRef ref, Typ
|
||||
|
||||
static void gencontext_emit_global_variable_definition(GenContext *context, Decl *decl)
|
||||
{
|
||||
if (decl->var.kind == VARDECL_CONST_CT) return;
|
||||
|
||||
assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST);
|
||||
|
||||
// Skip real constants.
|
||||
if (!decl->type) return;
|
||||
|
||||
// TODO fix name
|
||||
decl->ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->name);
|
||||
decl->backend_ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->name);
|
||||
|
||||
if (decl->var.init_expr)
|
||||
{
|
||||
LLVMSetInitializer(decl->ref, gencontext_emit_expr(context, decl->var.init_expr));
|
||||
LLVMSetInitializer(decl->backend_ref, gencontext_emit_expr(context, decl->var.init_expr));
|
||||
}
|
||||
else
|
||||
{
|
||||
LLVMSetInitializer(decl->ref, LLVMConstNull(llvm_type(decl->type)));
|
||||
LLVMSetInitializer(decl->backend_ref, LLVMConstNull(llvm_type(decl->type)));
|
||||
}
|
||||
|
||||
LLVMSetGlobalConstant(decl->ref, decl->var.kind == VARDECL_CONST);
|
||||
LLVMSetGlobalConstant(decl->backend_ref, decl->var.kind == VARDECL_CONST);
|
||||
|
||||
switch (decl->visibility)
|
||||
{
|
||||
case VISIBLE_MODULE:
|
||||
LLVMSetVisibility(decl->ref, LLVMProtectedVisibility);
|
||||
LLVMSetVisibility(decl->backend_ref, LLVMProtectedVisibility);
|
||||
break;
|
||||
case VISIBLE_PUBLIC:
|
||||
LLVMSetVisibility(decl->ref, LLVMDefaultVisibility);
|
||||
LLVMSetVisibility(decl->backend_ref, LLVMDefaultVisibility);
|
||||
break;
|
||||
case VISIBLE_EXTERN:
|
||||
case VISIBLE_LOCAL:
|
||||
LLVMSetVisibility(decl->ref, LLVMHiddenVisibility);
|
||||
LLVMSetVisibility(decl->backend_ref, LLVMHiddenVisibility);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -406,8 +407,7 @@ void llvm_codegen(Context *context)
|
||||
gencontext_destroy(&gen_context);
|
||||
}
|
||||
|
||||
void
|
||||
gencontext_add_attribute(GenContext *context, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index)
|
||||
void gencontext_add_attribute(GenContext *context, LLVMValueRef value_to_add_attribute_to, unsigned attribute_id, int index)
|
||||
{
|
||||
LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(context->context, attribute_id, 0);
|
||||
LLVMAddAttributeAtIndex(value_to_add_attribute_to, index, llvm_attr);
|
||||
|
||||
@@ -223,6 +223,12 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
||||
}
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_MEMBER_ACCESS:
|
||||
case EXPR_ENUM_CONSTANT:
|
||||
case EXPR_CT_IDENT:
|
||||
case EXPR_MACRO_CT_IDENTIFIER:
|
||||
case EXPR_MACRO_IDENTIFIER:
|
||||
UNREACHABLE
|
||||
case EXPR_DESIGNATED_INITIALIZER:
|
||||
// Should only appear when generating designated initializers.
|
||||
UNREACHABLE
|
||||
@@ -236,6 +242,7 @@ LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
||||
case EXPR_TYPEINFO:
|
||||
// Should never be an lvalue
|
||||
UNREACHABLE
|
||||
case EXPR_CONST_IDENTIFIER:
|
||||
case EXPR_IDENTIFIER:
|
||||
return decl_ref(expr->identifier_expr.decl);
|
||||
case EXPR_UNARY:
|
||||
@@ -677,6 +684,13 @@ LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
case UNARYOP_ERROR:
|
||||
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
|
||||
case UNARYOP_TADDR:
|
||||
{
|
||||
LLVMValueRef val = gencontext_emit_expr(context, expr->unary_expr.expr);
|
||||
LLVMValueRef temp = gencontext_emit_alloca(context, llvm_type(expr->unary_expr.expr->type), "taddr");
|
||||
LLVMBuildStore(context->builder, val, temp);
|
||||
return temp;
|
||||
}
|
||||
case UNARYOP_NOT:
|
||||
if (type_is_float(type))
|
||||
{
|
||||
@@ -1661,14 +1675,14 @@ LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
|
||||
{
|
||||
Decl *function_decl = expr->call_expr.function->access_expr.ref;
|
||||
signature = &function_decl->func.function_signature;
|
||||
func = function_decl->ref;
|
||||
func = function_decl->backend_ref;
|
||||
func_type = llvm_type(function_decl->type);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decl *function_decl = expr->call_expr.function->identifier_expr.decl;
|
||||
signature = &function_decl->func.function_signature;
|
||||
func = function_decl->ref;
|
||||
func = function_decl->backend_ref;
|
||||
func_type = llvm_type(function_decl->type);
|
||||
}
|
||||
|
||||
@@ -1792,9 +1806,26 @@ static inline LLVMValueRef gencontext_emit_macro_block(GenContext *context, Expr
|
||||
VECEACH(expr->macro_block.params, i)
|
||||
{
|
||||
// In case we have a constant, we never do an emit. The value is already folded.
|
||||
if (!expr->macro_block.args[i]) continue;
|
||||
Decl *decl = expr->macro_block.params[i];
|
||||
decl->ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_CONST:
|
||||
case VARDECL_GLOBAL:
|
||||
case VARDECL_LOCAL:
|
||||
case VARDECL_MEMBER:
|
||||
case VARDECL_LOCAL_CT:
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
case VARDECL_ALIAS:
|
||||
UNREACHABLE
|
||||
case VARDECL_PARAM_REF:
|
||||
case VARDECL_PARAM_CT:
|
||||
case VARDECL_PARAM_CT_TYPE:
|
||||
case VARDECL_PARAM_EXPR:
|
||||
continue;
|
||||
case VARDECL_PARAM:
|
||||
break;
|
||||
}
|
||||
decl->backend_ref = gencontext_emit_alloca(context, llvm_type(decl->type), decl->name);
|
||||
LLVMValueRef value = gencontext_emit_expr(context, expr->macro_block.args[i]);
|
||||
gencontext_emit_store(context, decl, value);
|
||||
}
|
||||
@@ -1855,6 +1886,7 @@ LLVMValueRef gencontext_emit_assign_expr(GenContext *context, LLVMValueRef ref,
|
||||
|
||||
static inline LLVMValueRef gencontext_emit_identifier_rvalue(GenContext *context, Decl *decl)
|
||||
{
|
||||
|
||||
if (decl->decl_kind != DECL_VAR || !decl->var.failable)
|
||||
{
|
||||
return gencontext_emit_load(context, decl->type, decl_ref(decl));
|
||||
@@ -1902,9 +1934,14 @@ LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
|
||||
NESTED_RETRY:
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_MEMBER_ACCESS:
|
||||
case EXPR_POISONED:
|
||||
case EXPR_DECL_LIST:
|
||||
case EXPR_TYPEINFO:
|
||||
case EXPR_ENUM_CONSTANT:
|
||||
case EXPR_MACRO_IDENTIFIER:
|
||||
case EXPR_MACRO_CT_IDENTIFIER:
|
||||
case EXPR_CT_IDENT:
|
||||
UNREACHABLE
|
||||
case EXPR_UNDEF:
|
||||
// Should never reach this.
|
||||
@@ -1954,6 +1991,8 @@ NESTED_RETRY:
|
||||
// These are folded in the semantic analysis step.
|
||||
UNREACHABLE
|
||||
case EXPR_IDENTIFIER:
|
||||
case EXPR_CONST_IDENTIFIER:
|
||||
assert(expr->identifier_expr.is_rvalue);
|
||||
return gencontext_emit_identifier_rvalue(context, expr->identifier_expr.decl);
|
||||
case EXPR_SUBSCRIPT:
|
||||
case EXPR_ACCESS:
|
||||
|
||||
@@ -76,7 +76,7 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
|
||||
|
||||
// Allocate room on stack and copy.
|
||||
const char *name = decl->name ? decl->name : "anon";
|
||||
decl->ref = gencontext_emit_alloca(context, llvm_type(decl->type), name);
|
||||
decl->backend_ref = gencontext_emit_alloca(context, llvm_type(decl->type), name);
|
||||
if (gencontext_use_debug(context))
|
||||
{
|
||||
SourceLocation *loc = TOKLOC(decl->span.loc);
|
||||
@@ -93,9 +93,9 @@ static inline void gencontext_emit_parameter(GenContext *context, Decl *decl, un
|
||||
);
|
||||
decl->var.backend_debug_ref = var;
|
||||
LLVMDIBuilderInsertDeclareAtEnd(context->debug.builder,
|
||||
decl->ref, var, LLVMDIBuilderCreateExpression(context->debug.builder, NULL, 0),
|
||||
LLVMDIBuilderCreateDebugLocation(context->context, loc->line, loc->col, context->debug.function, /* inline at */NULL),
|
||||
LLVMGetInsertBlock(context->builder));
|
||||
decl->backend_ref, var, LLVMDIBuilderCreateExpression(context->debug.builder, NULL, 0),
|
||||
LLVMDIBuilderCreateDebugLocation(context->context, loc->line, loc->col, context->debug.function, /* inline at */NULL),
|
||||
LLVMGetInsertBlock(context->builder));
|
||||
}
|
||||
gencontext_emit_store(context, decl, LLVMGetParam(context->function, index));
|
||||
|
||||
@@ -121,7 +121,7 @@ void gencontext_emit_implicit_return(GenContext *context)
|
||||
void gencontext_emit_function_body(GenContext *context, Decl *decl)
|
||||
{
|
||||
DEBUG_LOG("Generating function %s.", decl->external_name);
|
||||
assert(decl->ref);
|
||||
assert(decl->backend_ref);
|
||||
|
||||
bool emit_debug = gencontext_use_debug(context);
|
||||
LLVMValueRef prev_function = context->function;
|
||||
@@ -130,7 +130,7 @@ void gencontext_emit_function_body(GenContext *context, Decl *decl)
|
||||
context->error_var = NULL;
|
||||
context->catch_block = NULL;
|
||||
|
||||
context->function = decl->ref;
|
||||
context->function = decl->backend_ref;
|
||||
if (emit_debug)
|
||||
{
|
||||
context->debug.function = LLVMGetSubprogram(context->function);
|
||||
@@ -217,7 +217,7 @@ void gencontext_emit_function_decl(GenContext *context, Decl *decl)
|
||||
assert(decl->decl_kind == DECL_FUNC);
|
||||
// Resolve function backend type for function.
|
||||
LLVMValueRef function = LLVMAddFunction(context->module, decl->cname ?: decl->external_name, llvm_type(decl->type));
|
||||
decl->ref = function;
|
||||
decl->backend_ref = function;
|
||||
if (decl->func.function_signature.return_param)
|
||||
{
|
||||
if (!decl->func.function_signature.failable)
|
||||
@@ -314,13 +314,13 @@ void gencontext_emit_extern_decl(GenContext *context, Decl *decl)
|
||||
case DECL_POISONED:
|
||||
UNREACHABLE;
|
||||
case DECL_FUNC:
|
||||
decl->ref = LLVMAddFunction(context->module, decl->cname ?: decl->external_name,
|
||||
llvm_type(decl->type));
|
||||
LLVMSetVisibility(decl->ref, LLVMDefaultVisibility);
|
||||
decl->backend_ref = LLVMAddFunction(context->module, decl->cname ?: decl->external_name,
|
||||
llvm_type(decl->type));
|
||||
LLVMSetVisibility(decl->backend_ref, LLVMDefaultVisibility);
|
||||
break;
|
||||
case DECL_VAR:
|
||||
decl->ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->cname ?: decl->external_name);
|
||||
LLVMSetVisibility(decl->ref, LLVMDefaultVisibility);
|
||||
decl->backend_ref = LLVMAddGlobal(context->module, llvm_type(decl->type), decl->cname ?: decl->external_name);
|
||||
LLVMSetVisibility(decl->backend_ref, LLVMDefaultVisibility);
|
||||
break;
|
||||
case DECL_TYPEDEF:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -199,7 +199,7 @@ static inline LLVMValueRef decl_failable_ref(Decl *decl)
|
||||
static inline LLVMValueRef decl_ref(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_ALIAS) return decl_ref(decl->var.alias);
|
||||
return decl->ref;
|
||||
return decl->backend_ref;
|
||||
}
|
||||
|
||||
static inline void gencontext_emit_store(GenContext *context, Decl *decl, LLVMValueRef value)
|
||||
|
||||
@@ -24,13 +24,22 @@ void gencontext_emit_compound_stmt(GenContext *context, Ast *ast)
|
||||
}
|
||||
}
|
||||
|
||||
void gencontext_emit_ct_compound_stmt(GenContext *context, Ast *ast)
|
||||
{
|
||||
assert(ast->ast_kind == AST_CT_COMPOUND_STMT);
|
||||
VECEACH(ast->compound_stmt.stmts, i)
|
||||
{
|
||||
gencontext_emit_stmt(context, ast->compound_stmt.stmts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
|
||||
{
|
||||
Decl *decl = ast->declare_stmt;
|
||||
|
||||
LLVMTypeRef alloc_type = llvm_type(type_reduced(decl->type));
|
||||
decl->ref = gencontext_emit_alloca(context, alloc_type, decl->name);
|
||||
decl->backend_ref = gencontext_emit_alloca(context, alloc_type, decl->name);
|
||||
if (decl->var.failable)
|
||||
{
|
||||
decl->var.failable_ref = gencontext_emit_alloca(context, llvm_type(type_error), decl->name);
|
||||
@@ -58,7 +67,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
|
||||
// If we don't have undef, then make an assign.
|
||||
if (init->expr_kind != EXPR_UNDEF)
|
||||
{
|
||||
gencontext_emit_assign_expr(context, decl->ref, decl->var.init_expr, decl->var.failable_ref);
|
||||
gencontext_emit_assign_expr(context, decl->backend_ref, decl->var.init_expr, decl->var.failable_ref);
|
||||
}
|
||||
// TODO trap on undef in debug mode.
|
||||
}
|
||||
@@ -67,7 +76,7 @@ static LLVMValueRef gencontext_emit_decl(GenContext *context, Ast *ast)
|
||||
// Normal case, zero init.
|
||||
gencontext_emit_store(context, decl, LLVMConstNull(alloc_type));
|
||||
}
|
||||
return decl->ref;
|
||||
return decl->backend_ref;
|
||||
}
|
||||
|
||||
void gencontext_emit_decl_expr_list_ignore_result(GenContext *context, Expr *expr)
|
||||
@@ -904,7 +913,7 @@ void gencontext_emit_catch_stmt(GenContext *context, Ast *ast)
|
||||
Decl *error_var = ast->catch_stmt.err_var;
|
||||
assert(error_var->type->canonical == type_error);
|
||||
error_result = gencontext_emit_alloca(context, llvm_type(type_error), error_var->name);
|
||||
error_var->ref = error_result;
|
||||
error_var->backend_ref = error_result;
|
||||
catch_expr = error_var->var.init_expr;
|
||||
|
||||
}
|
||||
@@ -1009,6 +1018,9 @@ void gencontext_emit_stmt(GenContext *context, Ast *ast)
|
||||
case AST_COMPOUND_STMT:
|
||||
gencontext_emit_compound_stmt(context, ast);
|
||||
break;
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
gencontext_emit_ct_compound_stmt(context, ast);
|
||||
break;
|
||||
case AST_FOR_STMT:
|
||||
gencontext_emit_for_stmt(context, ast);
|
||||
break;
|
||||
|
||||
@@ -61,9 +61,6 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr)
|
||||
case TYPE_FXX:
|
||||
fprintf(file, "%Lf", expr->f);
|
||||
break;
|
||||
case TYPE_ENUM:
|
||||
fprintf(file, "%s", expr->enum_constant->name);
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
fprintf(file, "%.*s", expr->string.len, expr->string.chars);
|
||||
break;
|
||||
@@ -246,9 +243,6 @@ const char *expr_const_to_error_string(const ExprConst *expr)
|
||||
case TYPE_FXX:
|
||||
asprintf(&buff, "%Lf", expr->f);
|
||||
return buff;
|
||||
case TYPE_ENUM:
|
||||
asprintf(&buff, "%s.%s", expr->enum_constant->type->name, expr->enum_constant->name);
|
||||
return buff;
|
||||
case TYPE_STRING:
|
||||
asprintf(&buff, "\"%*.s\"", expr->string.len, expr->string.chars);
|
||||
return buff;
|
||||
|
||||
@@ -104,9 +104,16 @@ bool parse_param_list(Context *context, Expr ***result, bool allow_type, TokenTy
|
||||
static Expr *parse_macro_ident(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *macro_ident = EXPR_NEW_TOKEN(EXPR_IDENTIFIER, context->tok);
|
||||
macro_ident->identifier_expr.is_macro = true;
|
||||
Expr *macro_ident = EXPR_NEW_TOKEN(EXPR_MACRO_IDENTIFIER, context->tok);
|
||||
advance_and_verify(context, TOKEN_AT);
|
||||
if (TOKEN_IS(TOKEN_CT_IDENT))
|
||||
{
|
||||
macro_ident->ct_macro_ident_expr.identifier = TOKSTR(context->tok);
|
||||
macro_ident->expr_kind = EXPR_MACRO_CT_IDENTIFIER;
|
||||
advance_and_verify(context, TOKEN_CT_IDENT);
|
||||
RANGE_EXTEND_PREV(macro_ident);
|
||||
return macro_ident;
|
||||
}
|
||||
bool had_error = false;
|
||||
macro_ident->identifier_expr.path = parse_path_prefix(context, &had_error);
|
||||
if (had_error) return poisoned_expr;
|
||||
@@ -424,13 +431,27 @@ static Expr *parse_access_expr(Context *context, Expr *left)
|
||||
|
||||
static Expr *parse_identifier_with_path(Context *context, Path *path)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_IDENTIFIER, context->tok);
|
||||
Expr *expr = EXPR_NEW_TOKEN(context->tok.type == TOKEN_CONST_IDENT ? EXPR_CONST_IDENTIFIER : EXPR_IDENTIFIER , context->tok);
|
||||
expr->identifier_expr.identifier = TOKSTR(context->tok);
|
||||
expr->identifier_expr.path = path;
|
||||
advance(context);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_ct_ident(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
if (try_consume(context, TOKEN_CT_CONST_IDENT))
|
||||
{
|
||||
SEMA_TOKID_ERROR(context->prev_tok, "Compile time identifiers may not be constants.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_IDENT, context->tok);
|
||||
expr->ct_ident_expr.identifier = TOKSTR(context->tok);
|
||||
advance(context);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_identifier(Context *context, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
@@ -447,7 +468,6 @@ static Expr *parse_maybe_scope(Context *context, Expr *left)
|
||||
switch (context->tok.type)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CT_IDENT:
|
||||
case TOKEN_CONST_IDENT:
|
||||
return parse_identifier_with_path(context, path);
|
||||
case TOKEN_TYPE_IDENT:
|
||||
@@ -910,16 +930,11 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_NULL] = { parse_null, NULL, PREC_NONE },
|
||||
[TOKEN_INTEGER] = { parse_integer, NULL, PREC_NONE },
|
||||
[TOKEN_CHAR_LITERAL] = { parse_char_lit, NULL, PREC_NONE },
|
||||
[TOKEN_IDENT] = { parse_maybe_scope, NULL, PREC_NONE },
|
||||
[TOKEN_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
|
||||
[TOKEN_CT_IDENT] = { parse_identifier, NULL, PREC_NONE },
|
||||
[TOKEN_AT] = { parse_macro_ident, NULL, PREC_NONE },
|
||||
[TOKEN_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE },
|
||||
[TOKEN_CT_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE },
|
||||
[TOKEN_STRING] = { parse_string_literal, NULL, PREC_NONE },
|
||||
[TOKEN_REAL] = { parse_double, NULL, PREC_NONE },
|
||||
[TOKEN_OR] = { NULL, parse_binary, PREC_LOGICAL },
|
||||
[TOKEN_AND] = { NULL, parse_binary, PREC_LOGICAL },
|
||||
[TOKEN_AND] = { parse_unary_expr, parse_binary, PREC_LOGICAL },
|
||||
[TOKEN_EQ] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
[TOKEN_PLUS_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
[TOKEN_PLUS_MOD_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
@@ -934,4 +949,13 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_BIT_OR_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
[TOKEN_SHR_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
[TOKEN_SHL_ASSIGN] = { NULL, parse_binary, PREC_ASSIGNMENT },
|
||||
|
||||
[TOKEN_IDENT] = { parse_maybe_scope, NULL, PREC_NONE },
|
||||
[TOKEN_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
|
||||
[TOKEN_CT_IDENT] = { parse_ct_ident, NULL, PREC_NONE },
|
||||
[TOKEN_CONST_IDENT] = { parse_identifier, NULL, PREC_NONE },
|
||||
[TOKEN_CT_CONST_IDENT] = { parse_ct_ident, NULL, PREC_NONE },
|
||||
[TOKEN_CT_TYPE_IDENT] = { parse_type_identifier, NULL, PREC_NONE },
|
||||
//[TOKEN_HASH_TYPE_IDENT] = { parse_type_identifier(, NULL, PREC_NONE }
|
||||
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "compiler_internal.h"
|
||||
#include "parser_internal.h"
|
||||
|
||||
static Decl *parse_const_declaration(Context *context, Visibility visibility);
|
||||
|
||||
static bool context_next_up_is_type_with_path(Context *context)
|
||||
{
|
||||
@@ -221,8 +222,8 @@ static inline Path *parse_module_path(Context *context)
|
||||
/**
|
||||
*
|
||||
* module_param
|
||||
* : CT_IDENT
|
||||
* | HASH_IDENT
|
||||
* : TYPE_IDENT
|
||||
* | IDENT
|
||||
* ;
|
||||
*
|
||||
* module_params
|
||||
@@ -249,14 +250,15 @@ static inline bool parse_optional_module_params(Context *context, TokenId **toke
|
||||
switch (context->tok.type)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
SEMA_TOKEN_ERROR(context->tok, "The module parameter must be a $ or #-prefixed name, did you forgot the '$'?");
|
||||
case TOKEN_TYPE_IDENT:
|
||||
return false;
|
||||
case TOKEN_COMMA:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Unexpected ','");
|
||||
return false;
|
||||
case TOKEN_CT_IDENT:
|
||||
case TOKEN_TYPE_IDENT:
|
||||
break;
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
SEMA_TOKEN_ERROR(context->tok, "The module parameter cannot be a $-prefixed name.");
|
||||
return false;
|
||||
default:
|
||||
SEMA_TOKEN_ERROR(context->tok, "Only generic parameters are allowed here as parameters to the module.");
|
||||
return false;
|
||||
@@ -384,7 +386,7 @@ bool consume_const_name(Context *context, const char* type)
|
||||
SEMA_TOKEN_ERROR(context->tok, "Names of %ss must be all upper case.", type);
|
||||
return false;
|
||||
}
|
||||
if (!consume(context, TOKEN_CONST_IDENT, "'%s' should be followed by the name of the %s.", type, type)) return false;
|
||||
if (!consume(context, TOKEN_CONST_IDENT, "The constant name was expected here, did you forget it?")) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -683,7 +685,8 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type)
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
EXPECT_IDENT_FOR_OR("variable_name", poisoned_decl);
|
||||
|
||||
EXPECT_IDENT_FOR_OR("variable name", poisoned_decl);
|
||||
|
||||
TokenId name = context->tok.id;
|
||||
advance(context);
|
||||
@@ -703,6 +706,7 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type)
|
||||
return decl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* declaration ::= ('local' | 'const')? type variable ('=' expr)?
|
||||
*
|
||||
@@ -710,14 +714,22 @@ Decl *parse_decl_after_type(Context *context, bool local, TypeInfo *type)
|
||||
*/
|
||||
Decl *parse_decl(Context *context)
|
||||
{
|
||||
bool local = TOKEN_IS(TOKEN_LOCAL);
|
||||
bool constant = TOKEN_IS(TOKEN_CONST);
|
||||
if (local || constant) advance(context);
|
||||
bool local = try_consume(context, TOKEN_LOCAL);
|
||||
|
||||
TypeInfo *type_info = parse_type(context);
|
||||
TypeInfo *type = TRY_TYPE_OR(type_info, poisoned_decl);
|
||||
if (TOKEN_IS(TOKEN_CONST))
|
||||
{
|
||||
if (local)
|
||||
{
|
||||
SEMA_TOKID_ERROR(context->prev_tok, "A 'local' variable cannot also be declared 'constant'.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
return parse_const_declaration(context, VISIBLE_LOCAL);
|
||||
}
|
||||
|
||||
TypeInfo *type = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
|
||||
bool failable = try_consume(context, TOKEN_BANG);
|
||||
|
||||
Decl *decl = TRY_DECL_OR(parse_decl_after_type(context, local, type), poisoned_decl);
|
||||
if (failable && decl->var.unwrap)
|
||||
{
|
||||
@@ -725,7 +737,6 @@ Decl *parse_decl(Context *context)
|
||||
return poisoned_decl;
|
||||
}
|
||||
decl->var.failable = failable;
|
||||
if (constant) decl->var.kind = VARDECL_CONST;
|
||||
|
||||
return decl;
|
||||
}
|
||||
@@ -734,40 +745,28 @@ Decl *parse_decl(Context *context)
|
||||
|
||||
/**
|
||||
* const_decl
|
||||
* : 'const' CT_CONST_IDENT '=' const_expr ';'
|
||||
* | 'const' type IDENT '=' const_expr ';'
|
||||
* : 'const' type? IDENT '=' const_expr
|
||||
* ;
|
||||
*/
|
||||
static inline Decl *parse_const_declaration(Context *context, Visibility visibility)
|
||||
static Decl *parse_const_declaration(Context *context, Visibility visibility)
|
||||
{
|
||||
advance_and_verify(context, TOKEN_CONST);
|
||||
|
||||
Decl *decl = DECL_NEW_VAR(NULL, VARDECL_CONST, visibility);
|
||||
decl->span.loc = context->prev_tok;
|
||||
|
||||
// Parse the compile time constant.
|
||||
if (try_consume(context, TOKEN_CT_CONST_IDENT))
|
||||
{
|
||||
decl->var.kind = VARDECL_CONST_CT;
|
||||
if (!is_all_upper(decl->name))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Compile time constants must be all upper characters.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (parse_next_is_decl(context))
|
||||
{
|
||||
decl->var.type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
decl->name = TOKKSTR(context->tok);
|
||||
decl->name_token = context->tok.id;
|
||||
if (!consume_const_name(context, "constant")) return poisoned_decl;
|
||||
}
|
||||
decl->name = TOKKSTR(context->tok);
|
||||
decl->name_token = context->tok.id;
|
||||
if (!consume_const_name(context, "const")) return poisoned_decl;
|
||||
|
||||
CONSUME_OR(TOKEN_EQ, poisoned_decl);
|
||||
|
||||
decl->var.init_expr = TRY_EXPR_OR(parse_initializer(context), poisoned_decl);
|
||||
|
||||
CONSUME_OR(TOKEN_EOS, poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -790,9 +789,14 @@ static inline Decl *parse_global_declaration(Context *context, Visibility visibi
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "'func' can't appear here, maybe you intended to put 'func' the type?");
|
||||
advance(context);
|
||||
return false;
|
||||
return poisoned_decl;
|
||||
}
|
||||
|
||||
if (TOKEN_IS(TOKEN_CONST_IDENT))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "This looks like a constant variable, did you forget 'const'?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (!consume_ident(context, "global variable")) return poisoned_decl;
|
||||
|
||||
if (try_consume(context, TOKEN_EQ))
|
||||
@@ -890,7 +894,8 @@ bool parse_next_is_decl(Context *context)
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
case TOKEN_ERR:
|
||||
case TOKEN_TYPEID:
|
||||
return (next_tok == TOKEN_BANG) | (next_tok == TOKEN_STAR) | (next_tok == TOKEN_LBRACKET) | (next_tok == TOKEN_IDENT);
|
||||
return (next_tok == TOKEN_BANG) | (next_tok == TOKEN_STAR) | (next_tok == TOKEN_LBRACKET) | (next_tok == TOKEN_IDENT)
|
||||
| (next_tok == TOKEN_CONST_IDENT);
|
||||
case TOKEN_IDENT:
|
||||
if (next_tok != TOKEN_SCOPE) return false;
|
||||
return context_next_up_is_type_with_path(context);
|
||||
@@ -1197,6 +1202,13 @@ static inline Decl *parse_struct_declaration(Context *context, Visibility visibi
|
||||
return decl;
|
||||
}
|
||||
|
||||
static inline Decl *parse_top_level_const_declaration(Context *context, Visibility visibility)
|
||||
{
|
||||
Decl *decl = TRY_DECL_OR(parse_const_declaration(context, visibility), poisoned_decl);
|
||||
TRY_CONSUME_EOS_OR(poisoned_decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse statements up to the next '}', 'case' or 'default'
|
||||
*/
|
||||
@@ -1264,6 +1276,11 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi
|
||||
|
||||
static inline Decl *parse_define(Context *context, Visibility visibility)
|
||||
{
|
||||
if (context->next_tok.type == TOKEN_CT_TYPE_IDENT || context->next_tok.type == TOKEN_CT_IDENT)
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->next_tok, "Compile time variables cannot be defined at the global level.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
advance_and_verify(context, TOKEN_DEFINE);
|
||||
bool had_error = false;
|
||||
Path *path = parse_path_prefix(context, &had_error);
|
||||
@@ -1437,12 +1454,32 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
|
||||
while (!try_consume(context, TOKEN_RPAREN))
|
||||
{
|
||||
TypeInfo *parm_type = NULL;
|
||||
VarDeclKind param_kind;
|
||||
TEST_TYPE:
|
||||
switch (context->tok.type)
|
||||
{
|
||||
case TOKEN_IDENT:
|
||||
case TOKEN_CT_IDENT:
|
||||
param_kind = VARDECL_PARAM;
|
||||
break;
|
||||
case TOKEN_CT_IDENT:
|
||||
param_kind = VARDECL_PARAM_CT;
|
||||
break;
|
||||
case TOKEN_AND:
|
||||
advance(context);
|
||||
if (!TOKEN_IS(TOKEN_IDENT))
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "Only normal variables may be passed by reference.");
|
||||
}
|
||||
param_kind = VARDECL_PARAM_REF;
|
||||
break;
|
||||
case TOKEN_HASH_IDENT:
|
||||
param_kind = VARDECL_PARAM_EXPR;
|
||||
break;
|
||||
case TOKEN_HASH_TYPE_IDENT:
|
||||
param_kind = VARDECL_PARAM_EXPR;
|
||||
break;
|
||||
case TOKEN_ELLIPSIS:
|
||||
TODO
|
||||
default:
|
||||
if (parm_type)
|
||||
{
|
||||
@@ -1452,7 +1489,7 @@ static inline Decl *parse_macro_declaration(Context *context, Visibility visibil
|
||||
parm_type = TRY_TYPE_OR(parse_type(context), poisoned_decl);
|
||||
goto TEST_TYPE;
|
||||
}
|
||||
Decl *param = decl_new_var(context->tok.id, parm_type, VARDECL_PARAM, visibility);
|
||||
Decl *param = decl_new_var(context->tok.id, parm_type, param_kind, visibility);
|
||||
advance(context);
|
||||
params = VECADD(params, param);
|
||||
COMMA_RPAREN_OR(poisoned_decl);
|
||||
@@ -1767,7 +1804,7 @@ void parse_imports(Context *context)
|
||||
* | attribute_declaration
|
||||
* ;
|
||||
* @param visibility
|
||||
* @return true if parsing worked
|
||||
* @return Decl* or a poison value if parsing failed
|
||||
*/
|
||||
Decl *parse_top_level_statement(Context *context)
|
||||
{
|
||||
@@ -1811,7 +1848,7 @@ Decl *parse_top_level_statement(Context *context)
|
||||
if (!check_no_visibility_before(context, visibility)) return poisoned_decl;
|
||||
return parse_ct_switch_top_level(context);
|
||||
case TOKEN_CONST:
|
||||
return parse_const_declaration(context, visibility);
|
||||
return parse_top_level_const_declaration(context, visibility);
|
||||
case TOKEN_STRUCT:
|
||||
case TOKEN_UNION:
|
||||
return parse_struct_declaration(context, visibility);
|
||||
@@ -1854,7 +1891,7 @@ Decl *parse_top_level_statement(Context *context)
|
||||
{
|
||||
return parse_global_declaration(context, visibility);
|
||||
}
|
||||
SEMA_TOKEN_ERROR(context->tok, "Unexpected symbol found.");
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a top level declaration here.");
|
||||
return poisoned_decl;
|
||||
}
|
||||
}
|
||||
@@ -206,7 +206,7 @@ static inline Ast* parse_do_stmt(Context *context)
|
||||
|
||||
static inline bool token_type_ends_case(TokenType type, TokenType case_type, TokenType default_type)
|
||||
{
|
||||
return type == case_type || type == default_type || type == TOKEN_RBRACE;
|
||||
return type == case_type || type == default_type || type == TOKEN_RBRACE || type == TOKEN_CT_ENDSWITCH;
|
||||
}
|
||||
|
||||
static inline Ast *parse_case_stmts(Context *context, TokenType case_type, TokenType default_type)
|
||||
@@ -605,14 +605,13 @@ static inline Ast *parse_decl_or_expr_stmt(Context *context)
|
||||
static inline Ast *parse_define_stmt(Context *context)
|
||||
{
|
||||
Ast *ast = AST_NEW_TOKEN(AST_DEFINE_STMT, context->tok);
|
||||
|
||||
TokenId start = context->tok.id;
|
||||
advance_and_verify(context, TOKEN_DEFINE);
|
||||
Decl *decl = decl_new_var(context->tok.id, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL);
|
||||
ast->define_stmt = decl;
|
||||
|
||||
Decl *decl;
|
||||
switch (context->tok.type)
|
||||
{
|
||||
case TOKEN_CT_IDENT:
|
||||
decl = decl_new_var(context->tok.id, NULL, VARDECL_LOCAL_CT, VISIBLE_LOCAL);
|
||||
advance(context);
|
||||
if (try_consume(context, TOKEN_EQ))
|
||||
{
|
||||
@@ -620,6 +619,7 @@ static inline Ast *parse_define_stmt(Context *context)
|
||||
}
|
||||
break;
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
decl = decl_new_var(context->tok.id, NULL, VARDECL_LOCAL_CT_TYPE, VISIBLE_LOCAL);
|
||||
advance(context);
|
||||
if (try_consume(context, TOKEN_EQ))
|
||||
{
|
||||
@@ -630,35 +630,52 @@ static inline Ast *parse_define_stmt(Context *context)
|
||||
SEMA_TOKEN_ERROR(context->tok, "Expected a compile time variable name ('$Foo' or '$foo').");
|
||||
return poisoned_ast;
|
||||
}
|
||||
decl->span.loc = start;
|
||||
ast->define_stmt = decl;
|
||||
RANGE_EXTEND_PREV(decl);
|
||||
RANGE_EXTEND_PREV(ast);
|
||||
TRY_CONSUME_EOS();
|
||||
return ast;
|
||||
}
|
||||
|
||||
static inline Ast* parse_ct_compound_stmt(Context *context)
|
||||
{
|
||||
Ast *stmts = AST_NEW_TOKEN(AST_CT_COMPOUND_STMT, context->tok);
|
||||
while (1)
|
||||
{
|
||||
TokenType token = context->tok.type;
|
||||
if (token == TOKEN_CT_ELSE || token == TOKEN_CT_ELIF || token == TOKEN_CT_ENDIF) break;
|
||||
Ast *stmt = TRY_AST(parse_stmt(context));
|
||||
vec_add(stmts->ct_compound_stmt, stmt);
|
||||
RANGE_EXTEND_PREV(stmts);
|
||||
}
|
||||
return stmts;
|
||||
}
|
||||
|
||||
/**
|
||||
* ct_else_stmt
|
||||
* : CT_ELSE compound_stmt
|
||||
* : CT_ELSE ':' ct_compound_stmt
|
||||
*/
|
||||
static inline Ast* parse_ct_else_stmt(Context *context)
|
||||
{
|
||||
Ast *ast = AST_NEW_TOKEN(AST_CT_ELSE_STMT, context->tok);
|
||||
advance_and_verify(context, TOKEN_CT_ELSE);
|
||||
ast->ct_elif_stmt.then = TRY_AST(parse_compound_stmt(context));
|
||||
TRY_CONSUME(TOKEN_COLON, "$else needs a ':', did you forget it?");
|
||||
ast->ct_else_stmt = TRY_AST(parse_ct_compound_stmt(context));
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* ct_elif_stmt
|
||||
* : CT_ELIF '(' expression ')' compound_statement
|
||||
* : CT_ELIF '(' expression ')' ':' ct_compound_stmt (ct_elif_stmt | ct_else_stmt)?
|
||||
*/
|
||||
static inline Ast *parse_ct_elif_stmt(Context *context)
|
||||
{
|
||||
Ast *ast = AST_NEW_TOKEN(AST_CT_ELIF_STMT, context->tok);
|
||||
advance_and_verify(context, TOKEN_CT_ELIF);
|
||||
|
||||
ast->ct_elif_stmt.expr = TRY_EXPR_OR(parse_const_paren_expr(context), poisoned_ast);
|
||||
|
||||
ast->ct_elif_stmt.then = TRY_AST(parse_compound_stmt(context));
|
||||
|
||||
TRY_CONSUME(TOKEN_COLON, "$elif needs a ':' after the expression, did you forget it?");
|
||||
ast->ct_elif_stmt.then = TRY_AST(parse_ct_compound_stmt(context));
|
||||
if (TOKEN_IS(TOKEN_CT_ELIF))
|
||||
{
|
||||
ast->ct_elif_stmt.elif = TRY_AST(parse_ct_elif_stmt(context));
|
||||
@@ -669,11 +686,10 @@ static inline Ast *parse_ct_elif_stmt(Context *context)
|
||||
}
|
||||
return ast;
|
||||
}
|
||||
|
||||
/**
|
||||
* ct_if_stmt
|
||||
* : CT_IF '(' expression ')' compound_stmt
|
||||
* | CT_IF '(' expression ')' compound_stmt elif_stmt
|
||||
* | CT_IF '(' expression ')' compound_stmt else_stmt
|
||||
* : CT_IF '(' expression ')' ':' ct_compound_stmt (ct_elif_stmt | ct_else_stmt) CT_ENDIF EOS
|
||||
* ;
|
||||
*/
|
||||
static inline Ast* parse_ct_if_stmt(Context *context)
|
||||
@@ -681,7 +697,8 @@ static inline Ast* parse_ct_if_stmt(Context *context)
|
||||
Ast *ast = AST_NEW_TOKEN(AST_CT_IF_STMT, context->tok);
|
||||
advance_and_verify(context, TOKEN_CT_IF);
|
||||
ast->ct_if_stmt.expr = TRY_EXPR_OR(parse_const_paren_expr(context), poisoned_ast);
|
||||
ast->ct_if_stmt.then = TRY_AST(parse_compound_stmt(context));
|
||||
TRY_CONSUME(TOKEN_COLON, "$if needs a ':' after the expression, did you forget it?");
|
||||
ast->ct_if_stmt.then = TRY_AST(parse_ct_compound_stmt(context));
|
||||
if (TOKEN_IS(TOKEN_CT_ELIF))
|
||||
{
|
||||
ast->ct_if_stmt.elif = TRY_AST(parse_ct_elif_stmt(context));
|
||||
@@ -690,6 +707,9 @@ static inline Ast* parse_ct_if_stmt(Context *context)
|
||||
{
|
||||
ast->ct_if_stmt.elif = TRY_AST(parse_ct_else_stmt(context));
|
||||
}
|
||||
advance_and_verify(context, TOKEN_CT_ENDIF);
|
||||
RANGE_EXTEND_PREV(ast);
|
||||
TRY_CONSUME_EOS();
|
||||
return ast;
|
||||
}
|
||||
|
||||
@@ -774,7 +794,7 @@ static inline Ast* parse_ct_for_stmt(Context *context)
|
||||
}
|
||||
|
||||
/**
|
||||
* CTSWITCH '(' expression ')' '{' ct_switch_body '}'
|
||||
* CTSWITCH '(' expression ')' ':' '{' ct_switch_body '}'
|
||||
*
|
||||
* ct_switch_body
|
||||
* : ct_case_statement
|
||||
@@ -793,7 +813,29 @@ static inline Ast* parse_ct_switch_stmt(Context *context)
|
||||
Ast *ast = AST_NEW_TOKEN(AST_CT_SWITCH_STMT, context->tok);
|
||||
advance_and_verify(context, TOKEN_CT_SWITCH);
|
||||
ast->ct_switch_stmt.cond = TRY_EXPR_OR(parse_const_paren_expr(context), poisoned_ast);
|
||||
if (!parse_switch_body(context, &ast->ct_switch_stmt.body, TOKEN_CT_CASE, TOKEN_CT_DEFAULT)) return poisoned_ast;
|
||||
TRY_CONSUME(TOKEN_COLON, "Expected ':' after $switch expression, did you forget it?");
|
||||
Ast **cases = NULL;
|
||||
while (!try_consume(context, TOKEN_CT_ENDSWITCH))
|
||||
{
|
||||
Ast *result;
|
||||
TokenType next = context->tok.type;
|
||||
if (next == TOKEN_CT_CASE)
|
||||
{
|
||||
result = TRY_AST_OR(parse_case_stmt(context, TOKEN_CT_CASE, TOKEN_CT_DEFAULT), poisoned_ast);
|
||||
}
|
||||
else if (next == TOKEN_CT_DEFAULT)
|
||||
{
|
||||
result = TRY_AST_OR(parse_default_stmt(context, TOKEN_CT_CASE, TOKEN_CT_DEFAULT), poisoned_ast);
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_TOKEN_ERROR(context->tok, "A '$case' or '$default' would be needed here, '%.*s' is not allowed.", TOKLEN(context->tok.id), TOKSTR(context->tok.id));
|
||||
return poisoned_ast;
|
||||
}
|
||||
vec_add(cases, result);
|
||||
}
|
||||
TRY_CONSUME_EOS();
|
||||
ast->ct_switch_stmt.body = cases;
|
||||
return ast;
|
||||
}
|
||||
|
||||
@@ -872,6 +914,9 @@ Ast *parse_stmt(Context *context)
|
||||
case TOKEN_C_ULONGLONG:
|
||||
case TOKEN_TYPEID:
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
case TOKEN_HASH_TYPE_IDENT:
|
||||
case TOKEN_HASH_CONST_IDENT:
|
||||
case TOKEN_HASH_IDENT:
|
||||
case TOKEN_TYPE_IDENT:
|
||||
case TOKEN_ERR:
|
||||
case TOKEN_IDENT:
|
||||
@@ -1038,6 +1083,8 @@ Ast *parse_stmt(Context *context)
|
||||
case TOKEN_CT_ELIF:
|
||||
case TOKEN_CT_ELSE:
|
||||
case TOKEN_CT_DEFAULT:
|
||||
case TOKEN_CT_ENDIF:
|
||||
case TOKEN_CT_ENDSWITCH:
|
||||
case TOKEN_RPARBRA:
|
||||
case TOKEN_IN:
|
||||
case TOKEN_BANGBANG:
|
||||
|
||||
@@ -56,7 +56,7 @@ Expr *parse_type_access_expr_after_type(Context *context, TypeInfo *type_info);
|
||||
bool parse_next_is_decl(Context *context);
|
||||
bool parse_next_is_case_type(Context *context);
|
||||
bool parse_module(Context *context);
|
||||
|
||||
Decl *parse_define_compile_time_variable(Context *context, bool global);
|
||||
bool try_consume(Context *context, TokenType type);
|
||||
bool consume(Context *context, TokenType type, const char *message, ...);
|
||||
bool consume_const_name(Context *context, const char* type);
|
||||
|
||||
@@ -34,11 +34,6 @@ static bool sema_type_mismatch(Context *context, Expr *expr, Type *type, CastTyp
|
||||
SEMA_ERROR(expr, "A raw type cannot be used in an expression. Add the suffix '.typeid' to use it as a value.");
|
||||
return false;
|
||||
}
|
||||
if (expr_type == type_member)
|
||||
{
|
||||
SEMA_ERROR(expr, "A raw member reference cannot be used in an expression.");
|
||||
return false;
|
||||
}
|
||||
const char *action = "";
|
||||
switch (cast_type)
|
||||
{
|
||||
|
||||
@@ -560,43 +560,15 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl)
|
||||
|
||||
|
||||
|
||||
static inline bool expr_is_constant_eval(Expr *expr)
|
||||
{
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_CONST:
|
||||
return true;
|
||||
case EXPR_COMPOUND_LITERAL:
|
||||
return expr_is_constant_eval(expr->expr_compound_literal.initializer);
|
||||
case EXPR_INITIALIZER_LIST:
|
||||
{
|
||||
Expr** init_exprs = expr->expr_initializer.initializer_expr;
|
||||
switch (expr->expr_initializer.init_type)
|
||||
{
|
||||
case INITIALIZER_NORMAL:
|
||||
{
|
||||
VECEACH(init_exprs, i)
|
||||
{
|
||||
if (!expr_is_constant_eval(init_exprs[i])) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_global(Context *context, Decl *decl)
|
||||
{
|
||||
if (decl->var.kind == VARDECL_CONST_CT) return true;
|
||||
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||
decl->type = decl->var.type_info->type;
|
||||
if (decl->var.init_expr)
|
||||
if (decl->var.type_info)
|
||||
{
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||
decl->type = decl->var.type_info->type;
|
||||
}
|
||||
if (decl->var.init_expr && decl->type)
|
||||
{
|
||||
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false;
|
||||
if (!expr_is_constant_eval(decl->var.init_expr))
|
||||
@@ -605,7 +577,12 @@ static inline bool sema_analyse_global(Context *context, Decl *decl)
|
||||
SEMA_ERROR(decl->var.init_expr, "The expression must be a constant value.");
|
||||
return false;
|
||||
}
|
||||
if (!decl->type) decl->type = decl->var.init_expr->type;
|
||||
}
|
||||
// We expect a constant to actually be parsed correctly so that it has a value, so
|
||||
// this should always be true.
|
||||
assert(decl->type || decl->var.kind == VARDECL_CONST);
|
||||
|
||||
AttributeDomain domain = decl->var.kind == VARDECL_CONST ? ATTR_CONST : ATTR_FUNC;
|
||||
VECEACH(decl->attributes, i)
|
||||
{
|
||||
@@ -661,6 +638,13 @@ static inline bool sema_analyse_generic(Context *context, Decl *decl)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_define(Context *context, Decl *decl)
|
||||
{
|
||||
Path *path = decl->generic_decl.path;
|
||||
TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline bool sema_analyse_error(Context *context __unused, Decl *decl)
|
||||
@@ -748,6 +732,9 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
case DECL_GENERIC:
|
||||
if (!sema_analyse_generic(context, decl)) return decl_poison(decl);
|
||||
break;
|
||||
case DECL_DEFINE:
|
||||
if (!sema_analyse_define(context, decl)) return decl_poison(decl);
|
||||
break;
|
||||
case DECL_ATTRIBUTE:
|
||||
TODO
|
||||
case DECL_POISONED:
|
||||
@@ -760,7 +747,6 @@ bool sema_analyse_decl(Context *context, Decl *decl)
|
||||
case DECL_CT_SWITCH:
|
||||
case DECL_CT_CASE:
|
||||
case DECL_CT_IF:
|
||||
case DECL_DEFINE:
|
||||
UNREACHABLE
|
||||
}
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -154,6 +154,7 @@ bool sema_add_member(Context *context, Decl *decl)
|
||||
{
|
||||
return sema_append_local(context, decl);
|
||||
}
|
||||
|
||||
bool sema_add_local(Context *context, Decl *decl)
|
||||
{
|
||||
Decl *dummy;
|
||||
|
||||
@@ -146,6 +146,10 @@ void sema_analysis_pass_decls(Context *context)
|
||||
{
|
||||
sema_analyse_decl(context, context->functions[i]);
|
||||
}
|
||||
VECEACH(context->generic_defines, i)
|
||||
{
|
||||
sema_analyse_decl(context, context->generic_defines[i]);
|
||||
}
|
||||
DEBUG_LOG("Pass finished with %d error(s).", diagnostics.errors);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ AstId context_start_defer(Context *context)
|
||||
|
||||
static inline bool sema_analyse_block_return_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
assert(context->current_scope->flags & SCOPE_EXPR_BLOCK);
|
||||
assert(context->current_scope->flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO));
|
||||
context->current_scope->jump_end = true;
|
||||
if (statement->return_stmt.expr)
|
||||
{
|
||||
@@ -138,7 +138,7 @@ static inline bool sema_analyse_block_return_stmt(Context *context, Ast *stateme
|
||||
static inline bool sema_analyse_return_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
// This might be a return in a function block or a macro which must be treated differently.
|
||||
if (context->current_scope->flags & SCOPE_EXPR_BLOCK)
|
||||
if (context->current_scope->flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO))
|
||||
{
|
||||
return sema_analyse_block_return_stmt(context, statement);
|
||||
}
|
||||
@@ -331,6 +331,26 @@ static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
|
||||
Decl *decl = statement->declare_stmt;
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
if (!sema_add_local(context, decl)) return decl_poison(decl);
|
||||
if (decl->var.kind == VARDECL_CONST)
|
||||
{
|
||||
Expr *init_expr = decl->var.init_expr;
|
||||
if (!init_expr)
|
||||
{
|
||||
SEMA_ERROR(decl, "Constants need to have an initial value.");
|
||||
return false;
|
||||
}
|
||||
if (init_expr->expr_kind == EXPR_TYPEINFO && init_expr->type_expr->resolve_status == RESOLVE_DONE
|
||||
&& init_expr->type_expr->type->type_kind == TYPE_VOID)
|
||||
{
|
||||
SEMA_ERROR(decl, "Constants cannot be undefined.");
|
||||
return false;
|
||||
}
|
||||
if (!decl->var.type_info)
|
||||
{
|
||||
// Skip further evaluation.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!sema_resolve_type_info(context, decl->var.type_info)) return decl_poison(decl);
|
||||
decl->type = decl->var.type_info->type;
|
||||
if (decl->var.init_expr)
|
||||
@@ -357,19 +377,61 @@ static inline bool sema_analyse_declare_stmt(Context *context, Ast *statement)
|
||||
static inline bool sema_analyse_define_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
Decl *decl = statement->declare_stmt;
|
||||
statement->ast_kind = AST_NOP_STMT;
|
||||
assert(decl->decl_kind == DECL_VAR);
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
case VARDECL_LOCAL_CT_TYPE:
|
||||
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||
break;
|
||||
case VARDECL_LOCAL:
|
||||
if (decl->var.init_expr) TODO;
|
||||
TODO
|
||||
case VARDECL_LOCAL_CT:
|
||||
if (decl->var.type_info && !sema_resolve_type_info(context, decl->var.type_info)) return false;
|
||||
if (decl->var.type_info)
|
||||
{
|
||||
decl->type = decl->var.type_info->type->canonical;
|
||||
if (!type_is_builtin(decl->type->type_kind))
|
||||
{
|
||||
SEMA_ERROR(decl->var.type_info, "Compile time variables may only be built-in types.");
|
||||
return false;
|
||||
}
|
||||
if (decl->var.init_expr)
|
||||
{
|
||||
if (!sema_analyse_expr_of_required_type(context, decl->type, decl->var.init_expr, false)) return false;
|
||||
if (decl->var.init_expr->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression here.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TODO // generate.
|
||||
// decl->var.init_expr =
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (decl->var.init_expr)
|
||||
{
|
||||
if (!sema_analyse_expr(context, NULL, decl->var.init_expr)) return false;
|
||||
if (decl->var.init_expr->expr_kind != EXPR_CONST)
|
||||
{
|
||||
SEMA_ERROR(decl->var.init_expr, "Expected a constant expression here.");
|
||||
return false;
|
||||
}
|
||||
decl->type = decl->var.init_expr->type;
|
||||
}
|
||||
else
|
||||
{
|
||||
decl->type = type_void;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
TODO;
|
||||
decl->var.scope = context->current_scope;
|
||||
return sema_add_local(context, decl);
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_expr_stmt(Context *context, Ast *statement)
|
||||
@@ -1398,6 +1460,20 @@ static bool sema_analyse_compound_stmt(Context *context, Ast *statement)
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool sema_analyse_ct_compound_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
bool all_ok = ast_ok(statement);
|
||||
VECEACH(statement->ct_compound_stmt, i)
|
||||
{
|
||||
if (!sema_analyse_statement(context, statement->ct_compound_stmt[i]))
|
||||
{
|
||||
ast_poison(statement->ct_compound_stmt[i]);
|
||||
all_ok = false;
|
||||
}
|
||||
}
|
||||
return all_ok;
|
||||
}
|
||||
|
||||
static inline bool sema_analyse_statement_inner(Context *context, Ast *statement)
|
||||
{
|
||||
if (statement->ast_kind == AST_POISONED)
|
||||
@@ -1437,6 +1513,8 @@ static inline bool sema_analyse_statement_inner(Context *context, Ast *statement
|
||||
return sema_analyse_continue_stmt(context, statement);
|
||||
case AST_CT_ASSERT:
|
||||
return sema_analyse_ct_assert_stmt(context, statement);
|
||||
case AST_CT_COMPOUND_STMT:
|
||||
return sema_analyse_ct_compound_stmt(context, statement);
|
||||
case AST_CT_IF_STMT:
|
||||
return sema_analyse_ct_if_stmt(context, statement);
|
||||
case AST_DECLARE_STMT:
|
||||
|
||||
@@ -44,6 +44,7 @@ const char *kw_nameof;
|
||||
const char *kw_qnameof;
|
||||
const char *kw_kindof;
|
||||
const char *kw_len;
|
||||
const char *kw_ordinal;
|
||||
|
||||
void symtab_init(uint32_t capacity)
|
||||
{
|
||||
@@ -85,6 +86,7 @@ void symtab_init(uint32_t capacity)
|
||||
kw_qnameof = KW_DEF("qnameof");
|
||||
kw_kindof = KW_DEF("kindof");
|
||||
kw_len = KW_DEF("len");
|
||||
kw_ordinal = KW_DEF("ordinal");
|
||||
attribute_list[ATTRIBUTE_INLINE] = KW_DEF("inline");
|
||||
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");
|
||||
attribute_list[ATTRIBUTE_STDCALL] = KW_DEF("stdcall");
|
||||
|
||||
@@ -148,6 +148,12 @@ const char *token_type_to_string(TokenType type)
|
||||
return "CT_CONST_IDENT";
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
return "CT_TYPE_IDENT";
|
||||
case TOKEN_HASH_IDENT:
|
||||
return "HASH_IDENT";
|
||||
case TOKEN_HASH_CONST_IDENT:
|
||||
return "HASH_CONST_IDENT";
|
||||
case TOKEN_HASH_TYPE_IDENT:
|
||||
return "HASH_TYPE_IDENT";
|
||||
case TOKEN_CONST_IDENT:
|
||||
return "CONST_IDENT";
|
||||
case TOKEN_TYPE_IDENT:
|
||||
@@ -338,6 +344,10 @@ const char *token_type_to_string(TokenType type)
|
||||
return "$else";
|
||||
case TOKEN_CT_ELIF:
|
||||
return "$elif";
|
||||
case TOKEN_CT_ENDIF:
|
||||
return "$endif";
|
||||
case TOKEN_CT_ENDSWITCH:
|
||||
return "$endswitch";
|
||||
case TOKEN_CT_IF:
|
||||
return "$if";
|
||||
case TOKEN_CT_SWITCH:
|
||||
|
||||
@@ -10,7 +10,7 @@ static Type t_f32, t_f64, t_fxx;
|
||||
static Type t_usz, t_isz;
|
||||
static Type t_cus, t_cui, t_cul, t_cull;
|
||||
static Type t_cs, t_ci, t_cl, t_cll;
|
||||
static Type t_voidstar, t_typeid, t_error, t_typeinfo, t_member;
|
||||
static Type t_voidstar, t_typeid, t_error, t_typeinfo;
|
||||
|
||||
Type *type_bool = &t_u1;
|
||||
Type *type_void = &t_u0;
|
||||
@@ -20,7 +20,6 @@ Type *type_float = &t_f32;
|
||||
Type *type_double = &t_f64;
|
||||
Type *type_typeid = &t_typeid;
|
||||
Type *type_typeinfo = &t_typeinfo;
|
||||
Type *type_member = &t_member;
|
||||
Type *type_char = &t_i8;
|
||||
Type *type_short = &t_i16;
|
||||
Type *type_int = &t_i32;
|
||||
@@ -488,7 +487,6 @@ type_create(#_name, &_shortname, _type, _bits, target->align_ ## _align, target-
|
||||
#undef DEF_TYPE
|
||||
|
||||
type_create("typeinfo", &t_typeinfo, TYPE_TYPEINFO, 0, 0, 0);
|
||||
type_create("member", &t_member, TYPE_MEMBER, 0, 0, 0);
|
||||
type_create("typeid", &t_typeid, TYPE_TYPEID, target->width_pointer, target->align_pref_pointer, target->align_pointer);
|
||||
type_create("void*", &t_voidstar, TYPE_POINTER, target->width_pointer, target->align_pref_pointer, target->align_pointer);
|
||||
create_type_cache(type_void);
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
const byte AA = ~0;
|
||||
const byte BB = 200 ;
|
||||
const uint CC = ~0;
|
||||
const uint DD = $FOO;
|
||||
const uint DD = FOO;
|
||||
|
||||
const $FOO = ~0;
|
||||
const FOO = ~0;
|
||||
|
||||
uint x = AA;
|
||||
uint z = CC;
|
||||
byte w = $FOO;
|
||||
ushort v = $FOO;
|
||||
byte w = FOO;
|
||||
ushort v = FOO;
|
||||
uint z2 = DD;
|
||||
|
||||
func void test()
|
||||
{
|
||||
int xx = $FOO;
|
||||
int xx = FOO;
|
||||
int* yy = &&FOO;
|
||||
}
|
||||
|
||||
// #expect: constants.ll
|
||||
@@ -30,5 +31,9 @@ func void test()
|
||||
|
||||
entry:
|
||||
%xx = alloca i32
|
||||
%yy = alloca i32*
|
||||
%taddr = alloca i32
|
||||
store i32 -1, i32* %xx
|
||||
store i32 -1, i32* %taddr
|
||||
store i32* %taddr, i32** %yy
|
||||
ret void
|
||||
@@ -11,8 +11,8 @@ func void test1()
|
||||
test2(a); // #error: Cannot implicitly cast 'int' to 'char'.
|
||||
test2(100 + a); // #error: Cannot implicitly cast 'int' to 'char'.
|
||||
|
||||
const int x = 120;
|
||||
test2(x); // #error: Cannot implicitly cast 'int' to 'char'.
|
||||
const int X = 120;
|
||||
test2(X); // #error: Cannot implicitly cast 'int' to 'char'.
|
||||
|
||||
test2(100 + 100); // #error: Cannot fit '200' into type 'char'.
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const $FOO = 3;
|
||||
$BAR = 4; // #error: Did you forget a 'const' before the name of this compile time constant?
|
||||
const FOO = 3;
|
||||
int BAR = 4; // #error: This looks like a constant variable, did you forget 'const'?
|
||||
|
||||
const $BAZ = "ofke";
|
||||
const BAZ = "ofke";
|
||||
|
||||
$FOOBAR; // #error: Compile time constant unexpectedly found
|
||||
FOOBAR; // #error: Expected a top level declaration here.
|
||||
@@ -60,15 +60,17 @@ func void test8()
|
||||
|
||||
func void test9()
|
||||
{
|
||||
const char a = 1; // TODO should be "A"
|
||||
char b = a;
|
||||
a = b; // #error: Expression is not assignable
|
||||
const char A = 1;
|
||||
char b = A;
|
||||
A = b; // #error: Expression is not assignable
|
||||
}
|
||||
|
||||
func void test10()
|
||||
{
|
||||
const char a = 1;
|
||||
char* b = &a; // #error: address of values
|
||||
const char B = 1;
|
||||
char* c = &B;
|
||||
const A = 1;
|
||||
char* b = &A; // #error: To take the address of a temporary value, use '&&' instead of '&'
|
||||
}
|
||||
|
||||
enum Enum : int
|
||||
@@ -181,4 +183,16 @@ int[2][3] b123;
|
||||
func void test24()
|
||||
{
|
||||
int a = b123; // #error: cast 'int[2][3]' to 'int'
|
||||
}
|
||||
}
|
||||
|
||||
func void test25()
|
||||
{
|
||||
const A = void; // #error: Constants cannot be undefined.
|
||||
}
|
||||
|
||||
func void test26()
|
||||
{
|
||||
const int A = void; // #error: Constants cannot be undefined.
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user