NODE(TypeAlias) \
NODE(TypeRawAlias) \
NODE(CompoundType) \
+ NODE(TypeOf) \
\
NODE(Binding) \
NODE(Alias) \
Ast_Kind_Type_Alias,
Ast_Kind_Type_Raw_Alias,
Ast_Kind_Type_Compound,
+ Ast_Kind_Typeof,
Ast_Kind_Type_End,
Ast_Kind_Struct_Member,
Ast_Flag_Has_Been_Checked = BH_BIT(27),
Ast_Flag_Static_If_Resolved = BH_BIT(28),
+
+ // :TEMPORARY
+ Ast_Flag_Params_Introduced = BH_BIT(29),
} AstFlags;
typedef enum UnaryOp {
bh_arr(AstType *) types;
};
+struct AstTypeOf {
+ AstType_base;
+
+ AstTyped* expr;
+ Type* resolved_type;
+};
// Top level nodes
struct AstBinding { AstTyped_base; AstNode* node; };
Token_Type_Keyword_Continue,
Token_Type_Keyword_Sizeof,
Token_Type_Keyword_Alignof,
+ Token_Type_Keyword_Typeof,
Token_Type_Keyword_Defer,
Token_Type_Keyword_Do,
Token_Type_Keyword_Case,
# strings in YAML. When using single quoted strings, only single quotes
# need to be escaped: this is done by using two single quotes next to each
# other.
- - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|defer|switch|case|macro)\b'
+ - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|typeof|defer|switch|case|macro)\b'
scope: keyword.control.onyx
- match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr|str|cstr|range|type_expr|any)\b'
syn keyword onyxKeyword for while do
syn keyword onyxKeyword switch case
syn keyword onyxKeyword break continue return defer fallthrough
-syn keyword onyxKeyword as cast sizeof alignof
+syn keyword onyxKeyword as cast sizeof alignof typeof
syn keyword onyxType bool void
syn keyword onyxType i8 u8
syn keyword onyxType i16 u16
"TYPE_ALIAS",
"TYPE RAW ALIAS",
"COMPOUND TYPE",
+ "TYPE OF",
"TYPE_END (BAD)",
"STRUCT MEMBER",
// This is to ensure that the type will exist when compiling. For example, a poly-call type
// would have to wait for the entity to pass through, which the code generation does not know
// about.
+ if (expr->kind == Ast_Kind_Typeof) {
+ CHECK(type, (AstType *) expr);
+ }
+
if (type_build_from_ast(context.ast_alloc, (AstType*) expr) == NULL) {
return Check_Yield_Macro;
}
case Ast_Kind_Param:
if (expr->type == NULL) {
- onyx_report_error(expr->token->pos, "Parameter with unknown type. You should hopefully never see this.");
+ onyx_report_error(expr->token->pos, "Parameter with bad type.");
retval = Check_Error;
}
break;
AstTyped* typed_stmt = (AstTyped *) stmt;
fill_in_type(typed_stmt);
if (typed_stmt->type_node != NULL && typed_stmt->type == NULL) {
+ CHECK(type, typed_stmt->type_node);
+
if (!node_is_type((AstNode *) typed_stmt->type_node)) {
onyx_report_error(stmt->token->pos, "Local's type is not a type.");
return Check_Error;
while (type->kind == Ast_Kind_Type_Alias)
type = ((AstTypeAlias *) type)->to;
- if (type->kind == Ast_Kind_Poly_Call_Type) {
- AstPolyCallType* pc_node = (AstPolyCallType *) type;
+ switch (type->kind) {
+ case Ast_Kind_Poly_Call_Type: {
+ AstPolyCallType* pc_node = (AstPolyCallType *) type;
- bh_arr_each(AstNode *, param, pc_node->params) {
- if (!node_is_type(*param)) {
- CHECK(expression, (AstTyped **) param);
- resolve_expression_type((AstTyped *) *param);
+ bh_arr_each(AstNode *, param, pc_node->params) {
+ if (!node_is_type(*param)) {
+ CHECK(expression, (AstTyped **) param);
+ resolve_expression_type((AstTyped *) *param);
+ }
}
+
+ break;
}
+
+ case Ast_Kind_Typeof: {
+ AstTypeOf *type_of = (AstTypeOf *) type;
+ CHECK(expression, (AstTyped **) &type_of->expr);
+ resolve_expression_type(type_of->expr);
+
+ if (type_of->expr->type == NULL) {
+ return Check_Yield_Macro;
+ }
+
+ type_of->resolved_type = type_of->expr->type;
+ break;
+ }
+
+ case Ast_Kind_Pointer_Type: CHECK(type, ((AstPointerType *) type)->elem); break;
+ case Ast_Kind_Slice_Type: CHECK(type, ((AstSliceType *) type)->elem); break;
+ case Ast_Kind_DynArr_Type: CHECK(type, ((AstDynArrType *) type)->elem); break;
+ case Ast_Kind_VarArg_Type: CHECK(type, ((AstVarArgType *) type)->elem); break;
+
+ case Ast_Kind_Function_Type: {
+ AstFunctionType* ftype = (AstFunctionType *) type;
+
+ CHECK(type, ftype->return_type);
+
+ if (ftype->param_count > 0) {
+ fori (i, 0, (i64) ftype->param_count) {
+ CHECK(type, ftype->params[i]);
+ }
+ }
+ break;
+ }
+
+ case Ast_Kind_Type_Compound: {
+ AstCompoundType* ctype = (AstCompoundType *) type;
+
+ bh_arr_each(AstType *, type, ctype->types) CHECK(type, *type);
+ break;
+ }
}
return Check_Success;
case Ast_Kind_Type_Alias: return sizeof(AstTypeAlias);
case Ast_Kind_Type_Raw_Alias: return sizeof(AstTypeRawAlias);
case Ast_Kind_Type_Compound: return sizeof(AstCompoundType);
+ case Ast_Kind_Typeof: return sizeof(AstTypeOf);
case Ast_Kind_Type_End: return 0;
case Ast_Kind_Struct_Member: return sizeof(AstStructMember);
case Ast_Kind_Enum_Value: return sizeof(AstEnumValue);
((AstDirectiveInsert *) nn)->code_expr = (AstTyped *) ast_clone(a, ((AstDirectiveInsert *) node)->code_expr);
break;
}
+
+ case Ast_Kind_Typeof: {
+ ((AstTypeOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstTypeOf *) node)->expr);
+ ((AstTypeOf *) nn)->resolved_type = NULL;
+ break;
+ }
}
clone_depth--;
"continue",
"sizeof",
"alignof",
+ "typeof",
"defer",
"do",
"switch",
LITERAL_TOKEN("return", 1, Token_Type_Keyword_Return);
break;
case 's':
- LITERAL_TOKEN("sizeof", 1, Token_Type_Keyword_Sizeof);
LITERAL_TOKEN("struct", 1, Token_Type_Keyword_Struct);
+ LITERAL_TOKEN("sizeof", 1, Token_Type_Keyword_Sizeof);
LITERAL_TOKEN("switch", 1, Token_Type_Keyword_Switch);
break;
case 't':
LITERAL_TOKEN("true", 1, Token_Type_Literal_True);
+ LITERAL_TOKEN("typeof", 1, Token_Type_Keyword_Typeof);
break;
case 'u':
LITERAL_TOKEN("use", 1, Token_Type_Keyword_Use);
static AstBlock* parse_block(OnyxParser* parser, b32 make_a_new_scope);
static AstNode* parse_statement(OnyxParser* parser);
static AstType* parse_type(OnyxParser* parser);
+static AstTypeOf* parse_typeof(OnyxParser* parser);
static AstStructType* parse_struct(OnyxParser* parser);
static void parse_function_params(OnyxParser* parser, AstFunction* func);
static b32 parse_possible_directive(OnyxParser* parser, const char* dir);
break;
}
+ case Token_Type_Keyword_Typeof: {
+ retval = (AstTyped *) parse_typeof(parser);
+ break;
+ }
+
case Token_Type_Symbol: {
OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
break;
}
+ case Token_Type_Keyword_Typeof: {
+ *next_insertion = (AstType *) parse_typeof(parser);
+ next_insertion = NULL;
+ break;
+ }
+
default:
onyx_report_error(parser->curr->pos, "unexpected token '%b'.", parser->curr->text, parser->curr->length);
consume_token(parser);
return root;
}
+static AstTypeOf* parse_typeof(OnyxParser* parser) {
+ OnyxToken* token = expect_token(parser, Token_Type_Keyword_Typeof);
+
+ AstTypeOf* type_of = make_node(AstTypeOf, Ast_Kind_Typeof);
+ type_of->token = token;
+ type_of->expr = parse_expression(parser, 0);
+ type_of->resolved_type = NULL;
+
+ return type_of;
+}
+
static AstStructType* parse_struct(OnyxParser* parser) {
OnyxToken *s_token = expect_token(parser, Token_Type_Keyword_Struct);
SYMRES(type, (AstType **) &alias->alias);
break;
}
+
+ case Ast_Kind_Typeof: {
+ AstTypeOf* type_of = (AstTypeOf *) *type;
+ SYMRES(expression, &type_of->expr);
+ break;
+ }
}
return Symres_Success;
SymresStatus symres_function_header(AstFunction* func) {
func->flags |= Ast_Flag_Comptime;
+ if (func->scope == NULL)
+ func->scope = scope_create(context.ast_alloc, curr_scope, func->token->pos);
+
+ scope_enter(func->scope);
+
bh_arr_each(AstParam, param, func->params) {
if (param->default_value != NULL) {
SYMRES(expression, ¶m->default_value);
}
}
- SYMRES(type, &func->return_type);
- if (!node_is_type((AstNode *) func->return_type)) {
- onyx_report_error(func->token->pos, "Return type is not a type.");
+ if ((func->flags & Ast_Flag_Params_Introduced) == 0) {
+ bh_arr_each(AstParam, param, func->params) {
+ symbol_introduce(curr_scope, param->local->token, (AstNode *) param->local);
+ }
+
+ func->flags |= Ast_Flag_Params_Introduced;
}
bh_arr_each(AstParam, param, func->params) {
SYMRES(type, ¶m->local->type_node);
}
}
+
+ SYMRES(type, &func->return_type);
+ if (!node_is_type((AstNode *) func->return_type)) {
+ onyx_report_error(func->token->pos, "Return type is not a type.");
+ }
+
+ scope_leave();
+
return Symres_Success;
}
if ((func->flags & Ast_Flag_Has_Been_Symres) == 0) {
bh_arr_each(AstParam, param, func->params) {
- symbol_introduce(curr_scope, param->local->token, (AstNode *) param->local);
-
// CLEANUP: Currently, in order to 'use' parameters, the type must be completely
// resolved and built. This is excessive because all that should need to be known
// is the names of the members, since all that happens is implicit field accesses
mem_alignment = type_alignment_of((*member)->type);
if (mem_alignment <= 0) {
- onyx_report_error((*member)->token->pos, "Invalid member type: %s", type_get_name((*member)->type));
+ onyx_report_error((*member)->token->pos, "Invalid member type: %s. Has alignment %d", type_get_name((*member)->type), mem_alignment);
return NULL;
}
AstAlias* alias = (AstAlias *) type_node;
return type_build_from_ast(alloc, (AstType *) alias->alias);
}
+
+ case Ast_Kind_Typeof: {
+ AstTypeOf* type_of = (AstTypeOf *) type_node;
+ if (type_of->resolved_type != NULL) {
+ return type_of->resolved_type;
+ }
+
+ return NULL;
+ }
}
return NULL;