Browse Source

`alias` and unified parameters lists for procedures and structures.

gingerBill 9 years ago
parent
commit
32ab8fcf99

+ 6 - 0
examples/test.odin

@@ -0,0 +1,6 @@
+type Vec2: struct { x, y: f32 }
+
+
+main :: proc() {
+
+}

+ 14 - 6
src/checker/checker.cpp

@@ -297,12 +297,12 @@ void init_universal_scope(void) {
 	for (isize i = 0; i < gb_count_of(basic_types); i++) {
 		Token token = {Token_Identifier};
 		token.string = basic_types[i].basic.name;
-		add_global_entity(alloc_entity(a, Entity_TypeName, NULL, token, &basic_types[i]));
+		add_global_entity(make_entity_type_name(a, NULL, token, &basic_types[i]));
 	}
 	for (isize i = 0; i < gb_count_of(basic_type_aliases); i++) {
 		Token token = {Token_Identifier};
 		token.string = basic_type_aliases[i].basic.name;
-		add_global_entity(alloc_entity(a, Entity_TypeName, NULL, token, &basic_type_aliases[i]));
+		add_global_entity(make_entity_type_name(a, NULL, token, &basic_type_aliases[i]));
 	}
 
 // Constants
@@ -555,8 +555,8 @@ void check_parsed_files(Checker *c) {
 						add_file_entity(c, name, e, di);
 					}
 
-					isize lhs_count = vd->name_list_count;
-					isize rhs_count = vd->value_list_count;
+					isize lhs_count = vd->name_count;
+					isize rhs_count = vd->value_count;
 
 					if (rhs_count == 0 && vd->type_expression == NULL) {
 						error(&c->error_collector, ast_node_token(decl), "Missing type or initial expression");
@@ -566,11 +566,11 @@ void check_parsed_files(Checker *c) {
 				} break;
 
 				case Declaration_Mutable: {
-					isize entity_count = vd->name_list_count;
+					isize entity_count = vd->name_count;
 					isize entity_index = 0;
 					Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
 					DeclarationInfo *di = NULL;
-					if (vd->value_list_count == 1) {
+					if (vd->value_count == 1) {
 						di = make_declaration_info(gb_heap_allocator(), c->global_scope);
 						di->entities = entities;
 						di->entity_count = entity_count;
@@ -610,6 +610,14 @@ void check_parsed_files(Checker *c) {
 				add_file_entity(c, identifier, e, d);
 			} break;
 
+			case AstNode_AliasDeclaration: {
+				AstNode *identifier = decl->alias_declaration.name;
+				Entity *e = make_entity_alias_name(c->allocator, c->global_scope, identifier->identifier.token, NULL);
+				DeclarationInfo *d = make_declaration_info(c->allocator, e->parent);
+				d->type_expr = decl->alias_declaration.type_expression;
+				add_file_entity(c, identifier, e, d);
+			} break;
+
 			case AstNode_ProcedureDeclaration: {
 				AstNode *identifier = decl->procedure_declaration.name;
 				Token token = identifier->identifier.token;

+ 9 - 2
src/checker/entity.cpp

@@ -8,6 +8,7 @@ enum EntityKind {
 	Entity_Constant,
 	Entity_Variable,
 	Entity_TypeName,
+	Entity_AliasName,
 	Entity_Procedure,
 	Entity_Builtin,
 
@@ -33,6 +34,7 @@ struct Entity {
 			b8 used;
 		} variable;
 		struct {} type_name;
+		struct {} alias_name;
 		struct {} procedure;
 		struct { BuiltinProcedureId id; } builtin;
 	};
@@ -70,14 +72,19 @@ Entity *make_entity_type_name(gbAllocator a, Scope *parent, Token token, Type *t
 	return entity;
 }
 
+Entity *make_entity_alias_name(gbAllocator a, Scope *parent, Token token, Type *type) {
+	Entity *entity = alloc_entity(a, Entity_AliasName, parent, token, type);
+	return entity;
+}
+
 Entity *make_entity_param(gbAllocator a, Scope *parent, Token token, Type *type) {
-	Entity *entity = alloc_entity(a, Entity_Variable, parent, token, type);
+	Entity *entity = make_entity_variable(a, parent, token, type);
 	entity->variable.used = true;
 	return entity;
 }
 
 Entity *make_entity_field(gbAllocator a, Scope *parent, Token token, Type *type) {
-	Entity *entity = alloc_entity(a, Entity_Variable, parent, token, type);
+	Entity *entity = make_entity_variable(a, parent, token, type);
 	entity->variable.is_field  = true;
 	return entity;
 }

+ 9 - 9
src/checker/expression.cpp

@@ -123,13 +123,13 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
 	// gb_printf("%td -> %td\n", param_count, result_count);
 
 	Type *params  = check_get_params(c, c->context.scope, proc_type_node->procedure_type.param_list,   param_count);
-	Type *results = check_get_results(c, c->context.scope, proc_type_node->procedure_type.results_list, result_count);
+	Type *results = check_get_results(c, c->context.scope, proc_type_node->procedure_type.result_list, result_count);
 
-	type->procedure.scope         = c->context.scope;
-	type->procedure.params        = params;
-	type->procedure.params_count  = proc_type_node->procedure_type.param_count;
-	type->procedure.results       = results;
-	type->procedure.results_count = proc_type_node->procedure_type.result_count;
+	type->procedure.scope        = c->context.scope;
+	type->procedure.params       = params;
+	type->procedure.param_count  = proc_type_node->procedure_type.param_count;
+	type->procedure.results      = results;
+	type->procedure.result_count = proc_type_node->procedure_type.result_count;
 }
 
 
@@ -171,6 +171,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
 		break;
 
 	case Entity_TypeName:
+	case Entity_AliasName:
 		o->mode = Addressing_Type;
 		break;
 
@@ -1416,9 +1417,9 @@ ExpressionKind check_call_expression(Checker *c, Operand *operand, AstNode *call
 	check_call_arguments(c, operand, proc_type, call);
 
 	auto *proc = &proc_type->procedure;
-	if (proc->results_count == 0) {
+	if (proc->result_count == 0) {
 		operand->mode = Addressing_NoValue;
-	} else if (proc->results_count == 1) {
+	} else if (proc->result_count == 1) {
 		operand->mode = Addressing_Value;
 		operand->type = proc->results->tuple.variables[0]->type;
 	} else {
@@ -1524,7 +1525,6 @@ void check_expression_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t
 	}
 }
 
-
 ExpressionKind check__expression_base(Checker *c, Operand *o, AstNode *node, Type *type_hint) {
 	ExpressionKind kind = Expression_Statement;
 

+ 27 - 5
src/checker/statements.cpp

@@ -360,6 +360,17 @@ void check_type_declaration(Checker *c, Entity *e, AstNode *type_expr, Type *nam
 	set_base_type(named, get_base_type(get_base_type(named)));
 }
 
+void check_alias_declaration(Checker *c, Entity *e, AstNode *type_expr, Type *alias_type) {
+	GB_ASSERT(e->type == NULL);
+	Type *named = make_type_alias(c->allocator, e->token.string, NULL, e);
+	named->alias.alias_name = e;
+	set_base_type(alias_type, named);
+	e->type = named;
+
+	check_type(c, type_expr, named);
+
+	set_base_type(named, get_base_type(get_base_type(named)));
+}
 
 void check_procedure_body(Checker *c, Token token, DeclarationInfo *decl, Type *type, AstNode *body) {
 	GB_ASSERT(body->kind == AstNode_BlockStatement);
@@ -370,7 +381,7 @@ void check_procedure_body(Checker *c, Token token, DeclarationInfo *decl, Type *
 
 	push_procedure(c, type);
 	check_statement_list(c, body->block_statement.list, 0);
-	if (type->procedure.results_count > 0) {
+	if (type->procedure.result_count > 0) {
 		if (!check_is_terminating(c, body)) {
 			error(&c->error_collector, body->block_statement.close, "Missing return statement at the end of the procedure");
 		}
@@ -498,6 +509,9 @@ void check_entity_declaration(Checker *c, Entity *e, Type *named_type) {
 	case Entity_TypeName:
 		check_type_declaration(c, e, d->type_expr, named_type);
 		break;
+	case Entity_AliasName:
+		check_alias_declaration(c, e, d->type_expr, named_type);
+		break;
 	case Entity_Procedure:
 		check_procedure_declaration(c, e, d, true);
 		break;
@@ -763,7 +777,7 @@ void check_statement(Checker *c, AstNode *node, u32 flags) {
 // Declarations
 	case AstNode_VariableDeclaration: {
 		auto *vd = &node->variable_declaration;
-		isize entity_count = vd->name_list_count;
+		isize entity_count = vd->name_count;
 		isize entity_index = 0;
 		Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_count);
 		switch (vd->kind) {
@@ -820,7 +834,7 @@ void check_statement(Checker *c, AstNode *node, u32 flags) {
 			}
 
 
-			check_init_variables(c, entities, entity_count, vd->value_list, vd->value_list_count, make_string("variable declaration"));
+			check_init_variables(c, entities, entity_count, vd->value_list, vd->value_count, make_string("variable declaration"));
 
 			AstNode *name = vd->name_list;
 			for (isize i = 0; i < new_entity_count; i++, name = name->next) {
@@ -840,8 +854,8 @@ void check_statement(Checker *c, AstNode *node, u32 flags) {
 				check_constant_declaration(c, e, vd->type_expression, value);
 			}
 
-			isize lhs_count = vd->name_list_count;
-			isize rhs_count = vd->value_list_count;
+			isize lhs_count = vd->name_count;
+			isize rhs_count = vd->value_count;
 
 			// TODO(bill): Better error messages or is this good enough?
 			if (rhs_count == 0 && vd->type_expression == NULL) {
@@ -881,5 +895,13 @@ void check_statement(Checker *c, AstNode *node, u32 flags) {
 		add_entity(c, c->context.scope, name, e);
 		check_type_declaration(c, e, td->type_expression, NULL);
 	} break;
+
+	case AstNode_AliasDeclaration: {
+		auto *ad = &node->alias_declaration;
+		AstNode *name = ad->name;
+		Entity *e = make_entity_alias_name(c->allocator, c->context.scope, name->identifier.token, NULL);
+		add_entity(c, c->context.scope, name, e);
+		check_alias_declaration(c, e, ad->type_expression, NULL);
+	} break;
 	}
 }

+ 42 - 10
src/checker/type.cpp

@@ -60,6 +60,7 @@ enum TypeKind {
 	Type_Structure,
 	Type_Pointer,
 	Type_Named,
+	Type_Alias,
 	Type_Tuple,
 	Type_Procedure,
 
@@ -81,7 +82,7 @@ struct Type {
 			Entity **fields; // Entity_Variable
 			isize    field_count; // == offset_count
 			i64 *    offsets;
-			b32      offsets_set;
+			b32      are_offsets_set;
 		} structure;
 		struct { Type *element; } pointer;
 		struct {
@@ -89,6 +90,11 @@ struct Type {
 			Type *  base;
 			Entity *type_name; // Entity_TypeName
 		} named;
+		struct {
+			String  name;
+			Type *  base;
+			Entity *alias_name; // Entity_AliasName
+		} alias;
 		struct {
 			Entity **variables; // Entity_Variable
 			isize    variable_count;
@@ -97,15 +103,18 @@ struct Type {
 			Scope *scope;
 			Type * params;  // Type_Tuple
 			Type * results; // Type_Tuple
-			isize  params_count;
-			isize  results_count;
+			isize  param_count;
+			isize  result_count;
 		} procedure;
 	};
 };
 
 Type *get_base_type(Type *t) {
-	while (t->kind == Type_Named) {
-		t = t->named.base;
+	while (t->kind == Type_Named || t->kind == Type_Alias) {
+		if (t->kind == Type_Named)
+			t = t->named.base;
+		else
+			t = t->alias.base;
 	}
 	return t;
 }
@@ -113,6 +122,8 @@ Type *get_base_type(Type *t) {
 void set_base_type(Type *t, Type *base) {
 	if (t && t->kind == Type_Named) {
 		t->named.base = base;
+	} else if (t && t->kind == Type_Alias) {
+		t->alias.base = base;
 	}
 }
 
@@ -162,18 +173,26 @@ Type *make_type_named(gbAllocator a, String name, Type *base, Entity *type_name)
 	return t;
 }
 
+Type *make_type_alias(gbAllocator a, String name, Type *base, Entity *alias_name) {
+	Type *t = alloc_type(a, Type_Alias);
+	t->alias.name = name;
+	t->alias.base = base;
+	t->alias.alias_name = alias_name;
+	return t;
+}
+
 Type *make_type_tuple(gbAllocator a) {
 	Type *t = alloc_type(a, Type_Tuple);
 	return t;
 }
 
-Type *make_type_procedure(gbAllocator a, Scope *scope, Type *params, isize params_count, Type *results, isize results_count) {
+Type *make_type_procedure(gbAllocator a, Scope *scope, Type *params, isize param_count, Type *results, isize result_count) {
 	Type *t = alloc_type(a, Type_Procedure);
 	t->procedure.scope = scope;
 	t->procedure.params = params;
-	t->procedure.params_count = params_count;
+	t->procedure.param_count = param_count;
 	t->procedure.results = results;
-	t->procedure.results_count = results_count;
+	t->procedure.result_count = result_count;
 	return t;
 }
 
@@ -343,6 +362,10 @@ b32 are_types_identical(Type *x, Type *y) {
 			return are_types_identical(x->pointer.element, y->pointer.element);
 		break;
 
+
+	case Type_Alias:
+		return are_types_identical(get_base_type(x), y);
+
 	case Type_Named:
 		if (y->kind == Type_Named)
 			return x->named.base == y->named.base;
@@ -463,9 +486,9 @@ i64 *type_set_offsets_of(BaseTypeSizes s, gbAllocator allocator, Entity **fields
 
 b32 type_set_offsets(BaseTypeSizes s, gbAllocator allocator, Type *t) {
 	GB_ASSERT(t->kind == Type_Structure);
-	if (!t->structure.offsets_set) {
+	if (!t->structure.are_offsets_set) {
 		t->structure.offsets = type_set_offsets_of(s, allocator, t->structure.fields, t->structure.field_count);
-		t->structure.offsets_set = true;
+		t->structure.are_offsets_set = true;
 		return true;
 	}
 	return false;
@@ -571,6 +594,15 @@ gbString write_type_to_string(gbString str, Type *type) {
 		}
 		break;
 
+	case Type_Alias:
+		if (type->alias.alias_name != NULL) {
+			str = gb_string_append_length(str, type->alias.name.text, type->alias.name.len);
+		} else {
+			// NOTE(bill): Just in case
+			str = gb_string_appendc(str, "<alias type>");
+		}
+		break;
+
 	case Type_Tuple:
 		if (type->tuple.variable_count > 0) {
 			for (isize i = 0; i < type->tuple.variable_count; i++) {

+ 13 - 0
src/common.cpp

@@ -31,6 +31,19 @@ gb_inline b32 are_strings_equal(String a, String b) {
 	return false;
 }
 
+gb_inline b32 are_strings_equal_ignore_case(String a, String b) {
+	if (a.len == b.len) {
+		for (isize i = 0; i < a.len; i++) {
+			char x = cast(char)a.text[i];
+			char y = cast(char)b.text[i];
+			if (gb_char_to_lower(x) != gb_char_to_lower(y))
+				return false;
+		}
+		return true;
+	}
+	return false;
+}
+
 
 gb_inline isize string_extension_position(String str) {
 	isize dot_pos = -1;

+ 92 - 69
src/parser.cpp

@@ -112,6 +112,7 @@ AstNode__DeclarationBegin,
 	AstNode_VariableDeclaration,
 	AstNode_ProcedureDeclaration,
 	AstNode_TypeDeclaration,
+	AstNode_AliasDeclaration,
 	AstNode_ImportDeclaration,
 AstNode__DeclarationEnd,
 
@@ -234,21 +235,16 @@ struct AstNode {
 			AstNode *name_list;
 			AstNode *type_expression;
 			AstNode *value_list;
-			isize name_list_count, value_list_count;
+			isize name_count, value_count;
 		} variable_declaration;
 
 		struct {
 			AstNode *name_list;
-			isize name_list_count;
+			isize name_count;
 			AstNode *type_expression;
 		} field;
-		struct {
-			Token token;
-			AstNode *param_list; // AstNode_Field list
-			isize param_count;
-			AstNode *results_list; // type expression list
-			isize result_count;
-		} procedure_type;
+
+		// TODO(bill): Unify Procedure Declarations and Literals
 		struct {
 			DeclarationKind kind;
 			AstNode *name;           // AstNode_Identifier
@@ -262,6 +258,11 @@ struct AstNode {
 			AstNode *name; // AstNode_Identifier
 			AstNode *type_expression;
 		} type_declaration;
+		struct {
+			Token token;
+			AstNode *name; // AstNode_Identifier
+			AstNode *type_expression;
+		} alias_declaration;
 		struct {
 			Token token;
 			Token filepath;
@@ -282,6 +283,13 @@ struct AstNode {
 			AstNode *field_list; // AstNode_Field
 			isize field_count;
 		} struct_type;
+		struct {
+			Token token;
+			AstNode *param_list; // AstNode_Field list
+			isize param_count;
+			AstNode *result_list; // type expression list
+			isize result_count;
+		} procedure_type;
 	};
 };
 
@@ -374,6 +382,8 @@ Token ast_node_token(AstNode *node) {
 		return node->procedure_declaration.name->identifier.token;
 	case AstNode_TypeDeclaration:
 		return node->type_declaration.token;
+	case AstNode_AliasDeclaration:
+		return node->alias_declaration.token;
 	case AstNode_ImportDeclaration:
 		return node->import_declaration.token;
 	case AstNode_Field: {
@@ -717,31 +727,31 @@ gb_inline AstNode *make_bad_declaration(AstFile *f, Token begin, Token end) {
 	return result;
 }
 
-gb_inline AstNode *make_variable_declaration(AstFile *f, DeclarationKind kind, AstNode *name_list, isize name_list_count, AstNode *type_expression, AstNode *value_list, isize value_list_count) {
+gb_inline AstNode *make_variable_declaration(AstFile *f, DeclarationKind kind, AstNode *name_list, isize name_count, AstNode *type_expression, AstNode *value_list, isize value_count) {
 	AstNode *result = make_node(f, AstNode_VariableDeclaration);
 	result->variable_declaration.kind = kind;
 	result->variable_declaration.name_list = name_list;
-	result->variable_declaration.name_list_count = name_list_count;
+	result->variable_declaration.name_count = name_count;
 	result->variable_declaration.type_expression = type_expression;
 	result->variable_declaration.value_list = value_list;
-	result->variable_declaration.value_list_count = value_list_count;
+	result->variable_declaration.value_count = value_count;
 	return result;
 }
 
-gb_inline AstNode *make_field(AstFile *f, AstNode *name_list, isize name_list_count, AstNode *type_expression) {
+gb_inline AstNode *make_field(AstFile *f, AstNode *name_list, isize name_count, AstNode *type_expression) {
 	AstNode *result = make_node(f, AstNode_Field);
 	result->field.name_list = name_list;
-	result->field.name_list_count = name_list_count;
+	result->field.name_count = name_count;
 	result->field.type_expression = type_expression;
 	return result;
 }
 
-gb_inline AstNode *make_procedure_type(AstFile *f, Token token, AstNode *param_list, isize param_count, AstNode *results_list, isize result_count) {
+gb_inline AstNode *make_procedure_type(AstFile *f, Token token, AstNode *param_list, isize param_count, AstNode *result_list, isize result_count) {
 	AstNode *result = make_node(f, AstNode_ProcedureType);
 	result->procedure_type.token = token;
 	result->procedure_type.param_list = param_list;
 	result->procedure_type.param_count = param_count;
-	result->procedure_type.results_list = results_list;
+	result->procedure_type.result_list = result_list;
 	result->procedure_type.result_count = result_count;
 	return result;
 }
@@ -788,6 +798,15 @@ gb_inline AstNode *make_type_declaration(AstFile *f, Token token, AstNode *name,
 	return result;
 }
 
+gb_inline AstNode *make_alias_declaration(AstFile *f, Token token, AstNode *name, AstNode *type_expression) {
+	AstNode *result = make_node(f, AstNode_AliasDeclaration);
+	result->alias_declaration.token = token;
+	result->alias_declaration.name = name;
+	result->alias_declaration.type_expression = type_expression;
+	return result;
+}
+
+
 gb_inline AstNode *make_import_declaration(AstFile *f, Token token, Token filepath) {
 	AstNode *result = make_node(f, AstNode_ImportDeclaration);
 	result->import_declaration.token = token;
@@ -1293,7 +1312,7 @@ AstNode *parse_rhs_expression_list(AstFile *f, isize *list_count) {
 	return parse_expression_list(f, false, list_count);
 }
 
-AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count);
+AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_count);
 
 AstNode *parse_simple_statement(AstFile *f) {
 	isize lhs_count = 0, rhs_count = 0;
@@ -1423,9 +1442,9 @@ AstNode *parse_type(AstFile *f) {
 
 AstNode *parse_field_declaration(AstFile *f, AstScope *scope) {
 	AstNode *name_list = NULL;
-	isize name_list_count = 0;
-	name_list = parse_lhs_expression_list(f, &name_list_count);
-	if (name_list_count == 0)
+	isize name_count = 0;
+	name_list = parse_lhs_expression_list(f, &name_count);
+	if (name_count == 0)
 		ast_file_err(f, f->cursor[0], "Empty field declaration");
 
 	expect_token(f, Token_Colon);
@@ -1434,7 +1453,7 @@ AstNode *parse_field_declaration(AstFile *f, AstScope *scope) {
 	if (type_expression == NULL)
 		ast_file_err(f, f->cursor[0], "Expected a type for this field declaration");
 
-	AstNode *field = make_field(f, name_list, name_list_count, type_expression);
+	AstNode *field = make_field(f, name_list, name_count, type_expression);
 	add_ast_entity(f, scope, field, name_list);
 	return field;
 }
@@ -1457,6 +1476,23 @@ AstNode *parse_procedure_type(AstFile *f, AstScope **scope_) {
 }
 
 
+AstNode *parse_parameter_list(AstFile *f, AstScope *scope, isize *param_count_) {
+	AstNode *param_list = NULL;
+	AstNode *param_list_curr = NULL;
+	isize param_count = 0;
+	while (f->cursor[0].kind == Token_Identifier) {
+		AstNode *field = parse_field_declaration(f, scope);
+		DLIST_APPEND(param_list, param_list_curr, field);
+		param_count += field->field.name_count;
+		if (f->cursor[0].kind != Token_Comma)
+			break;
+		next_token(f);
+	}
+
+	if (param_count_) *param_count_ = param_count;
+	return param_list;
+}
+
 AstNode *parse_identifier_or_type(AstFile *f) {
 	switch (f->cursor[0].kind) {
 	case Token_Identifier:
@@ -1480,24 +1516,15 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 	case Token_struct: {
 		Token token = expect_token(f, Token_struct);
 		Token open, close;
-		AstNode *field_list = NULL;
-		AstNode *field_list_curr = NULL;
-		isize field_list_count = 0;
-
-		open = expect_token(f, Token_OpenBrace);
-
+		AstNode *params = NULL;
+		isize param_count = 0;
 		AstScope *scope = make_ast_scope(f, NULL); // NOTE(bill): The struct needs its own scope with NO parent
-		while (f->cursor[0].kind == Token_Identifier ||
-		       f->cursor[0].kind == Token_Mul) {
-			DLIST_APPEND(field_list, field_list_curr, parse_field_declaration(f, scope));
-			expect_token(f, Token_Semicolon);
-			field_list_count++;
-		}
-		destroy_ast_scope(scope);
 
-		close = expect_token(f, Token_CloseBrace);
+		open   = expect_token(f, Token_OpenBrace);
+		params = parse_parameter_list(f, scope, &param_count);
+		close  = expect_token(f, Token_CloseBrace);
 
-		return make_struct_type(f, token, field_list, field_list_count);
+		return make_struct_type(f, token, params, param_count);
 	}
 
 	case Token_proc:
@@ -1514,6 +1541,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 		return make_paren_expression(f, type_expression, open, close);
 	}
 
+	// TODO(bill): Why is this even allowed? Is this a parsing error?
 	case Token_Colon:
 		break;
 
@@ -1530,24 +1558,6 @@ AstNode *parse_identifier_or_type(AstFile *f) {
 	return NULL;
 }
 
-AstNode *parse_parameters(AstFile *f, AstScope *scope, isize *param_count_) {
-	AstNode *param_list = NULL;
-	AstNode *param_list_curr = NULL;
-	isize param_count = 0;
-	expect_token(f, Token_OpenParen);
-	while (f->cursor[0].kind != Token_CloseParen) {
-		AstNode *field = parse_field_declaration(f, scope);
-		DLIST_APPEND(param_list, param_list_curr, field);
-		param_count += field->field.name_list_count;
-		if (f->cursor[0].kind != Token_Comma)
-			break;
-		next_token(f);
-	}
-	expect_token(f, Token_CloseParen);
-
-	if (param_count_) *param_count_ = param_count;
-	return param_list;
-}
 
 AstNode *parse_results(AstFile *f, AstScope *scope, isize *result_count) {
 	if (allow_token(f, Token_ArrowRight)) {
@@ -1582,7 +1592,9 @@ Token parse_procedure_signature(AstFile *f, AstScope *scope,
                                AstNode **param_list, isize *param_count,
                                AstNode **result_list, isize *result_count) {
 	Token proc_token = expect_token(f, Token_proc);
-	*param_list  = parse_parameters(f, scope, param_count);
+	expect_token(f, Token_OpenParen);
+	*param_list = parse_parameter_list(f, scope, param_count);
+	expect_token(f, Token_CloseParen);
 	*result_list = parse_results(f, scope, result_count);
 	return proc_token;
 }
@@ -1626,10 +1638,10 @@ AstNode *parse_procedure_declaration(AstFile *f, Token proc_token, AstNode *name
 	return make_procedure_declaration(f, kind, name, proc_type, body, tag_list, tag_count);
 }
 
-AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count) {
+AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_count) {
 	AstNode *value_list = NULL;
 	AstNode *type_expression = NULL;
-	isize value_list_count = 0;
+	isize value_count = 0;
 	if (allow_token(f, Token_Colon)) {
 		type_expression = parse_identifier_or_type(f);
 	} else if (f->cursor[0].kind != Token_Eq && f->cursor[0].kind != Token_Semicolon) {
@@ -1647,26 +1659,20 @@ AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count
 		if (f->cursor[0].kind == Token_proc) { // NOTE(bill): Procedure declarations
 			Token proc_token = f->cursor[0];
 			AstNode *name = name_list;
-			if (name_list_count != 1) {
+			if (name_count != 1) {
 				ast_file_err(f, proc_token, "You can only declare one procedure at a time (at the moment)");
 				return make_bad_declaration(f, name->identifier.token, proc_token);
 			}
 
-			// TODO(bill): Allow for mutable procedures
-			if (declaration_kind != Declaration_Immutable) {
-				ast_file_err(f, proc_token, "Only immutable procedures are supported (at the moment)");
-				return make_bad_declaration(f, name->identifier.token, proc_token);
-			}
-
 			AstNode *procedure_declaration = parse_procedure_declaration(f, proc_token, name, declaration_kind);
 			add_ast_entity(f, f->curr_scope, procedure_declaration, name_list);
 			return procedure_declaration;
 
 		} else {
-			value_list = parse_rhs_expression_list(f, &value_list_count);
-			if (value_list_count > name_list_count) {
+			value_list = parse_rhs_expression_list(f, &value_count);
+			if (value_count > name_count) {
 				ast_file_err(f, f->cursor[0], "Too many values on the right hand side of the declaration");
-			} else if (value_list_count < name_list_count &&
+			} else if (value_count < name_count &&
 			           declaration_kind == Declaration_Immutable) {
 				ast_file_err(f, f->cursor[0], "All constant declarations must be defined");
 			} else if (value_list == NULL) {
@@ -1681,7 +1687,7 @@ AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count
 			return make_bad_declaration(f, f->cursor[0], f->cursor[0]);
 		}
 	} else if (declaration_kind == Declaration_Immutable) {
-		if (type_expression == NULL && value_list == NULL && name_list_count > 0) {
+		if (type_expression == NULL && value_list == NULL && name_count > 0) {
 			ast_file_err(f, f->cursor[0], "Missing constant value");
 			return make_bad_declaration(f, f->cursor[0], f->cursor[0]);
 		}
@@ -1692,7 +1698,7 @@ AstNode *parse_declaration(AstFile *f, AstNode *name_list, isize name_list_count
 		return make_bad_declaration(f, begin, f->cursor[0]);
 	}
 
-	AstNode *variable_declaration = make_variable_declaration(f, declaration_kind, name_list, name_list_count, type_expression, value_list, value_list_count);
+	AstNode *variable_declaration = make_variable_declaration(f, declaration_kind, name_list, name_count, type_expression, value_list, value_count);
 	add_ast_entity(f, f->curr_scope, variable_declaration, name_list);
 	return variable_declaration;
 }
@@ -1858,6 +1864,21 @@ AstNode *parse_type_declaration(AstFile *f) {
 	return type_declaration;
 }
 
+AstNode *parse_alias_declaration(AstFile *f) {
+	Token   token = expect_token(f, Token_alias);
+	AstNode *name = parse_identifier(f);
+	expect_token(f, Token_Colon);
+	AstNode *type_expression = parse_type(f);
+
+	AstNode *alias_declaration = make_alias_declaration(f, token, name, type_expression);
+
+	if (type_expression->kind != AstNode_StructType &&
+	    type_expression->kind != AstNode_ProcedureType)
+		expect_token(f, Token_Semicolon);
+
+	return alias_declaration;
+}
+
 AstNode *parse_import_declaration(AstFile *f) {
 	Token token = expect_token(f, Token_import);
 	Token filepath = expect_token(f, Token_String);
@@ -1874,6 +1895,8 @@ AstNode *parse_statement(AstFile *f) {
 	switch (token.kind) {
 	case Token_type:
 		return parse_type_declaration(f);
+	case Token_alias:
+		return parse_alias_declaration(f);
 	case Token_import:
 		return parse_import_declaration(f);
 

+ 2 - 2
src/printer.cpp

@@ -166,10 +166,10 @@ void print_ast(AstNode *node, isize indent) {
 		print_indent(indent);
 		gb_printf("(type:proc)(%td -> %td)\n", node->procedure_type.param_count, node->procedure_type.result_count);
 		print_ast(node->procedure_type.param_list, indent+1);
-		if (node->procedure_type.results_list) {
+		if (node->procedure_type.result_list) {
 			print_indent(indent+1);
 			gb_printf("->\n");
-			print_ast(node->procedure_type.results_list, indent+1);
+			print_ast(node->procedure_type.result_list, indent+1);
 		}
 		break;
 	case AstNode_Field:

+ 3 - 0
src/tokenizer.cpp

@@ -102,6 +102,7 @@ Token__OperatorEnd,
 
 Token__KeywordBegin,
 	Token_type,
+	Token_alias,
 	Token_proc,
 	Token_match, // TODO(bill): switch vs match?
 	Token_break,
@@ -189,6 +190,7 @@ char const *TOKEN_STRINGS[] = {
 "_OperatorEnd",
 "_KeywordBegin",
 	"type",
+	"alias",
 	"proc",
 	"match",
 	"break",
@@ -697,6 +699,7 @@ Token tokenizer_get_token(Tokenizer *t) {
 
 			KWB
 			KWT("type",        Token_type);
+			KWT("alias",       Token_alias);
 			KWT("proc",        Token_proc);
 			KWT("match",       Token_match);
 			KWT("break",       Token_break);