2
0
Эх сурвалжийг харах

Named return values but do not affect other declarations

Ginger Bill 8 жил өмнө
parent
commit
9ff474f387
4 өөрчлөгдсөн 177 нэмэгдсэн , 124 устгасан
  1. 7 2
      core/fmt.odin
  2. 92 27
      src/check_expr.c
  3. 5 3
      src/ir.c
  4. 73 92
      src/parser.c

+ 7 - 2
core/fmt.odin

@@ -293,7 +293,7 @@ sprintf :: proc(buf: []byte, fmt: string, args: ...any) -> string {
 
 
 
-parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
+parse_int :: proc(s: string, offset: int) -> (result: int, offset: int, ok: bool) {
 	is_digit :: proc(r: rune) -> bool #inline {
 		return '0' <= r && r <= '9';
 	}
@@ -316,7 +316,12 @@ parse_int :: proc(s: string, offset: int) -> (int, int, bool) {
 	return result, offset+i, i != 0;
 }
 
-_arg_number :: proc(fi: ^Fmt_Info, arg_index: int, format: string, offset: int, arg_count: int) -> (int, int, bool) {
+_arg_number :: proc(fi: ^Fmt_Info,
+                    arg_index: int,
+                    format: string,
+                    offset: int,
+                    arg_count: int,
+                    ) -> (index: int, offset: int, ok: bool) {
 	parse_arg_number :: proc(format: string) -> (int, int, bool) {
 		if format.count < 3 {
 			return 0, 1, false;

+ 92 - 27
src/check_expr.c

@@ -798,7 +798,13 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
 }
 
 
-Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_variadic_) {
+Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_variadic_) {
+	if (_params == NULL) {
+		return NULL;
+	}
+	ast_node(field_list, FieldList, _params);
+	AstNodeArray params = field_list->list;
+
 	if (params.count == 0) {
 		return NULL;
 	}
@@ -808,7 +814,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 		AstNode *field = params.e[i];
 		if (ast_node_expect(field, AstNode_Field)) {
 			ast_node(f, Field, field);
-			variable_count += f->names.count;
+			variable_count += max(f->names.count, 1);
 		}
 	}
 
@@ -877,26 +883,73 @@ Type *check_get_params(Checker *c, Scope *scope, AstNodeArray params, bool *is_v
 	return tuple;
 }
 
-Type *check_get_results(Checker *c, Scope *scope, AstNodeArray results) {
+Type *check_get_results(Checker *c, Scope *scope, AstNode *_results) {
+	if (_results == NULL) {
+		return NULL;
+	}
+	ast_node(field_list, FieldList, _results);
+	AstNodeArray results = field_list->list;
+
 	if (results.count == 0) {
 		return NULL;
 	}
 	Type *tuple = make_type_tuple(c->allocator);
 
-	Entity **variables = gb_alloc_array(c->allocator, Entity *, results.count);
+	isize variable_count = 0;
+	for_array(i, results) {
+		AstNode *field = results.e[i];
+		if (ast_node_expect(field, AstNode_Field)) {
+			ast_node(f, Field, field);
+			variable_count += max(f->names.count, 1);
+		}
+	}
+
+	Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
 	isize variable_index = 0;
 	for_array(i, results) {
-		AstNode *item = results.e[i];
-		Type *type = check_type(c, item);
-		Token token = ast_node_token(item);
-		token.string = str_lit(""); // NOTE(bill): results are not named
-		// TODO(bill): Should I have named results?
-		Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
-		// NOTE(bill): No need to record
-		variables[variable_index++] = param;
+		ast_node(field, Field, results.e[i]);
+		Type *type = check_type(c, field->type);
+		if (field->names.count == 0) {
+			Token token = ast_node_token(field->type);
+			token.string = str_lit("");
+			Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+			variables[variable_index++] = param;
+		} else {
+			for_array(j, field->names) {
+				Token token = ast_node_token(field->type);
+				token.string = str_lit("");
+
+				AstNode *name = field->names.e[j];
+				if (name->kind != AstNode_Ident) {
+					error_node(name, "Expected an identifer for as the field name");
+				} else {
+					token = name->Ident;
+				}
+
+				Entity *param = make_entity_param(c->allocator, scope, token, type, false, false);
+				variables[variable_index++] = param;
+			}
+		}
 	}
+
+	for (isize i = 0; i < variable_index; i++) {
+		String x = variables[i]->token.string;
+		if (x.len == 0 || str_eq(x, str_lit("_"))) {
+			continue;
+		}
+		for (isize j = i+1; j < variable_index; j++) {
+			String y = variables[j]->token.string;
+			if (y.len == 0 || str_eq(y, str_lit("_"))) {
+				continue;
+			}
+			if (str_eq(x, y)) {
+				error(variables[j]->token, "Duplicate return value name `%.*s`", LIT(y));
+			}
+		}
+	}
+
 	tuple->Tuple.variables = variables;
-	tuple->Tuple.variable_count = results.count;
+	tuple->Tuple.variable_count = variable_index;
 
 	return tuple;
 }
@@ -5126,16 +5179,6 @@ void check_expr_or_type(Checker *c, Operand *o, AstNode *e) {
 
 gbString write_expr_to_string(gbString str, AstNode *node);
 
-gbString write_params_to_string(gbString str, AstNodeArray params, char *sep) {
-	for_array(i, params) {
-		if (i > 0) {
-			str = gb_string_appendc(str, sep);
-		}
-		str = write_expr_to_string(str, params.e[i]);
-	}
-	return str;
-}
-
 gbString write_record_fields_to_string(gbString str, AstNodeArray params) {
 	for_array(i, params) {
 		if (i > 0) {
@@ -5301,6 +5344,13 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 		if (f->flags&FieldFlag_using) {
 			str = gb_string_appendc(str, "using ");
 		}
+		if (f->flags&FieldFlag_immutable) {
+			str = gb_string_appendc(str, "immutable ");
+		}
+		if (f->flags&FieldFlag_no_alias) {
+			str = gb_string_appendc(str, "no_alias ");
+		}
+
 		for_array(i, f->names) {
 			AstNode *name = f->names.e[i];
 			if (i > 0) {
@@ -5308,14 +5358,24 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 			}
 			str = write_expr_to_string(str, name);
 		}
-
-		str = gb_string_appendc(str, ": ");
+		if (f->names.count > 0) {
+			str = gb_string_appendc(str, ": ");
+		}
 		if (f->flags&FieldFlag_ellipsis) {
 			str = gb_string_appendc(str, "...");
 		}
 		str = write_expr_to_string(str, f->type);
 	case_end;
 
+	case_ast_node(f, FieldList, node);
+		for_array(i, f->list) {
+			if (i > 0) {
+				str = gb_string_appendc(str, ", ");
+			}
+			str = write_expr_to_string(str, f->list.e[i]);
+		}
+	case_end;
+
 	case_ast_node(ce, CallExpr, node);
 		str = write_expr_to_string(str, ce->proc);
 		str = gb_string_appendc(str, "(");
@@ -5332,7 +5392,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 
 	case_ast_node(pt, ProcType, node);
 		str = gb_string_appendc(str, "proc(");
-		str = write_params_to_string(str, pt->params, ", ");
+		str = write_expr_to_string(str, pt->params);
 		str = gb_string_appendc(str, ")");
 	case_end;
 
@@ -5366,7 +5426,12 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
 			str = gb_string_appendc(str, " ");
 		}
 		str = gb_string_appendc(str, "{");
-		str = write_params_to_string(str, et->fields, ", ");
+		for_array(i, et->fields) {
+			if (i > 0) {
+				str = gb_string_appendc(str, ", ");
+			}
+			str = write_expr_to_string(str, et->fields.e[i]);
+		}
 		str = gb_string_appendc(str, "}");
 	case_end;
 

+ 5 - 3
src/ir.c

@@ -5600,12 +5600,14 @@ void ir_begin_procedure_body(irProcedure *proc) {
 
 		TypeTuple *params = &proc->type->Proc.params->Tuple;
 		for (isize i = 0; i < params->variable_count; i++) {
-			GB_ASSERT(pt->params.e[0]->kind == AstNode_Field);
-			if (q_index == pt->params.e[param_index]->Field.names.count) {
+			ast_node(fl, FieldList, pt->params);
+			GB_ASSERT(fl->list.count > 0);
+			GB_ASSERT(fl->list.e[0]->kind == AstNode_Field);
+			if (q_index == fl->list.e[param_index]->Field.names.count) {
 				q_index = 0;
 				param_index++;
 			}
-			ast_node(field, Field, pt->params.e[param_index]);
+			ast_node(field, Field, fl->list.e[param_index]);
 			AstNode *name = field->names.e[q_index++];
 
 			Entity *e = params->variables[i];

+ 73 - 92
src/parser.c

@@ -302,16 +302,20 @@ AST_NODE_KIND(_DeclEnd,   "", i32) \
 		AstNode *    type;     \
 		u32          flags;    \
 	}) \
+	AST_NODE_KIND(FieldList, "field list", struct { \
+		Token token; \
+		AstNodeArray list; \
+	}) \
 AST_NODE_KIND(_TypeBegin, "", i32) \
 	AST_NODE_KIND(HelperType, "type", struct { \
 		Token token; \
 		AstNode *type; \
 	}) \
 	AST_NODE_KIND(ProcType, "procedure type", struct { \
-		Token token;          \
-		AstNodeArray params;  \
-		AstNodeArray results; \
-		u64          tags;    \
+		Token    token;   \
+		AstNode *params;  \
+		AstNode *results; \
+		u64      tags;    \
 		ProcCallingConvention calling_convention; \
 	}) \
 	AST_NODE_KIND(PointerType, "pointer type", struct { \
@@ -478,11 +482,14 @@ Token ast_node_token(AstNode *node) {
 	case AstNode_ImportDecl:     return node->ImportDecl.token;
 	case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
 
+
 	case AstNode_Field:
 		if (node->Field.names.count > 0) {
 			return ast_node_token(node->Field.names.e[0]);
 		}
 		return ast_node_token(node->Field.type);
+	case AstNode_FieldList:
+		return node->FieldList.token;
 
 	case AstNode_HelperType:       return node->HelperType.token;
 	case AstNode_ProcType:         return node->ProcType.token;
@@ -952,6 +959,13 @@ AstNode *ast_field(AstFile *f, AstNodeArray names, AstNode *type, u32 flags) {
 	return result;
 }
 
+AstNode *ast_field_list(AstFile *f, Token token, AstNodeArray list) {
+	AstNode *result = make_ast_node(f, AstNode_FieldList);
+	result->FieldList.token = token;
+	result->FieldList.list  = list;
+	return result;
+}
+
 
 AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
 	AstNode *result = make_ast_node(f, AstNode_HelperType);
@@ -961,7 +975,7 @@ AstNode *ast_helper_type(AstFile *f, Token token, AstNode *type) {
 }
 
 
-AstNode *ast_proc_type(AstFile *f, Token token, AstNodeArray params, AstNodeArray results, u64 tags, ProcCallingConvention calling_convention) {
+AstNode *ast_proc_type(AstFile *f, Token token, AstNode *params, AstNode *results, u64 tags, ProcCallingConvention calling_convention) {
 	AstNode *result = make_ast_node(f, AstNode_ProcType);
 	result->ProcType.token = token;
 	result->ProcType.params = params;
@@ -1308,7 +1322,6 @@ AstNode *    parse_proc_type(AstFile *f, AstNode **foreign_library, String *fore
 AstNodeArray parse_stmt_list(AstFile *f);
 AstNode *    parse_stmt(AstFile *f);
 AstNode *    parse_body(AstFile *f);
-void         parse_proc_signature(AstFile *f, AstNodeArray *params, AstNodeArray *results);
 
 
 
@@ -2258,15 +2271,39 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
 	return parse_body(f);
 }
 
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
+
 
+AstNode *parse_results(AstFile *f) {
+	if (!allow_token(f, Token_ArrowRight)) {
+		return NULL;
+	}
 
+	if (f->curr_token.kind != Token_OpenParen) {
+		Token begin_token = f->curr_token;
+		AstNodeArray empty_names = {0};
+		AstNodeArray list = make_ast_node_array(f);
+		AstNode *type = parse_type(f);
+		array_add(&list, ast_field(f, empty_names, type, 0));
+		return ast_field_list(f, begin_token, list);
+	}
+
+	AstNode *list = NULL;
+	expect_token(f, Token_OpenParen);
+	list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
+	expect_token_after(f, Token_CloseParen, "parameter list");
+	return list;
+}
 
 AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
-	AstNodeArray params = {0};
-	AstNodeArray results = {0};
+	AstNode *params = {0};
+	AstNode *results = {0};
 
 	Token proc_token = expect_token(f, Token_proc);
-	parse_proc_signature(f, &params, &results);
+	expect_token(f, Token_OpenParen);
+	params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
+	expect_token_after(f, Token_CloseParen, "parameter list");
+	results = parse_results(f);
 
 	u64 tags = 0;
 	String foreign_name = {0};
@@ -2404,8 +2441,9 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
 	return idents;
 }
 
-AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
-                              TokenKind separator, TokenKind follow) {
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
+	Token start_token = f->curr_token;
+
 	AstNodeArray params = make_ast_node_array(f);
 	AstNodeAndFlagsArray list = {0}; array_init(&list, heap_allocator()); // LEAK(bill):
 	isize total_name_count = 0;
@@ -2465,7 +2503,7 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
 		}
 
 		if (name_count_) *name_count_ = total_name_count;
-		return params;
+		return ast_field_list(f, start_token, params);
 	}
 
 	for_array(i, list) {
@@ -2483,11 +2521,11 @@ AstNodeArray parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags,
 	}
 
 	if (name_count_) *name_count_ = total_name_count;
-	return params;
+	return ast_field_list(f, start_token, params);
 }
 
 
-AstNodeArray parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
+AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
 	return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
 }
 
@@ -2617,9 +2655,15 @@ AstNode *parse_type_or_ident(AstFile *f) {
 
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
+		AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("struct"));
 		Token close = expect_token(f, Token_CloseBrace);
 
+		AstNodeArray decls = {0};
+		if (fields != NULL) {
+			GB_ASSERT(fields->kind == AstNode_FieldList);
+			decls = fields->FieldList.list;
+		}
+
 		return ast_struct_type(f, token, decls, decl_count, is_packed, is_ordered, align);
 	} break;
 
@@ -2627,9 +2671,15 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Token token = expect_token(f, Token_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, 0, str_lit("union"));
+		AstNode *fields = parse_record_fields(f, &decl_count, 0, str_lit("union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
+		AstNodeArray decls = {0};
+		if (fields != NULL) {
+			GB_ASSERT(fields->kind == AstNode_FieldList);
+			decls = fields->FieldList.list;
+		}
+
 		return ast_union_type(f, token, decls, decl_count);
 	}
 
@@ -2637,9 +2687,15 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Token token = expect_token(f, Token_raw_union);
 		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
 		isize decl_count = 0;
-		AstNodeArray decls = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
+		AstNode *fields = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("raw_union"));
 		Token close = expect_token(f, Token_CloseBrace);
 
+		AstNodeArray decls = {0};
+		if (fields != NULL) {
+			GB_ASSERT(fields->kind == AstNode_FieldList);
+			decls = fields->FieldList.list;
+		}
+
 		return ast_raw_union_type(f, token, decls, decl_count);
 	}
 
@@ -2679,39 +2735,6 @@ AstNode *parse_type_or_ident(AstFile *f) {
 }
 
 
-AstNodeArray parse_results(AstFile *f) {
-	AstNodeArray results = make_ast_node_array(f);
-	if (allow_token(f, Token_ArrowRight)) {
-		if (f->curr_token.kind == Token_OpenParen) {
-			expect_token(f, Token_OpenParen);
-			while (f->curr_token.kind != Token_CloseParen &&
-			       f->curr_token.kind != Token_EOF) {
-				array_add(&results, parse_type(f));
-				if (f->curr_token.kind != Token_Comma) {
-					break;
-				}
-				next_token(f);
-			}
-			expect_token(f, Token_CloseParen);
-
-			return results;
-		}
-
-		array_add(&results, parse_type(f));
-		return results;
-	}
-	return results;
-}
-
-void parse_proc_signature(AstFile *f,
-                          AstNodeArray *params,
-                          AstNodeArray *results) {
-	expect_token(f, Token_OpenParen);
-	*params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
-	expect_token_after(f, Token_CloseParen, "parameter list");
-	*results = parse_results(f);
-}
-
 AstNode *parse_body(AstFile *f) {
 	AstNodeArray stmts = {0};
 	Token open, close;
@@ -2727,48 +2750,6 @@ AstNode *parse_body(AstFile *f) {
 	return ast_block_stmt(f, stmts, open, close);
 }
 
-
-/*
-AstNode *parse_proc_decl(AstFile *f) {
-	if (look_ahead_token_kind(f, 1) == Token_OpenParen) {
-		// NOTE(bill): It's an anonymous procedure
-		// NOTE(bill): This look-ahead technically makes the grammar LALR(2)
-		// but is that a problem in practice?
-		return ast_expr_stmt(f, parse_expr(f, true));
-	}
-
-	AstNodeArray params = {0};
-	AstNodeArray results = {0};
-
-	Token proc_token = expect_token(f, Token_proc);
-	AstNode *name = parse_ident(f);
-	parse_proc_signature(f, &params, &results);
-
-	u64 tags = 0;
-	String foreign_name = {0};
-	String link_name = {0};
-	ProcCallingConvention cc = ProcCC_Odin;
-
-	parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
-
-	AstNode *proc_type = ast_proc_type(f, proc_token, params, results, tags, cc);
-	AstNode *body = NULL;
-
-	if (f->curr_token.kind == Token_OpenBrace) {
-		if ((tags & ProcTag_foreign) != 0) {
-			syntax_error(proc_token, "A procedure tagged as `#foreign` cannot have a body");
-		}
-		AstNode *curr_proc = f->curr_proc;
-		f->curr_proc = proc_type;
-		body = parse_body(f);
-		f->curr_proc = curr_proc;
-	} else if ((tags & ProcTag_foreign) == 0) {
-		syntax_error(proc_token, "Only a procedure tagged as `#foreign` cannot have a body");
-	}
-
-	return ast_proc_decl(f, name, proc_type, body, tags, foreign_name, link_name);
-} */
-
 AstNode *parse_if_stmt(AstFile *f) {
 	if (f->curr_proc == NULL) {
 		syntax_error(f->curr_token, "You cannot use an if statement in the file scope");