commit 555bd4914dcf770a15733efdd20dd39149a8a89c
parent aa6d14a8ef21b29376b73e95065c9a44e5960ff6
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 3 Sep 2021 10:50:41 +0200
all: basic first-class type riggings
Diffstat:
13 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/include/ast.h b/include/ast.h
@@ -317,6 +317,10 @@ struct ast_expression_tuple {
struct ast_expression_tuple *next;
};
+struct ast_expression_type {
+ struct ast_type *type;
+};
+
struct ast_expression_unarithm {
enum unarithm_operator op;
struct ast_expression *operand;
@@ -324,7 +328,7 @@ struct ast_expression_unarithm {
struct ast_expression {
struct location loc;
- enum expr_type type;
+ enum expr_type type; // TODO: Rename me to "kind", and "_type" to "type"
union {
struct ast_expression_access access;
struct ast_expression_alloc alloc;
@@ -352,6 +356,7 @@ struct ast_expression {
struct ast_expression_struct _struct;
struct ast_expression_switch _switch;
struct ast_expression_tuple tuple;
+ struct ast_expression_type _type;
struct ast_expression_unarithm unarithm;
};
};
diff --git a/include/expr.h b/include/expr.h
@@ -36,6 +36,7 @@ enum expr_type {
EXPR_STRUCT,
EXPR_SWITCH,
EXPR_TUPLE,
+ EXPR_TYPE,
EXPR_UNARITHM,
EXPR_YIELD,
};
@@ -322,6 +323,10 @@ struct expression_tuple {
struct expression_tuple *next;
};
+struct expression_type {
+ const struct type *type;
+};
+
enum unarithm_operator {
UN_ADDRESS, // &
UN_BNOT, // ~
@@ -367,6 +372,7 @@ struct expression {
struct expression_switch _switch;
struct expression_struct _struct;
struct expression_slice slice;
+ struct expression_type _type;
struct expression_tuple tuple;
struct expression_unarithm unarithm;
void *user;
diff --git a/include/types.h b/include/types.h
@@ -39,6 +39,7 @@ enum type_storage {
STORAGE_TAGGED,
STORAGE_TUPLE,
STORAGE_UNION,
+ STORAGE_TYPE,
};
struct type;
diff --git a/src/check.c b/src/check.c
@@ -661,6 +661,7 @@ type_promote(struct type_store *store,
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UINTPTR:
case STORAGE_UNION:
case STORAGE_VOID:
@@ -1482,6 +1483,7 @@ check_expr_constant(struct context *ctx,
case STORAGE_SLICE:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_STRUCT:
case STORAGE_UNION:
assert(0); // Invariant
@@ -2779,6 +2781,8 @@ check_expression(struct context *ctx,
case EXPR_TUPLE:
check_expr_tuple(ctx, aexpr, expr, hint);
break;
+ case EXPR_TYPE:
+ assert(0); // TODO
case EXPR_UNARITHM:
check_expr_unarithm(ctx, aexpr, expr, hint);
break;
@@ -3111,6 +3115,8 @@ type_is_specified(struct context *ctx, const struct ast_type *atype)
}
}
return true;
+ case STORAGE_TYPE:
+ assert(0); // TODO
}
assert(0); // Unreachable
}
@@ -3296,6 +3302,8 @@ expr_is_specified(struct context *ctx, const struct ast_expression *aexpr)
}
}
return true;
+ case EXPR_TYPE:
+ return type_is_specified(ctx, aexpr->_type.type);
case EXPR_UNARITHM:
return expr_is_specified(ctx, aexpr->unarithm.operand);
case EXPR_YIELD:
diff --git a/src/eval.c b/src/eval.c
@@ -89,6 +89,7 @@ itrunc(const struct type *type, uintmax_t val)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UNION:
case STORAGE_VOID:
assert(0);
@@ -346,6 +347,7 @@ eval_const(struct context *ctx, struct expression *in, struct expression *out)
case STORAGE_POINTER:
case STORAGE_RUNE:
case STORAGE_SIZE:
+ case STORAGE_TYPE:
case STORAGE_U16:
case STORAGE_U32:
case STORAGE_U64:
@@ -456,6 +458,8 @@ eval_cast(struct context *ctx, struct expression *in, struct expression *out)
case STORAGE_TUPLE:
case STORAGE_UNION:
assert(0); // Invariant
+ case STORAGE_TYPE:
+ assert(0); // TODO
case STORAGE_VOID:
break; // no-op
}
@@ -536,6 +540,7 @@ constant_default(struct context *ctx, struct expression *v)
assert(0); // TODO
case STORAGE_ALIAS:
case STORAGE_FUNCTION:
+ case STORAGE_TYPE:
assert(0); // Invariant
case STORAGE_VOID:
break; // no-op
@@ -731,6 +736,7 @@ eval_expr(struct context *ctx, struct expression *in, struct expression *out)
case EXPR_PROPAGATE:
case EXPR_RETURN:
case EXPR_SWITCH:
+ case EXPR_TYPE: // XXX: Should this work?
case EXPR_YIELD:
// Excluded from translation-compatible subset
return EVAL_INVALID;
diff --git a/src/gen.c b/src/gen.c
@@ -1335,6 +1335,8 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr)
assert(from->storage == STORAGE_SLICE);
pushi(ctx->current, &qresult, Q_COPY, &qvalue, NULL);
break;
+ case STORAGE_TYPE:
+ assert(0); // TODO
case STORAGE_ALIAS:
case STORAGE_BOOL:
case STORAGE_FCONST:
@@ -2607,6 +2609,8 @@ gen_expr(struct gen_context *ctx, const struct expression *expr)
return gen_expr_return(ctx, expr);
case EXPR_SWITCH:
return gen_expr_switch_with(ctx, expr, NULL);
+ case EXPR_TYPE:
+ assert(0); // TODO
case EXPR_UNARITHM:
return gen_expr_unarithm(ctx, expr);
case EXPR_SLICE:
@@ -3129,6 +3133,7 @@ gen_data_item(struct gen_context *ctx, struct expression *expr,
}
break;
case STORAGE_UNION:
+ case STORAGE_TYPE:
assert(0); // TODO
case STORAGE_ALIAS:
case STORAGE_FCONST:
diff --git a/src/lex.c b/src/lex.c
@@ -1137,6 +1137,7 @@ token_str(const struct token *tok)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UNION:
case STORAGE_VOID:
assert(0);
diff --git a/src/parse.c b/src/parse.c
@@ -369,6 +369,9 @@ parse_primitive_type(struct lexer *lexer)
case T_STR:
type->storage = STORAGE_STRING;
break;
+ case T_TYPE:
+ type->storage = STORAGE_TYPE;
+ break;
case T_F32:
type->storage = STORAGE_F32;
break;
@@ -613,24 +616,25 @@ parse_type(struct lexer *lexer)
struct ast_type *type = NULL;
bool noreturn = false, nullable = false, unwrap = false;
switch (lex(lexer, &tok)) {
- case T_I8:
+ case T_BOOL:
+ case T_CHAR:
+ case T_F32:
+ case T_F64:
case T_I16:
case T_I32:
case T_I64:
- case T_U8:
+ case T_I8:
+ case T_INT:
+ case T_RUNE:
+ case T_SIZE:
+ case T_STR:
+ case T_TYPE:
case T_U16:
case T_U32:
case T_U64:
- case T_INT:
+ case T_U8:
case T_UINT:
- case T_SIZE:
case T_UINTPTR:
- case T_CHAR:
- case T_RUNE:
- case T_STR:
- case T_F32:
- case T_F64:
- case T_BOOL:
case T_VOID:
unlex(lexer, &tok);
type = parse_primitive_type(lexer);
@@ -816,6 +820,7 @@ parse_constant(struct lexer *lexer)
case STORAGE_TAGGED:
case STORAGE_TUPLE:
case STORAGE_UNION:
+ case STORAGE_TYPE:
assert(0); // Handled in a different nonterminal
}
return exp;
@@ -1129,6 +1134,20 @@ parse_measurement_expression(struct lexer *lexer)
}
static struct ast_expression *
+parse_type_expression(struct lexer *lexer)
+{
+ struct ast_expression *exp = mkexpr(&lexer->loc);
+ exp->type = EXPR_TYPE;
+ struct token tok;
+ lex(lexer, &tok);
+
+ want(lexer, T_LPAREN, NULL);
+ exp->_type.type = parse_type(lexer);
+ want(lexer, T_RPAREN, NULL);
+ return exp;
+}
+
+static struct ast_expression *
parse_call_expression(struct lexer *lexer, struct ast_expression *lvalue)
{
struct token tok;
@@ -1462,6 +1481,9 @@ parse_builtin_expression(struct lexer *lexer)
case T_OFFSET:
unlex(lexer, &tok);
return parse_measurement_expression(lexer);
+ case T_TYPE:
+ unlex(lexer, &tok);
+ return parse_type_expression(lexer);
default:
unlex(lexer, &tok);
break;
diff --git a/src/qinstr.c b/src/qinstr.c
@@ -57,6 +57,7 @@ store_for_type(struct gen_context *ctx, const struct type *type)
break;
case STORAGE_POINTER:
case STORAGE_UINTPTR:
+ case STORAGE_TYPE:
switch (ctx->arch.ptr->stype) {
case Q_LONG:
return Q_STOREL;
@@ -124,6 +125,7 @@ load_for_type(struct gen_context *ctx, const struct type *type)
break;
case STORAGE_POINTER:
case STORAGE_UINTPTR:
+ case STORAGE_TYPE:
switch (ctx->arch.ptr->stype) {
case Q_LONG:
return Q_LOADL;
diff --git a/src/qtype.c b/src/qtype.c
@@ -175,6 +175,7 @@ aggregate_lookup(struct gen_context *ctx, const struct type *type)
case STORAGE_SIZE:
case STORAGE_UINTPTR:
case STORAGE_POINTER:
+ case STORAGE_TYPE:
case STORAGE_NULL:
case STORAGE_F32:
case STORAGE_F64:
@@ -215,6 +216,7 @@ qtype_lookup(struct gen_context *ctx,
case STORAGE_UINTPTR:
case STORAGE_POINTER:
case STORAGE_NULL:
+ case STORAGE_TYPE:
return ctx->arch.ptr;
case STORAGE_F32:
return &qbe_single;
@@ -259,6 +261,7 @@ type_is_aggregate(const struct type *type)
case STORAGE_I8:
case STORAGE_INT:
case STORAGE_POINTER:
+ case STORAGE_TYPE:
case STORAGE_NULL:
case STORAGE_RUNE:
case STORAGE_SIZE:
diff --git a/src/type_store.c b/src/type_store.c
@@ -123,6 +123,7 @@ builtin_type_for_storage(enum type_storage storage, bool is_const)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UNION:
case STORAGE_ENUM:
return NULL;
@@ -702,6 +703,10 @@ type_init_from_atype(struct type_store *store,
type->pointer.referent = type_store_lookup_atype(
store, atype->pointer.referent);
break;
+ case STORAGE_TYPE:
+ type->size = 8; // XXX: ARCH
+ type->align = 8;
+ break;
case STORAGE_SLICE:
type->size = 24; // XXX: ARCH
type->align = 8;
diff --git a/src/typedef.c b/src/typedef.c
@@ -141,6 +141,7 @@ emit_const(const struct expression *expr, FILE *out)
case STORAGE_FUNCTION:
case STORAGE_POINTER:
case STORAGE_TAGGED:
+ case STORAGE_TYPE:
assert(0); // Invariant
}
}
@@ -315,6 +316,8 @@ emit_type(const struct type *type, FILE *out)
}
fprintf(out, ")");
break;
+ case STORAGE_TYPE:
+ assert(0); // TODO
case STORAGE_FCONST:
case STORAGE_ICONST:
assert(0); // Invariant
diff --git a/src/types.c b/src/types.c
@@ -150,6 +150,8 @@ type_storage_unparse(enum type_storage storage)
return "tagged union";
case STORAGE_TUPLE:
return "tuple";
+ case STORAGE_TYPE:
+ return "type";
case STORAGE_U16:
return "u16";
case STORAGE_U32:
@@ -183,6 +185,7 @@ type_is_integer(const struct type *type)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UNION:
case STORAGE_BOOL:
case STORAGE_NULL:
@@ -226,6 +229,7 @@ type_is_numeric(const struct type *type)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UNION:
case STORAGE_BOOL:
case STORAGE_CHAR:
@@ -278,6 +282,7 @@ type_storage_is_signed(enum type_storage storage)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_UNION:
case STORAGE_BOOL:
case STORAGE_CHAR:
@@ -340,6 +345,7 @@ bool storage_is_flexible(enum type_storage storage)
case STORAGE_STRUCT:
case STORAGE_TAGGED:
case STORAGE_TUPLE:
+ case STORAGE_TYPE:
case STORAGE_U16:
case STORAGE_U32:
case STORAGE_U64:
@@ -447,6 +453,9 @@ type_hash(const struct type *type)
hash = fnv1a_u32(hash, type_hash(tuple->type));
}
break;
+ case STORAGE_TYPE:
+ // Does not require any additional information
+ break;
}
return hash;
}
@@ -566,6 +575,8 @@ type_is_assignable(const struct type *to, const struct type *from)
case STORAGE_ICONST:
case STORAGE_FCONST:
assert(0); // Invariant
+ case STORAGE_TYPE:
+ assert(0); // TODO
case STORAGE_I8:
case STORAGE_I16:
case STORAGE_I32:
@@ -712,6 +723,7 @@ type_is_castable(const struct type *to, const struct type *from)
switch (from->storage) {
case STORAGE_FCONST:
case STORAGE_ICONST:
+ case STORAGE_TYPE:
assert(0); // TODO
case STORAGE_I8:
case STORAGE_I16: