Browse Source

Make record semicolon syntax more consistent

Ginger Bill 8 years ago
parent
commit
069a47220e
5 changed files with 115 additions and 157 deletions
  1. 1 1
      code/demo.odin
  2. 2 2
      core/_soft_numbers.odin
  3. 2 2
      core/fmt.odin
  4. 40 20
      src/check_expr.cpp
  5. 70 132
      src/parser.cpp

+ 1 - 1
code/demo.odin

@@ -253,7 +253,7 @@ explicit_parametric_polymorphic_procedures :: proc() {
 
 	// A more complicated example using subtyping
 	// Something like this could be used in a game
-	Vector2 :: struct {x, y: f32};
+	Vector2 :: struct {x, y: f32;};
 
 	Entity :: struct {
 		using position: Vector2;

+ 2 - 2
core/_soft_numbers.odin

@@ -8,12 +8,12 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
 	when ODIN_ENDIAN == "bit" {
 		TWords :: raw_union {
 			all: u128;
-			using _: struct {lo, hi: u64};
+			using _: struct {lo, hi: u64;};
 		};
 	} else {
 		TWords :: raw_union {
 			all: u128;
-			using _: struct {hi, lo: u64};
+			using _: struct {hi, lo: u64;};
 		};
 	}
 

+ 2 - 2
core/fmt.odin

@@ -10,8 +10,8 @@ import (
 _BUFFER_SIZE :: 1<<12;
 
 StringBuffer :: union {
-	Static {buf: []u8};
-	Dynamic{buf: [dynamic]u8};
+	Static {buf: []u8;};
+	Dynamic{buf: [dynamic]u8;};
 }
 
 FmtInfo :: struct {

+ 40 - 20
src/check_expr.cpp

@@ -710,21 +710,36 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
 	isize field_index = 0;
 	for_array(decl_index, decls) {
 		AstNode *decl = decls[decl_index];
-		if (decl->kind != AstNode_Field) {
+		if (decl->kind != AstNode_ValueDecl) {
 			continue;
 		}
-		ast_node(f, Field, decl);
+		ast_node(vd, ValueDecl, decl);
 
-		Type *type = check_type(c, f->type);
-		bool is_using = (f->flags&FieldFlag_using) != 0;
+		Type *type = nullptr;
+		if (vd->type != nullptr) {
+			type = check_type(c, vd->type);
+		} else {
+			error(vd->names[0], "Expected a type for this field");
+			type = t_invalid;
+		}
+		bool is_using = (vd->flags&VarDeclFlag_using) != 0;
 
-		if (is_using && f->names.count > 1) {
-			error(f->names[0], "Cannot apply `using` to more than one of the same type");
+		if (is_using && vd->names.count > 1) {
+			error(vd->names[0], "Cannot apply `using` to more than one of the same type");
 			is_using = false;
 		}
 
-		for_array(name_index, f->names) {
-			AstNode *name = f->names[name_index];
+		if (!vd->is_mutable) {
+			error(vd->names[0], "Immutable values in a %.*s are not yet supported", LIT(context));
+			continue;
+		}
+
+		if (vd->values.count) {
+			error(vd->values[0], "Default values are not allowed within a %.*s", LIT(context));
+		}
+
+		for_array(name_index, vd->names) {
+			AstNode *name = vd->names[name_index];
 			if (!ast_node_expect(name, AstNode_Ident)) {
 				continue;
 			}
@@ -759,16 +774,16 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
 		if (is_using) {
 			Type *t = base_type(type_deref(type));
 			if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) &&
-			    f->names.count >= 1 &&
-			    f->names[0]->kind == AstNode_Ident) {
-				Token name_token = f->names[0]->Ident.token;
+			    vd->names.count >= 1 &&
+			    vd->names[0]->kind == AstNode_Ident) {
+				Token name_token = vd->names[0]->Ident.token;
 				if (is_type_indexable(t)) {
 					bool ok = true;
 					for_array(emi, entity_map.entries) {
 						Entity *e = entity_map.entries[emi].value;
 						if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
 							if (is_type_indexable(e->type)) {
-								if (e->identifier != f->names[0]) {
+								if (e->identifier != vd->names[0]) {
 									ok = false;
 									using_index_expr = e;
 									break;
@@ -852,7 +867,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
 	for_array(field_index, st->fields) {
 	AstNode *field = st->fields[field_index];
 		switch (field->kind) {
-		case_ast_node(f, Field, field);
+		case_ast_node(f, ValueDecl, field);
 			field_count += f->names.count;
 		case_end;
 		}
@@ -947,9 +962,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 	isize field_count = 0;
 	for_array(i, ut->fields) {
 		AstNode *field = ut->fields[i];
-		if (field->kind == AstNode_Field) {
-			ast_node(f, Field, field);
+		switch (field->kind) {
+		case_ast_node(f, ValueDecl, field);
 			field_count += f->names.count;
+		case_end;
 		}
 	}
 
@@ -1005,8 +1021,12 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
 
 			isize list_count = 0;
 			for_array(j, list) {
-				ast_node(f, Field, list[j]);
-				list_count += f->names.count;
+				if (list[j]->kind == AstNode_Field) {
+					list_count += list[j]->Field.names.count;
+				} else {
+					ast_node(f, ValueDecl, list[j]);
+					list_count += f->names.count;
+				}
 			}
 
 
@@ -1067,10 +1087,10 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
 	ast_node(ut, RawUnionType, node);
 
 	isize field_count = 0;
-	for_array(field_index, ut->fields) {
-		AstNode *field = ut->fields[field_index];
+	for_array(i, ut->fields) {
+		AstNode *field = ut->fields[i];
 		switch (field->kind) {
-		case_ast_node(f, Field, field);
+		case_ast_node(f, ValueDecl, field);
 			field_count += f->names.count;
 		case_end;
 		}

+ 70 - 132
src/parser.cpp

@@ -1880,13 +1880,11 @@ void expect_semicolon(AstFile *f, AstNode *s) {
 				return;
 			}
 		} else {
-			// switch (s->kind) {
-			// case AstNode_GiveExpr:
-			// 	if (f->curr_token.kind == Token_CloseBrace) {
-			// 		return;
-			// 	}
-			// 	break;
-			// }
+			if (s->kind == AstNode_ValueDecl) {
+				if (f->curr_token.kind == Token_CloseBrace) {
+					return;
+				}
+			}
 		}
 		String node_string = ast_node_strings[s->kind];
 		if (s->kind == AstNode_GenDecl) {
@@ -3007,7 +3005,6 @@ AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs)
 		}
 	}
 
-
 	if (is_mutable) {
 		if (type == nullptr && values.count == 0) {
 			syntax_error(f->curr_token, "Missing variable type or initialization");
@@ -3029,7 +3026,12 @@ AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs)
 		if (!is_mutable && values.count > 0) {
 			end = values[values.count-1];
 		}
-		expect_semicolon(f, end);
+		if (f->curr_token.kind == Token_CloseBrace &&
+		    f->curr_token.pos.line == f->prev_token.pos.line) {
+
+		} else {
+			expect_semicolon(f, end);
+		}
 	}
 
 	return ast_value_decl(f, names, type, values, is_mutable, docs, f->line_comment);
@@ -3377,98 +3379,36 @@ bool parse_expect_struct_separator(AstFile *f, AstNode *param) {
 }
 
 
-AstNode *parse_struct_field_list(AstFile *f, isize *name_count_) {
+AstNode *parse_record_field_list(AstFile *f, isize *name_count_) {
 	CommentGroup docs = f->lead_comment;
 	Token start_token = f->curr_token;
 
-	Array<AstNode *> params = make_ast_node_array(f);
-	Array<AstNodeAndFlags> list = {}; array_init(&list, heap_allocator());
-	defer (array_free(&list));
+	Array<AstNode *> decls = make_ast_node_array(f);
 
 	isize total_name_count = 0;
 
 	while (f->curr_token.kind != Token_CloseBrace &&
-	       f->curr_token.kind != Token_Colon &&
 	       f->curr_token.kind != Token_EOF) {
-		u32 flags = parse_field_prefixes(f);
-		AstNode *param = parse_var_type(f, false, false);
-		AstNodeAndFlags naf = {param, flags};
-		array_add(&list, naf);
-		if (f->curr_token.kind != Token_Comma) {
-			break;
-		}
-		next_token(f);
-	}
-
-	if (f->curr_token.kind == Token_Colon) {
-		Array<AstNode *> names = convert_to_ident_list(f, list, true); // Copy for semantic reasons
-		if (names.count == 0) {
-			syntax_error(f->curr_token, "Empty field declaration");
-		}
-		u32 set_flags = 0;
-		if (list.count > 0) {
-			set_flags = list[0].flags;
-		}
-		set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags);
-		total_name_count += names.count;
-
-		AstNode *type = nullptr;
-
-		expect_token_after(f, Token_Colon, "field list");
-		type = parse_var_type(f, false, false);
-
-		parse_expect_struct_separator(f, type);
-		AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment);
-		array_add(&params, param);
-
-
-		while (f->curr_token.kind != Token_CloseBrace &&
-		       f->curr_token.kind != Token_EOF) {
-			CommentGroup docs = f->lead_comment;
-
-			u32 set_flags = parse_field_prefixes(f);
-			Array<AstNode *> names = parse_ident_list(f);
-			if (names.count == 0) {
-				syntax_error(f->curr_token, "Empty field declaration");
-				break;
-			}
-			set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags);
-			total_name_count += names.count;
-
-			AstNode *type = nullptr;
-
-			expect_token_after(f, Token_Colon, "field list");
-			type = parse_var_type(f, false, false);
-
-			bool ok = parse_expect_struct_separator(f, param);
-			AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment);
-			array_add(&params, param);
-
-			if (!ok) {
-				break;
+		AstNode *decl = parse_stmt(f);
+		if (decl->kind != AstNode_ValueDecl) {
+			error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind]));
+		} else {
+			ast_node(vd, ValueDecl, decl);
+			if (vd->is_mutable) {
+				if (vd->flags&VarDeclFlag_thread_local) {
+					vd->flags &= ~VarDeclFlag_thread_local;
+					error(decl, "Field values cannot be #thread_local");
+				}
+				array_add(&decls, decl);
+				total_name_count += vd->names.count;
+			} else {
+				error(decl, "Only variable declarations are allowed at the moment");
 			}
 		}
-
-		if (name_count_) *name_count_ = total_name_count;
-		return ast_field_list(f, start_token, params);
-	}
-
-	for_array(i, list) {
-		Array<AstNode *> names = {};
-		AstNode *type = list[i].node;
-		Token token = blank_token;
-
-		array_init_count(&names, heap_allocator(), 1);
-		token.pos = ast_node_token(type).pos;
-		names[0] = ast_ident(f, token);
-		u32 flags = check_field_prefixes(f, list.count, FieldFlag_using, list[i].flags);
-
-		AstNode *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
-		array_add(&params, param);
 	}
 
 	if (name_count_) *name_count_ = total_name_count;
-	return ast_field_list(f, start_token, params);
+	return ast_field_list(f, start_token, decls);
 }
 
 AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) {
@@ -3597,11 +3537,6 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
 	return ast_field_list(f, start_token, params);
 }
 
-
-AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
-	return parse_field_list(f, field_count_, flags, Token_CloseBrace, false);
-}
-
 AstNode *parse_type_or_ident(AstFile *f) {
 	switch (f->curr_token.kind) {
 	case Token_Dollar: {
@@ -3748,7 +3683,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Token open = expect_token_after(f, Token_OpenBrace, "struct");
 
 		isize    name_count = 0;
-		AstNode *fields     = parse_struct_field_list(f, &name_count);
+		AstNode *fields     = parse_record_field_list(f, &name_count);
 		Token    close      = expect_token(f, Token_CloseBrace);
 
 		Array<AstNode *> decls = {};
@@ -3767,50 +3702,57 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Array<AstNode *> variants = make_ast_node_array(f);
 		isize total_decl_name_count = 0;
 
+		CommentGroup docs = f->lead_comment;
+		Token start_token = f->curr_token;
+
+
 		while (f->curr_token.kind != Token_CloseBrace &&
 		       f->curr_token.kind != Token_EOF) {
 			CommentGroup docs = f->lead_comment;
-			u32 decl_flags = parse_field_prefixes(f);
-			if (decl_flags != 0) {
-				Array<AstNode *> names = parse_ident_list(f);
-				if (names.count == 0) {
-					syntax_error(f->curr_token, "Empty field declaration");
+			u32 flags = parse_field_prefixes(f);
+			auto names = parse_ident_list(f);
+			if (names.count == 0) {
+				break;
+			}
+			u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, flags);
+			if (names.count == 1 && f->curr_token.kind == Token_OpenBrace) {
+				if (set_flags != 0) {
+					error(names[0], "Variants cannot have field prefixes");
+					set_flags = 0;
 				}
-				u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
-				total_decl_name_count += names.count;
-				expect_token_after(f, Token_Colon, "field list");
-				AstNode *type = parse_var_type(f, false, false);
-				array_add(&decls, ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment));
+				AstNode *name  = names[0];
+				Token    open  = expect_token(f, Token_OpenBrace);
+				isize decl_count = 0;
+				AstNode *list = parse_record_field_list(f, &decl_count);
+				Token    close = expect_token(f, Token_CloseBrace);
+
+				array_add(&variants, ast_union_field(f, name, list));
+				expect_semicolon(f, nullptr);
 			} else {
-				Array<AstNode *> names = parse_ident_list(f);
-				if (names.count == 0) {
-					break;
-				}
-				if (names.count > 1 || f->curr_token.kind == Token_Colon) {
-					u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
-					total_decl_name_count += names.count;
-					expect_token_after(f, Token_Colon, "field list");
-					AstNode *type = parse_var_type(f, false, false);
-					array_add(&decls, ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment));
+				AstNode *decl = parse_value_decl(f, names, docs);
+				if (decl->kind != AstNode_ValueDecl) {
+					error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind]));
 				} else {
-					AstNode *name  = names[0];
-					Token    open  = expect_token(f, Token_OpenBrace);
-					isize decl_count = 0;
-					AstNode *list = parse_struct_field_list(f, &decl_count);
-					// AstNode *list  = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
-					Token    close = expect_token(f, Token_CloseBrace);
-
-					array_add(&variants, ast_union_field(f, name, list));
+					ast_node(vd, ValueDecl, decl);
+					if (vd->is_mutable) {
+						if (set_flags&FieldFlag_using) {
+							vd->flags |= VarDeclFlag_using;
+						}
+						if (vd->flags&VarDeclFlag_thread_local) {
+							vd->flags &= ~VarDeclFlag_thread_local;
+							error(decl, "Field values cannot be #thread_local");
+						}
+						array_add(&decls, decl);
+						total_decl_name_count += vd->names.count;
+					} else {
+						error(decl, "Only variable declarations are allowed at the moment");
+					}
 				}
 			}
-			if (!parse_expect_struct_separator(f, nullptr)) {
-				break;
-			}
 		}
 
 		Token close = expect_token(f, Token_CloseBrace);
 
-
 		return ast_union_type(f, token, decls, total_decl_name_count, variants);
 	} break;
 
@@ -3819,7 +3761,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
 		Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
 
 		isize    decl_count = 0;
-		AstNode *fields     = parse_struct_field_list(f, &decl_count);
+		AstNode *fields     = parse_record_field_list(f, &decl_count);
 		Token    close      = expect_token(f, Token_CloseBrace);
 
 		Array<AstNode *> decls = {};
@@ -4391,11 +4333,7 @@ AstNode *parse_stmt(AstFile *f) {
 				syntax_error(token, "`using` may only be applied to variable declarations");
 				return decl;
 			}
-			if (f->curr_proc == nullptr) {
-				syntax_error(token, "`using` is not allowed at the file scope");
-			} else {
-				decl->ValueDecl.flags |= VarDeclFlag_using;
-			}
+			decl->ValueDecl.flags |= VarDeclFlag_using;
 			return decl;
 		}