Added $converable / $castable. Simplify and corrected if try/catch parsing. Fix bug with { [A] = 1 }

This commit is contained in:
Christoffer Lerno
2022-07-24 15:01:48 +02:00
committed by Christoffer Lerno
parent 7e0a29ef40
commit 812bd8b3d0
22 changed files with 117 additions and 132 deletions

View File

@@ -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:

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 `*`

View File

@@ -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;

View File

@@ -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 },
};

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.2.22"
#define COMPILER_VERSION "0.2.23"