mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Added $converable / $castable. Simplify and corrected if try/catch parsing. Fix bug with { [A] = 1 }
This commit is contained in:
committed by
Christoffer Lerno
parent
7e0a29ef40
commit
812bd8b3d0
@@ -260,6 +260,7 @@ bool expr_is_pure(Expr *expr)
|
||||
case EXPR_PTR:
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_RETVAL:
|
||||
case EXPR_CT_CONV:
|
||||
return true;
|
||||
case EXPR_ARGV_TO_SUBARRAY:
|
||||
case EXPR_BITASSIGN:
|
||||
|
||||
@@ -792,10 +792,18 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
TokenType token_type;
|
||||
struct
|
||||
union
|
||||
{
|
||||
Expr *main_var;
|
||||
ExprFlatElement *flat_path;
|
||||
struct
|
||||
{
|
||||
Expr *main_var;
|
||||
ExprFlatElement *flat_path;
|
||||
};
|
||||
struct
|
||||
{
|
||||
TypeInfoId type_from;
|
||||
TypeInfoId type_to;
|
||||
};
|
||||
};
|
||||
} ExprCtCall;
|
||||
|
||||
@@ -1613,6 +1621,8 @@ extern const char *kw_min;
|
||||
extern const char *kw_elements;
|
||||
extern const char *kw_align;
|
||||
|
||||
extern const char *kw_castable;
|
||||
extern const char *kw_convertable;
|
||||
extern const char *kw_sizeof;
|
||||
extern const char *kw_in;
|
||||
extern const char *kw_out;
|
||||
@@ -2536,6 +2546,7 @@ const char *arch_to_linker_arch(ArchType arch);
|
||||
#define ASSIGN_EXPR_OR_RET(_assign, _expr_stmt, _res) Expr* TEMP(_expr) = (_expr_stmt); if (!expr_ok(TEMP(_expr))) return _res; _assign = TEMP(_expr)
|
||||
#define ASSIGN_EXPRID_OR_RET(_assign, _expr_stmt, _res) Expr* TEMP(_expr) = (_expr_stmt); if (!expr_ok(TEMP(_expr))) return _res; _assign = exprid(TEMP(_expr))
|
||||
#define ASSIGN_TYPE_OR_RET(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = TEMP(_type)
|
||||
#define ASSIGN_TYPEID_OR_RET(_assign, _type_stmt, _res) TypeInfo* TEMP(_type) = (_type_stmt); if (!type_info_ok(TEMP(_type))) return _res; _assign = type_infoid(TEMP(_type))
|
||||
#define ASSIGN_DECL_OR_RET(_assign, _decl_stmt, _res) Decl* TEMP(_decl) = (_decl_stmt); if (!decl_ok(TEMP(_decl))) return _res; _assign = TEMP(_decl)
|
||||
|
||||
|
||||
|
||||
@@ -184,6 +184,10 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
case EXPR_BUILTIN:
|
||||
case EXPR_RETVAL:
|
||||
return expr;
|
||||
case EXPR_CT_CONV:
|
||||
MACRO_COPY_TYPEID(expr->ct_call_expr.type_from);
|
||||
MACRO_COPY_TYPEID(expr->ct_call_expr.type_to);
|
||||
return expr;
|
||||
case EXPR_DECL:
|
||||
MACRO_COPY_DECL(expr->decl_expr);
|
||||
return expr;
|
||||
|
||||
@@ -210,6 +210,7 @@ typedef enum
|
||||
EXPR_COMPOUND_LITERAL,
|
||||
EXPR_CONST,
|
||||
EXPR_CT_CALL,
|
||||
EXPR_CT_CONV,
|
||||
EXPR_CT_IDENT,
|
||||
EXPR_CT_EVAL,
|
||||
EXPR_COND,
|
||||
@@ -526,6 +527,8 @@ typedef enum
|
||||
TOKEN_CT_STRINGIFY, // $stringify
|
||||
TOKEN_CT_SWITCH, // $switch
|
||||
TOKEN_CT_TYPEOF, // $typeof
|
||||
TOKEN_CT_CONVERTABLE, // $convertable
|
||||
TOKEN_CT_CASTABLE, // $castable
|
||||
|
||||
TOKEN_DOCS_START, // /**
|
||||
TOKEN_DOCS_END, // */ (may start with an arbitrary number of `*`
|
||||
|
||||
@@ -5567,6 +5567,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
case NON_RUNTIME_EXPR:
|
||||
case EXPR_COND:
|
||||
case EXPR_CT_CONV:
|
||||
UNREACHABLE
|
||||
case EXPR_RETVAL:
|
||||
*value = c->retval;
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#define IF_TRY_CATCH_PREC (PREC_AND + 1)
|
||||
typedef Expr *(*ParseFn)(ParseContext *context, Expr *);
|
||||
static Expr *parse_expr_or_type_prec(ParseContext *c, TypeInfo **type_ref, Precedence prec);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -83,10 +82,10 @@ static inline Expr *parse_catch_unwrap(ParseContext *c)
|
||||
Expr *expr = expr_new(EXPR_CATCH_UNWRAP, c->span);
|
||||
advance_and_verify(c, TOKEN_CATCH);
|
||||
TypeInfo *type = NULL;
|
||||
ASSIGN_EXPR_OR_RET(Expr * lhs, parse_expr_or_type_prec(c, &type, IF_TRY_CATCH_PREC), poisoned_expr);
|
||||
if (!lhs)
|
||||
ASSIGN_EXPR_OR_RET(Expr * lhs, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr);
|
||||
if (lhs->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(expr->catch_unwrap_expr.type, type, poisoned_expr);
|
||||
expr->catch_unwrap_expr.type = lhs->type_expr;
|
||||
ASSIGN_EXPR_OR_RET(expr->catch_unwrap_expr.variable, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr);
|
||||
}
|
||||
else
|
||||
@@ -131,18 +130,17 @@ static inline Expr *parse_try_unwrap(ParseContext *c)
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_TRY_UNWRAP);
|
||||
advance_and_verify(c, TOKEN_TRY);
|
||||
TypeInfo *type = NULL;
|
||||
ASSIGN_EXPR_OR_RET(Expr * lhs, parse_expr_or_type_prec(c, &type, IF_TRY_CATCH_PREC), poisoned_expr);
|
||||
if (!lhs)
|
||||
ASSIGN_EXPR_OR_RET(Expr *lhs, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr);
|
||||
if (lhs->expr_kind == EXPR_TYPEINFO)
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(expr->try_unwrap_expr.type, type, poisoned_expr);
|
||||
expr->try_unwrap_expr.type = lhs->type_expr;
|
||||
ASSIGN_EXPR_OR_RET(expr->try_unwrap_expr.variable, parse_precedence(c, IF_TRY_CATCH_PREC), poisoned_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
expr->try_unwrap_expr.variable = lhs;
|
||||
}
|
||||
if (type && expr->try_unwrap_expr.variable->expr_kind != EXPR_IDENTIFIER)
|
||||
if (lhs->expr_kind == EXPR_TYPEINFO && expr->try_unwrap_expr.variable->expr_kind != EXPR_IDENTIFIER)
|
||||
{
|
||||
SEMA_ERROR(expr->try_unwrap_expr.variable, "A new variable was expected.");
|
||||
return poisoned_expr;
|
||||
@@ -910,6 +908,21 @@ static Expr *parse_ct_call(ParseContext *c, Expr *left)
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_ct_conv(ParseContext *c, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_CONV);
|
||||
expr->ct_call_expr.token_type = c->tok;
|
||||
advance(c);
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_expr);
|
||||
ASSIGN_TYPEID_OR_RET(expr->ct_call_expr.type_from, parse_type(c), poisoned_expr);
|
||||
TRY_CONSUME_AFTER(TOKEN_COMMA, "Expected ',' here.", poisoned_expr);
|
||||
ASSIGN_TYPEID_OR_RET(expr->ct_call_expr.type_to, parse_type(c), poisoned_expr);
|
||||
TRY_CONSUME_AFTER(TOKEN_RPAREN, "Expected ')' here.", poisoned_expr);
|
||||
RANGE_EXTEND_PREV(expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_identifier(ParseContext *c, Expr *left)
|
||||
{
|
||||
assert(!left && "Unexpected left hand side");
|
||||
@@ -926,90 +939,6 @@ static Expr *parse_identifier(ParseContext *c, Expr *left)
|
||||
return expr;
|
||||
}
|
||||
|
||||
static Expr *parse_type_or_expression_with_path(ParseContext *c, Path *path, TypeInfo **type_ref)
|
||||
{
|
||||
TypeInfo *type;
|
||||
if (path)
|
||||
{
|
||||
type = type_info_new(TYPE_INFO_IDENTIFIER, path->span);
|
||||
type->unresolved.path = path;
|
||||
type->unresolved.name = symstr(c);
|
||||
advance_and_verify(c, TOKEN_TYPE_IDENT);
|
||||
RANGE_EXTEND_PREV(type);
|
||||
ASSIGN_TYPE_OR_RET(type, parse_type_with_base(c, type), poisoned_expr);
|
||||
type->failable = try_consume(c, TOKEN_BANG);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIGN_TYPE_OR_RET(type, parse_failable_type(c), poisoned_expr);
|
||||
}
|
||||
if (tok_is(c, TOKEN_LBRACE))
|
||||
{
|
||||
return parse_type_compound_literal_expr_after_type(c, type);
|
||||
}
|
||||
if (tok_is(c, TOKEN_DOT))
|
||||
{
|
||||
Expr *expr = expr_new(EXPR_TYPEINFO, type->span);
|
||||
expr->type_expr = type;
|
||||
return parse_access_expr(c, expr);
|
||||
}
|
||||
*type_ref = type;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static Expr *parse_expr_or_type_prec(ParseContext *c, TypeInfo **type_ref, Precedence prec)
|
||||
{
|
||||
switch (c->tok)
|
||||
{
|
||||
case TYPELIKE_TOKENS:
|
||||
return parse_type_or_expression_with_path(c, NULL, type_ref);
|
||||
case TOKEN_IDENT:
|
||||
{
|
||||
bool had_error;
|
||||
Path *path = parse_path_prefix(c, &had_error);
|
||||
if (had_error) return poisoned_expr;
|
||||
if (!path) return parse_precedence(c, prec);
|
||||
bool is_const = false;
|
||||
switch (c->tok)
|
||||
{
|
||||
case TOKEN_TYPE_IDENT:
|
||||
return parse_type_or_expression_with_path(c, path, type_ref);
|
||||
case TOKEN_CONST_IDENT:
|
||||
is_const = true;
|
||||
FALLTHROUGH;
|
||||
case TOKEN_IDENT:
|
||||
{
|
||||
Expr *expr = EXPR_NEW_TOKEN(EXPR_IDENTIFIER);
|
||||
expr->identifier_expr.ident = symstr(c);
|
||||
expr->identifier_expr.is_const = is_const;
|
||||
expr->identifier_expr.path = path;
|
||||
advance(c);
|
||||
return parse_precedence_with_left_side(c, expr, prec);
|
||||
}
|
||||
case TOKEN_HASH_IDENT:
|
||||
case TOKEN_HASH_CONST_IDENT:
|
||||
case TOKEN_HASH_TYPE_IDENT:
|
||||
case TOKEN_CT_CONST_IDENT:
|
||||
case TOKEN_CT_IDENT:
|
||||
case TOKEN_CT_TYPE_IDENT:
|
||||
SEMA_ERROR_HERE("'%s' cannot be used with paths.", symstr(c));
|
||||
return poisoned_expr;
|
||||
default:
|
||||
SEMA_ERROR_HERE("An identifier was expected after the path.");
|
||||
return poisoned_expr;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return parse_precedence(c, prec);
|
||||
}
|
||||
}
|
||||
|
||||
Expr *parse_expr_or_type(ParseContext *c, TypeInfo **type_ref)
|
||||
{
|
||||
return parse_expr_or_type_prec(c, type_ref, PREC_ASSIGNMENT);
|
||||
}
|
||||
|
||||
static Expr *parse_identifier_starting_expression(ParseContext *c, Expr *left)
|
||||
{
|
||||
@@ -1795,5 +1724,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
|
||||
[TOKEN_CT_TYPEOF] = { parse_type_expr, NULL, PREC_NONE },
|
||||
[TOKEN_CT_STRINGIFY] = { parse_ct_stringify, NULL, PREC_NONE },
|
||||
[TOKEN_CT_EVALTYPE] = { parse_type_expr, NULL, PREC_NONE },
|
||||
[TOKEN_CT_CONVERTABLE] = { parse_ct_conv, NULL, PREC_NONE },
|
||||
[TOKEN_CT_CASTABLE] = { parse_ct_conv, NULL, PREC_NONE },
|
||||
[TOKEN_LBRACE] = { parse_initializer_list, NULL, PREC_NONE },
|
||||
};
|
||||
|
||||
@@ -788,9 +788,9 @@ Decl *parse_decl(ParseContext *c)
|
||||
Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref)
|
||||
{
|
||||
TypeInfo *type_info;
|
||||
Expr *expr = parse_expr_or_type(c, &type_info);
|
||||
if (expr) return expr;
|
||||
ASSIGN_DECL_OR_RET(*decl_ref, parse_decl_after_type(c, type_info), poisoned_expr);
|
||||
Expr *expr = parse_expr(c);
|
||||
if (expr->expr_kind != EXPR_TYPEINFO) return expr;
|
||||
ASSIGN_DECL_OR_RET(*decl_ref, parse_decl_after_type(c, expr->type_expr), poisoned_expr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1034,6 +1034,8 @@ Ast *parse_stmt(ParseContext *c)
|
||||
case TOKEN_RVEC:
|
||||
case TOKEN_CT_ENDFOR:
|
||||
case TOKEN_CT_ENDFOREACH:
|
||||
case TOKEN_CT_CASTABLE:
|
||||
case TOKEN_CT_CONVERTABLE:
|
||||
SEMA_ERROR_HERE("Unexpected '%s' found when expecting a statement.",
|
||||
token_type_to_string(c->tok));
|
||||
advance(c);
|
||||
|
||||
@@ -53,7 +53,6 @@ bool try_consume(ParseContext *c, TokenType type);
|
||||
bool consume(ParseContext *c, TokenType type, const char *message, ...);
|
||||
bool consume_const_name(ParseContext *c, const char* type);
|
||||
Expr *parse_precedence_with_left_side(ParseContext *c, Expr *left_side, Precedence precedence);
|
||||
Expr *parse_expr_or_type(ParseContext *c, TypeInfo **type_ref);
|
||||
|
||||
INLINE const char *symstr(ParseContext *c)
|
||||
{
|
||||
|
||||
@@ -837,6 +837,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type)
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_VARIANT:
|
||||
case EXPR_CT_CONV:
|
||||
UNREACHABLE
|
||||
case EXPR_POST_UNARY:
|
||||
return recursive_may_narrow_float(expr->unary_expr.expr, type);
|
||||
@@ -991,6 +992,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type)
|
||||
case EXPR_STRINGIFY:
|
||||
case EXPR_CT_EVAL:
|
||||
case EXPR_VARIANT:
|
||||
case EXPR_CT_CONV:
|
||||
UNREACHABLE
|
||||
case EXPR_POST_UNARY:
|
||||
return recursive_may_narrow_int(expr->unary_expr.expr, type);
|
||||
|
||||
@@ -315,6 +315,8 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
|
||||
RETRY:
|
||||
switch (expr->expr_kind)
|
||||
{
|
||||
case EXPR_CT_CONV:
|
||||
return true;
|
||||
case EXPR_RETVAL:
|
||||
return false;
|
||||
case EXPR_BUILTIN:
|
||||
@@ -3820,7 +3822,7 @@ static Decl *sema_resolve_element_for_name(Decl** decls, DesignatorElement **ele
|
||||
|
||||
static MemberIndex sema_analyse_designator_index(SemaContext *context, Expr *index)
|
||||
{
|
||||
if (!sema_analyse_expr_lvalue(context, index))
|
||||
if (!sema_analyse_expr(context, index))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
@@ -7296,6 +7298,42 @@ static inline bool sema_expr_analyse_ct_call(SemaContext *context, Expr *expr)
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_ct_conv(SemaContext *c, Expr *expr)
|
||||
{
|
||||
TypeInfo *from = type_infoptr(expr->ct_call_expr.type_from);
|
||||
TypeInfo *to = type_infoptr(expr->ct_call_expr.type_to);
|
||||
if (!sema_resolve_type_info(c, from)) return false;
|
||||
if (!sema_resolve_type_info(c, to)) return false;
|
||||
Type *from_type = from->type;
|
||||
Type *to_type = to->type;
|
||||
if (IS_FAILABLE(from))
|
||||
{
|
||||
SEMA_ERROR(from, "Only non-optional types can be checked.");
|
||||
return false;
|
||||
}
|
||||
if (IS_FAILABLE(to))
|
||||
{
|
||||
SEMA_ERROR(to, "Only non-optional types can be checked.");
|
||||
return false;
|
||||
}
|
||||
bool result;
|
||||
switch (expr->ct_call_expr.token_type)
|
||||
{
|
||||
case TOKEN_CT_CONVERTABLE:
|
||||
result = cast_may_implicit(from_type, to_type, true, false);
|
||||
break;
|
||||
case TOKEN_CT_CASTABLE:
|
||||
result = cast_may_explicit(from_type, to_type, true, false);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
expr_const_set_bool(&expr->const_expr, result);
|
||||
expr->type = type_bool;
|
||||
expr->expr_kind = EXPR_CONST;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline BuiltinFunction builtin_by_name(const char *name)
|
||||
{
|
||||
@@ -7375,6 +7413,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr)
|
||||
return sema_expr_analyse_retval(context, expr);
|
||||
case EXPR_BUILTIN:
|
||||
return sema_expr_analyse_builtin(context, expr, true);
|
||||
case EXPR_CT_CONV:
|
||||
return sema_expr_analyse_ct_conv(context, expr);
|
||||
case EXPR_CT_CALL:
|
||||
return sema_expr_analyse_ct_call(context, expr);
|
||||
case EXPR_HASH_IDENT:
|
||||
|
||||
@@ -27,7 +27,6 @@ bool sema_resolve_type_info(SemaContext *context, TypeInfo *type_info)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags)
|
||||
{
|
||||
unsigned depth = context->active_scope.depth + 1;
|
||||
|
||||
@@ -43,6 +43,8 @@ const char *kw_std__core;
|
||||
const char *kw_std__core__types;
|
||||
const char *kw_typekind;
|
||||
|
||||
const char *kw_castable;
|
||||
const char *kw_convertable;
|
||||
const char *kw_in;
|
||||
const char *kw_out;
|
||||
const char *kw_inout;
|
||||
|
||||
@@ -374,6 +374,10 @@ const char *token_type_to_string(TokenType type)
|
||||
return "$switch";
|
||||
case TOKEN_CT_TYPEOF:
|
||||
return "$typeof";
|
||||
case TOKEN_CT_CONVERTABLE:
|
||||
return "$convertable";
|
||||
case TOKEN_CT_CASTABLE:
|
||||
return "$castable";
|
||||
case TOKEN_CT_STRINGIFY:
|
||||
return "$stringify";
|
||||
case TOKEN_EOF:
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.2.22"
|
||||
#define COMPILER_VERSION "0.2.23"
|
||||
Reference in New Issue
Block a user