Browse Source

*_of as keyords; Allow constant aliasing for user/built-in procedures, import names, and library names

Ginger Bill 8 years ago
parent
commit
689a0c0b49
9 changed files with 228 additions and 45 deletions
  1. 6 4
      code/demo.odin
  2. 14 2
      core/_preload.odin
  3. 65 10
      src/check_decl.cpp
  4. 44 8
      src/check_expr.cpp
  5. 14 0
      src/checker.cpp
  6. 10 0
      src/entity.cpp
  7. 7 0
      src/ir.cpp
  8. 64 21
      src/parser.cpp
  9. 4 0
      src/tokenizer.cpp

+ 6 - 4
code/demo.odin

@@ -1,6 +1,5 @@
 import (
 import (
 	"fmt.odin";
 	"fmt.odin";
-/*
 	"atomics.odin";
 	"atomics.odin";
 	"bits.odin";
 	"bits.odin";
 	"decimal.odin";
 	"decimal.odin";
@@ -16,6 +15,7 @@ import (
 	"types.odin";
 	"types.odin";
 	"utf8.odin";
 	"utf8.odin";
 	"utf16.odin";
 	"utf16.odin";
+/*
 */
 */
 )
 )
 
 
@@ -370,9 +370,11 @@ main :: proc() {
 	foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
 	foo :: proc(x: type, y: f32) do fmt.println("#2", type_info(x), y);
 	foo :: proc(x: type)         do fmt.println("#3", type_info(x));
 	foo :: proc(x: type)         do fmt.println("#3", type_info(x));
 
 
-	foo(y = 3785.1546, x = 123);
-	foo(x = int, y = 897.513);
-	foo(x = f32);
+	f :: foo;
+
+	f(y = 3785.1546, x = 123);
+	f(x = int, y = 897.513);
+	f(x = f32);
 /*
 /*
 	general_stuff();
 	general_stuff();
 	foreign_blocks();
 	foreign_blocks();

+ 14 - 2
core/_preload.odin

@@ -504,8 +504,20 @@ __mem_compare :: proc(a, b: ^u8, n: int) -> int #cc_contextless {
 }
 }
 
 
 foreign __llvm_core {
 foreign __llvm_core {
-	__sqrt_f32 :: proc(x: f32) -> f32 #link_name "llvm.sqrt.f32" ---;
-	__sqrt_f64 :: proc(x: f64) -> f64 #link_name "llvm.sqrt.f64" ---;
+	__sqrt_f32 :: proc(x: f32) -> f32        #link_name "llvm.sqrt.f32" ---;
+	__sqrt_f64 :: proc(x: f64) -> f64        #link_name "llvm.sqrt.f64" ---;
+
+	__sin_f32  :: proc(θ: f32) -> f32        #link_name "llvm.sin.f32" ---;
+	__sin_f64  :: proc(θ: f64) -> f64        #link_name "llvm.sin.f64" ---;
+
+	__cos_f32  :: proc(θ: f32) -> f32        #link_name "llvm.cos.f32" ---;
+	__cos_f64  :: proc(θ: f64) -> f64        #link_name "llvm.cos.f64" ---;
+
+	__pow_f32  :: proc(x, power: f32) -> f32 #link_name "llvm.pow.f32" ---;
+	__pow_f64  :: proc(x, power: f64) -> f64 #link_name "llvm.pow.f64" ---;
+
+	fmuladd32  :: proc(a, b, c: f32) -> f32 #link_name "llvm.fmuladd.f32" ---;
+	fmuladd64  :: proc(a, b, c: f64) -> f64 #link_name "llvm.fmuladd.f64" ---;
 }
 }
 __abs_complex64 :: proc(x: complex64) -> f32 #inline #cc_contextless {
 __abs_complex64 :: proc(x: complex64) -> f32 #inline #cc_contextless {
 	r, i := real(x), imag(x);
 	r, i := real(x), imag(x);

+ 65 - 10
src/check_decl.cpp

@@ -191,25 +191,80 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
 	}
 	}
 
 
 	Operand operand = {};
 	Operand operand = {};
+
 	if (init != NULL) {
 	if (init != NULL) {
-		check_expr_or_type(c, &operand, init);
+		Entity *entity = NULL;
+		if (init->kind == AstNode_Ident) {
+			entity = check_ident(c, &operand, init, NULL, e->type, true);
+		} else if (init->kind == AstNode_SelectorExpr) {
+			entity = check_selector(c, &operand, init, e->type);
+		} else {
+			check_expr_or_type(c, &operand, init, e->type);
+		}
+
+		switch (operand.mode) {
+		case Addressing_Type: {
+			e->kind = Entity_TypeName;
+
+			DeclInfo *d = c->context.decl;
+			d->type_expr = d->init_expr;
+			check_type_decl(c, e, d->type_expr, named_type);
+			return;
+		} break;
+
+		case Addressing_Builtin:
+			if (e->type != NULL) {
+				error(type_expr, "A constant alias of a built-in procedure may not have a type initializer");
+			}
+			e->kind = Entity_Builtin;
+			e->Builtin.id = operand.builtin_id;
+			e->type = t_invalid;
+			return;
+
+		case Addressing_Overload:
+			e->kind = Entity_Alias;
+			e->Alias.base = operand.overload_entities[0];
+			e->type = t_invalid;
+			return;
+		}
+
+		if (entity != NULL) {
+			switch (entity->kind) {
+			case Entity_Procedure:
+				e->kind = Entity_Alias;
+				e->type = entity->type;
+				e->Alias.base = entity;
+				return;
+			case Entity_ImportName:
+				e->kind = Entity_ImportName;
+				e->type = entity->type;
+				e->ImportName.path  = entity->ImportName.path;
+				e->ImportName.name  = entity->ImportName.path;
+				e->ImportName.scope = entity->ImportName.scope;
+				e->ImportName.used  = false;
+				return;
+			case Entity_LibraryName:
+				e->kind = Entity_LibraryName;
+				e->type = entity->type;
+				e->LibraryName.path  = entity->LibraryName.path;
+				e->LibraryName.name  = entity->LibraryName.path;
+				e->LibraryName.used  = false;
+				return;
+			}
+		}
 	}
 	}
-#if 1
-	if (operand.mode == Addressing_Type) {
-		e->kind = Entity_TypeName;
 
 
-		DeclInfo *d = c->context.decl;
-		d->type_expr = d->init_expr;
-		check_type_decl(c, e, d->type_expr, named_type);
-		return;
+	if (init != NULL) {
+		check_expr_or_type(c, &operand, init, e->type);
 	}
 	}
-#endif
 
 
 	check_init_constant(c, e, &operand);
 	check_init_constant(c, e, &operand);
 
 
 	if (operand.mode == Addressing_Invalid ||
 	if (operand.mode == Addressing_Invalid ||
 		base_type(operand.type) == t_invalid) {
 		base_type(operand.type) == t_invalid) {
-		error(e->token, "Invalid declaration type");
+		gbString str = expr_to_string(init);
+		error(e->token, "Invalid declaration type `%s`", str);
+		gb_string_free(str);
 	}
 	}
 }
 }
 
 

+ 44 - 8
src/check_expr.cpp

@@ -33,7 +33,7 @@ typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
 
 
 void     check_expr                     (Checker *c, Operand *operand, AstNode *expression);
 void     check_expr                     (Checker *c, Operand *operand, AstNode *expression);
 void     check_multi_expr               (Checker *c, Operand *operand, AstNode *expression);
 void     check_multi_expr               (Checker *c, Operand *operand, AstNode *expression);
-void     check_expr_or_type             (Checker *c, Operand *operand, AstNode *expression);
+void     check_expr_or_type             (Checker *c, Operand *operand, AstNode *expression, Type *type_hint = NULL);
 ExprKind check_expr_base                (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
 ExprKind check_expr_base                (Checker *c, Operand *operand, AstNode *expression, Type *type_hint);
 void     check_expr_with_type_hint      (Checker *c, Operand *o, AstNode *e, Type *t);
 void     check_expr_with_type_hint      (Checker *c, Operand *o, AstNode *e, Type *t);
 Type *   check_type                     (Checker *c, AstNode *expression, Type *named_type = NULL);
 Type *   check_type                     (Checker *c, AstNode *expression, Type *named_type = NULL);
@@ -1260,7 +1260,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 					success = false;
 					success = false;
 				}
 				}
 			}
 			}
-			if (type_expr->kind == AstNode_HelperType) {
+			if (type_expr->kind == AstNode_TypeType) {
 				is_type_param = true;
 				is_type_param = true;
 				if (operands != NULL) {
 				if (operands != NULL) {
 					detemine_type_from_operand = true;
 					detemine_type_from_operand = true;
@@ -1283,7 +1283,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
 			}
 			}
 
 
 			if (default_value != NULL) {
 			if (default_value != NULL) {
-				if (type_expr->kind == AstNode_HelperType) {
+				if (type_expr->kind == AstNode_TypeType) {
 					error(default_value, "A type parameter may not have a default value");
 					error(default_value, "A type parameter may not have a default value");
 				} else {
 				} else {
 					Operand o = {};
 					Operand o = {};
@@ -1817,7 +1817,16 @@ Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *
 
 
 	bool is_overloaded = false;
 	bool is_overloaded = false;
 	isize overload_count = 0;
 	isize overload_count = 0;
-	HashKey key = hash_string(name);
+
+	bool is_alias = false;
+	while (e->kind == Entity_Alias) {
+		GB_ASSERT(e->Alias.base != NULL);
+		e = e->Alias.base;
+		is_alias = true;
+	}
+
+	HashKey key = hash_string(e->token.string);
+
 
 
 	if (e->kind == Entity_Procedure) {
 	if (e->kind == Entity_Procedure) {
 		// NOTE(bill): Overloads are only allowed with the same scope
 		// NOTE(bill): Overloads are only allowed with the same scope
@@ -2135,6 +2144,10 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
 		}
 		}
 	case_end;
 	case_end;
 
 
+	case_ast_node(ht, HelperType, e);
+		return check_type_internal(c, ht->type, type, named_type);
+	case_end;
+
 	case_ast_node(pt, PolyType, e);
 	case_ast_node(pt, PolyType, e);
 		AstNode *ident = pt->type;
 		AstNode *ident = pt->type;
 		if (ident->kind != AstNode_Ident) {
 		if (ident->kind != AstNode_Ident) {
@@ -6047,6 +6060,24 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 			o->mode = Addressing_Value;
 			o->mode = Addressing_Value;
 			o->type = t_context;
 			o->type = t_context;
 			break;
 			break;
+
+		case Token_size_of:
+			o->mode       = Addressing_Builtin;
+			o->builtin_id = BuiltinProc_size_of;
+			break;
+		case Token_align_of:
+			o->mode       = Addressing_Builtin;
+			o->builtin_id = BuiltinProc_align_of;
+			break;
+		case Token_offset_of:
+			o->mode       = Addressing_Builtin;
+			o->builtin_id = BuiltinProc_offset_of;
+			break;
+		case Token_type_of:
+			o->mode       = Addressing_Builtin;
+			o->builtin_id = BuiltinProc_type_of;
+			break;
+
 		default:
 		default:
 			error(node, "Illegal implicit name `%.*s`", LIT(i->string));
 			error(node, "Illegal implicit name `%.*s`", LIT(i->string));
 			return kind;
 			return kind;
@@ -6916,7 +6947,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
 		}
 		}
 	case_end;
 	case_end;
 
 
-	case AstNode_HelperType:
+	case AstNode_TypeType:
 	case AstNode_ProcType:
 	case AstNode_ProcType:
 	case AstNode_PointerType:
 	case AstNode_PointerType:
 	case AstNode_ArrayType:
 	case AstNode_ArrayType:
@@ -7001,8 +7032,8 @@ void check_expr(Checker *c, Operand *o, AstNode *e) {
 }
 }
 
 
 
 
-void check_expr_or_type(Checker *c, Operand *o, AstNode *e) {
-	check_expr_base(c, o, e, NULL);
+void check_expr_or_type(Checker *c, Operand *o, AstNode *e, Type *type_hint) {
+	check_expr_base(c, o, e, type_hint);
 	check_not_tuple(c, o);
 	check_not_tuple(c, o);
 	error_operand_no_value(o);
 	error_operand_no_value(o);
 }
 }
@@ -7148,6 +7179,11 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = write_expr_to_string(str, fv->value);
 		str = write_expr_to_string(str, fv->value);
 	case_end;
 	case_end;
 
 
+	case_ast_node(ht, HelperType, node);
+		str = gb_string_appendc(str, "#type ");
+		str = write_expr_to_string(str, ht->type);
+	case_end;
+
 	case_ast_node(pt, PointerType, node);
 	case_ast_node(pt, PointerType, node);
 		str = gb_string_appendc(str, "^");
 		str = gb_string_appendc(str, "^");
 		str = write_expr_to_string(str, pt->type);
 		str = write_expr_to_string(str, pt->type);
@@ -7271,7 +7307,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		str = gb_string_appendc(str, ")");
 		str = gb_string_appendc(str, ")");
 	case_end;
 	case_end;
 
 
-	case_ast_node(ht, HelperType, node);
+	case_ast_node(ht, TypeType, node);
 		str = gb_string_appendc(str, "type");
 		str = gb_string_appendc(str, "type");
 	case_end;
 	case_end;
 
 

+ 14 - 0
src/checker.cpp

@@ -61,6 +61,12 @@ enum BuiltinProcId {
 	BuiltinProc_abs,
 	BuiltinProc_abs,
 	BuiltinProc_clamp,
 	BuiltinProc_clamp,
 
 
+/* 	BuiltinProc_sqrt,
+	BuiltinProc_sin,
+	BuiltinProc_cos,
+	BuiltinProc_tan,
+	BuiltinProc_pow, */
+
 	BuiltinProc_transmute,
 	BuiltinProc_transmute,
 
 
 	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
 	BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
@@ -107,6 +113,14 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
 	{STR_LIT("abs"),              1, false, Expr_Expr},
 	{STR_LIT("abs"),              1, false, Expr_Expr},
 	{STR_LIT("clamp"),            3, false, Expr_Expr},
 	{STR_LIT("clamp"),            3, false, Expr_Expr},
 
 
+/*
+	{STR_LIT("__sqrt"),            1, false, Expr_Expr},
+	{STR_LIT("__sin"),             1, false, Expr_Expr},
+	{STR_LIT("__cos"),             1, false, Expr_Expr},
+	{STR_LIT("__tan"),             1, false, Expr_Expr},
+	{STR_LIT("__pow"),             2, false, Expr_Expr},
+ */
+
 	{STR_LIT("transmute"),        2, false, Expr_Expr},
 	{STR_LIT("transmute"),        2, false, Expr_Expr},
 
 
 	{STR_LIT(""),                 0, true,  Expr_Expr}, // DIRECTIVE
 	{STR_LIT(""),                 0, true,  Expr_Expr}, // DIRECTIVE

+ 10 - 0
src/entity.cpp

@@ -12,6 +12,7 @@ struct DeclInfo;
 	ENTITY_KIND(TypeName) \
 	ENTITY_KIND(TypeName) \
 	ENTITY_KIND(Procedure) \
 	ENTITY_KIND(Procedure) \
 	ENTITY_KIND(Builtin) \
 	ENTITY_KIND(Builtin) \
+	ENTITY_KIND(Alias) \
 	ENTITY_KIND(ImportName) \
 	ENTITY_KIND(ImportName) \
 	ENTITY_KIND(LibraryName) \
 	ENTITY_KIND(LibraryName) \
 	ENTITY_KIND(Nil) \
 	ENTITY_KIND(Nil) \
@@ -108,6 +109,9 @@ struct Entity {
 		struct {
 		struct {
 			i32 id;
 			i32 id;
 		} Builtin;
 		} Builtin;
+		struct {
+			Entity *base;
+		} Alias;
 		struct {
 		struct {
 			String path;
 			String path;
 			String name;
 			String name;
@@ -232,6 +236,12 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
 	return entity;
 	return entity;
 }
 }
 
 
+Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type, Entity *base) {
+	Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
+	entity->Alias.base = base;
+	return entity;
+}
+
 Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
 Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
                                 String path, String name, Scope *import_scope) {
                                 String path, String name, Scope *import_scope) {
 	Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
 	Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);

+ 7 - 0
src/ir.cpp

@@ -5639,6 +5639,13 @@ void ir_build_constant_value_decl(irProcedure *proc, AstNodeValueDecl *vd) {
 		GB_ASSERT(ident->kind == AstNode_Ident);
 		GB_ASSERT(ident->kind == AstNode_Ident);
 		Entity *e = entity_of_ident(proc->module->info, ident);
 		Entity *e = entity_of_ident(proc->module->info, ident);
 		GB_ASSERT(e != NULL);
 		GB_ASSERT(e != NULL);
+		switch (e->kind) {
+		case Entity_TypeName:
+		case Entity_Procedure:
+			break;
+		default:
+			continue;
+		}
 
 
 		bool polymorphic = is_type_polymorphic(e->type);
 		bool polymorphic = is_type_polymorphic(e->type);
 
 

+ 64 - 21
src/parser.cpp

@@ -375,9 +375,13 @@ AST_NODE_KIND(_DeclEnd,   "", i32) \
 		AstNode *list; \
 		AstNode *list; \
 	}) \
 	}) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
-	AST_NODE_KIND(HelperType, "type", struct { \
+	AST_NODE_KIND(TypeType, "type", struct { \
 		Token token; \
 		Token token; \
 	}) \
 	}) \
+	AST_NODE_KIND(HelperType, "helper type", struct { \
+		Token token; \
+		AstNode *type; \
+	}) \
 	AST_NODE_KIND(PolyType, "polymorphic type", struct { \
 	AST_NODE_KIND(PolyType, "polymorphic type", struct { \
 		Token    token; \
 		Token    token; \
 		AstNode *type;  \
 		AstNode *type;  \
@@ -585,6 +589,7 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_UnionField:
 	case AstNode_UnionField:
 		return ast_node_token(node->UnionField.name);
 		return ast_node_token(node->UnionField.name);
 
 
+	case AstNode_TypeType:         return node->TypeType.token;
 	case AstNode_HelperType:       return node->HelperType.token;
 	case AstNode_HelperType:       return node->HelperType.token;
 	case AstNode_PolyType:         return node->PolyType.token;
 	case AstNode_PolyType:         return node->PolyType.token;
 	case AstNode_ProcType:         return node->ProcType.token;
 	case AstNode_ProcType:         return node->ProcType.token;
@@ -829,7 +834,10 @@ AstNode *clone_ast_node(gbAllocator a, AstNode *node) {
 		n->UnionField.list = clone_ast_node(a, n->UnionField.list);
 		n->UnionField.list = clone_ast_node(a, n->UnionField.list);
 		break;
 		break;
 
 
+	case AstNode_TypeType:
+		break;
 	case AstNode_HelperType:
 	case AstNode_HelperType:
+		n->HelperType.type = clone_ast_node(a, n->HelperType.type);
 		break;
 		break;
 	case AstNode_ProcType:
 	case AstNode_ProcType:
 		n->ProcType.params  = clone_ast_node(a, n->ProcType.params);
 		n->ProcType.params  = clone_ast_node(a, n->ProcType.params);
@@ -1367,12 +1375,20 @@ AstNode *ast_union_field(AstFile *f, AstNode *name, AstNode *list) {
 }
 }
 
 
 
 
-AstNode *ast_helper_type(AstFile *f, Token token) {
+AstNode *ast_type_type(AstFile *f, Token token) {
+	AstNode *result = make_ast_node(f, AstNode_TypeType);
+	result->TypeType.token = token;
+	return result;
+}
+
+AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
 	AstNode *result = make_ast_node(f, AstNode_HelperType);
 	AstNode *result = make_ast_node(f, AstNode_HelperType);
 	result->HelperType.token = token;
 	result->HelperType.token = token;
+	result->HelperType.type  = type;
 	return result;
 	return result;
 }
 }
 
 
+
 AstNode *ast_poly_type(AstFile *f, Token token, AstNode *type) {
 AstNode *ast_poly_type(AstFile *f, Token token, AstNode *type) {
 	AstNode *result = make_ast_node(f, AstNode_PolyType);
 	AstNode *result = make_ast_node(f, AstNode_PolyType);
 	result->PolyType.token = token;
 	result->PolyType.token = token;
@@ -2187,6 +2203,14 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 		next_token(f);
 		next_token(f);
 		return operand;
 		return operand;
 
 
+	case Token_size_of:
+	case Token_align_of:
+	case Token_offset_of: {
+		operand = ast_implicit(f, f->curr_token); next_token(f);
+		return parse_call_expr(f, operand);
+	}
+
+
 	case Token_String: {
 	case Token_String: {
 		Token token = f->curr_token;
 		Token token = f->curr_token;
 		next_token(f);
 		next_token(f);
@@ -2228,6 +2252,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
 
 
 	case Token_Hash: {
 	case Token_Hash: {
 		Token token = expect_token(f, Token_Hash);
 		Token token = expect_token(f, Token_Hash);
+		if (allow_token(f, Token_type)) {
+			return ast_helper_type(f, token, parse_type(f));
+		}
 		Token name  = expect_token(f, Token_Ident);
 		Token name  = expect_token(f, Token_Ident);
 		if (name.string == "run") {
 		if (name.string == "run") {
 			AstNode *expr = parse_expr(f, false);
 			AstNode *expr = parse_expr(f, false);
@@ -3162,7 +3189,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) {
 			break;
 			break;
 		}
 		}
 		if (f->type != NULL &&
 		if (f->type != NULL &&
-		    f->type->kind == AstNode_HelperType) {
+		    f->type->kind == AstNode_TypeType) {
 			is_generic = true;
 			is_generic = true;
 			break;
 			break;
 		}
 		}
@@ -3186,7 +3213,7 @@ AstNode *parse_var_type(AstFile *f, bool allow_ellipsis, bool allow_type_token)
 	AstNode *type = NULL;
 	AstNode *type = NULL;
 	if (allow_type_token &&
 	if (allow_type_token &&
 	    f->curr_token.kind == Token_type) {
 	    f->curr_token.kind == Token_type) {
-		type = ast_helper_type(f, expect_token(f, Token_type));
+		type = ast_type_type(f, expect_token(f, Token_type));
 	} else {
 	} else {
 		type = parse_type_attempt(f);
 		type = parse_type_attempt(f);
 	}
 	}
@@ -3473,8 +3500,6 @@ AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String
 }
 }
 
 
 AstNode *parse_type_or_ident(AstFile *f) {
 AstNode *parse_type_or_ident(AstFile *f) {
-	AstNode *type = NULL;
-
 	switch (f->curr_token.kind) {
 	switch (f->curr_token.kind) {
 	case Token_Dollar: {
 	case Token_Dollar: {
 		Token token = expect_token(f, Token_Dollar);
 		Token token = expect_token(f, Token_Dollar);
@@ -3482,8 +3507,19 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		return ast_poly_type(f, token, type);
 		return ast_poly_type(f, token, type);
 	} break;
 	} break;
 
 
-	case Token_Ident:
-	{
+	case Token_type_of: {
+		AstNode *i = ast_implicit(f, expect_token(f, Token_type_of));
+		AstNode *type = parse_call_expr(f, i);
+		while (f->curr_token.kind == Token_Period) {
+			Token token = f->curr_token;
+			next_token(f);
+			AstNode *sel = parse_ident(f);
+			type = ast_selector_expr(f, token, type, sel);
+		}
+		return type;
+	} break;
+
+	case Token_Ident: {
 		AstNode *e = parse_ident(f);
 		AstNode *e = parse_ident(f);
 		while (f->curr_token.kind == Token_Period) {
 		while (f->curr_token.kind == Token_Period) {
 			Token token = f->curr_token;
 			Token token = f->curr_token;
@@ -3496,21 +3532,28 @@ AstNode *parse_type_or_ident(AstFile *f) {
 			// HACK NOTE(bill): For type_of_val(expr) et al.
 			// HACK NOTE(bill): For type_of_val(expr) et al.
 			// e = parse_call_expr(f, e);
 			// e = parse_call_expr(f, e);
 		// }
 		// }
-		type = e;
+		return e;
 	} break;
 	} break;
 
 
 	case Token_Pointer: {
 	case Token_Pointer: {
 		Token token = expect_token(f, Token_Pointer);
 		Token token = expect_token(f, Token_Pointer);
 		AstNode *elem = parse_type(f);
 		AstNode *elem = parse_type(f);
-		type = ast_pointer_type(f, token, elem);
+		return ast_pointer_type(f, token, elem);
 	} break;
 	} break;
 
 
 	case Token_atomic: {
 	case Token_atomic: {
 		Token token = expect_token(f, Token_atomic);
 		Token token = expect_token(f, Token_atomic);
 		AstNode *elem = parse_type(f);
 		AstNode *elem = parse_type(f);
-		type = ast_atomic_type(f, token, elem);
+		return ast_atomic_type(f, token, elem);
 	} break;
 	} break;
 
 
+	case Token_Hash: {
+		Token hash_token = expect_token(f, Token_Hash);
+		Token type_token = expect_token(f, Token_type);
+		AstNode *type = parse_type(f);
+		return ast_helper_type(f, hash_token, type);
+	}
+
 	case Token_OpenBracket: {
 	case Token_OpenBracket: {
 		Token token = expect_token(f, Token_OpenBracket);
 		Token token = expect_token(f, Token_OpenBracket);
 		AstNode *count_expr = NULL;
 		AstNode *count_expr = NULL;
@@ -3541,7 +3584,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		if (is_vector) {
 		if (is_vector) {
 			return ast_vector_type(f, token, count_expr, parse_type(f));
 			return ast_vector_type(f, token, count_expr, parse_type(f));
 		}
 		}
-		type = ast_array_type(f, token, count_expr, parse_type(f));
+		return ast_array_type(f, token, count_expr, parse_type(f));
 	} break;
 	} break;
 
 
 	case Token_map: {
 	case Token_map: {
@@ -3559,7 +3602,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Token close = expect_token(f, Token_CloseBracket);
 		Token close = expect_token(f, Token_CloseBracket);
 		value = parse_type(f);
 		value = parse_type(f);
 
 
-		type = ast_map_type(f, token, count, key, value);
+		return ast_map_type(f, token, count, key, value);
 	} break;
 	} break;
 
 
 	case Token_struct: {
 	case Token_struct: {
@@ -3610,7 +3653,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 			decls = fields->FieldList.list;
 			decls = fields->FieldList.list;
 		}
 		}
 
 
-		type = ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
+		return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
 	} break;
 	} break;
 
 
 	case Token_union: {
 	case Token_union: {
@@ -3664,7 +3707,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Token close = expect_token(f, Token_CloseBrace);
 		Token close = expect_token(f, Token_CloseBrace);
 
 
 
 
-		type = ast_union_type(f, token, decls, total_decl_name_count, variants);
+		return ast_union_type(f, token, decls, total_decl_name_count, variants);
 	} break;
 	} break;
 
 
 	case Token_raw_union: {
 	case Token_raw_union: {
@@ -3680,7 +3723,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 			decls = fields->FieldList.list;
 			decls = fields->FieldList.list;
 		}
 		}
 
 
-		type = ast_raw_union_type(f, token, decls, decl_count);
+		return ast_raw_union_type(f, token, decls, decl_count);
 	} break;
 	} break;
 
 
 	case Token_enum: {
 	case Token_enum: {
@@ -3694,7 +3737,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Array<AstNode *> values = parse_element_list(f);
 		Array<AstNode *> values = parse_element_list(f);
 		Token close = expect_token(f, Token_CloseBrace);
 		Token close = expect_token(f, Token_CloseBrace);
 
 
-		type = ast_enum_type(f, token, base_type, values);
+		return ast_enum_type(f, token, base_type, values);
 	} break;
 	} break;
 
 
 	case Token_bit_field: {
 	case Token_bit_field: {
@@ -3739,7 +3782,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 
 
 		close = expect_token(f, Token_CloseBrace);
 		close = expect_token(f, Token_CloseBrace);
 
 
-		type = ast_bit_field_type(f, token, fields, align);
+		return ast_bit_field_type(f, token, fields, align);
 	} break;
 	} break;
 
 
 	case Token_proc: {
 	case Token_proc: {
@@ -3748,18 +3791,18 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		if (pt->ProcType.tags != 0) {
 		if (pt->ProcType.tags != 0) {
 			syntax_error(token, "A procedure type cannot have tags");
 			syntax_error(token, "A procedure type cannot have tags");
 		}
 		}
-		type = pt;
+		return pt;
 	} break;
 	} break;
 
 
 	case Token_OpenParen: {
 	case Token_OpenParen: {
 		Token    open  = expect_token(f, Token_OpenParen);
 		Token    open  = expect_token(f, Token_OpenParen);
 		AstNode *type  = parse_type(f);
 		AstNode *type  = parse_type(f);
 		Token    close = expect_token(f, Token_CloseParen);
 		Token    close = expect_token(f, Token_CloseParen);
-		type = ast_paren_expr(f, type, open, close);
+		return ast_paren_expr(f, type, open, close);
 	} break;
 	} break;
 	}
 	}
 
 
-	return type;
+	return NULL;
 }
 }
 
 
 
 

+ 4 - 0
src/tokenizer.cpp

@@ -118,6 +118,10 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
 	TOKEN_KIND(Token_context,                "context"),                \
 	TOKEN_KIND(Token_context,                "context"),                \
 	TOKEN_KIND(Token_push_context,           "push_context"),           \
 	TOKEN_KIND(Token_push_context,           "push_context"),           \
 	TOKEN_KIND(Token_push_allocator,         "push_allocator"),         \
 	TOKEN_KIND(Token_push_allocator,         "push_allocator"),         \
+	TOKEN_KIND(Token_size_of,                "size_of"),                \
+	TOKEN_KIND(Token_align_of,               "align_of"),               \
+	TOKEN_KIND(Token_offset_of,              "offset_of"),              \
+	TOKEN_KIND(Token_type_of,                "type_of"),                \
 	TOKEN_KIND(Token_asm,                    "asm"),                    \
 	TOKEN_KIND(Token_asm,                    "asm"),                    \
 	TOKEN_KIND(Token_yield,                  "yield"),                  \
 	TOKEN_KIND(Token_yield,                  "yield"),                  \
 	TOKEN_KIND(Token_await,                  "await"),                  \
 	TOKEN_KIND(Token_await,                  "await"),                  \