Browse Source

Improve flag handling to check for invalid uses

gingerBill 4 years ago
parent
commit
00192bb349
3 changed files with 149 additions and 56 deletions
  1. 32 0
      src/build_settings.cpp
  2. 40 0
      src/docs.cpp
  3. 77 56
      src/main.cpp

+ 32 - 0
src/build_settings.cpp

@@ -104,6 +104,35 @@ enum BuildModeKind {
 	BuildMode_Assembly,
 	BuildMode_Assembly,
 };
 };
 
 
+enum CommandKind : u32 {
+	Command_run     = 1<<0,
+	Command_build   = 1<<1,
+	Command_check   = 1<<3,
+	Command_query   = 1<<4,
+	Command_doc     = 1<<5,
+	Command_version = 1<<6,
+
+	Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc,
+	Command__does_build = Command_run|Command_build,
+	Command_all = ~(u32)0,
+};
+
+char const *odin_command_strings[32] = {
+	"run",
+	"build",
+	"check",
+	"query",
+	"doc",
+	"version",
+};
+
+
+
+enum CmdDocFlag : u32 {
+	CmdDocFlag_All = 1<<0,
+};
+
+
 
 
 // This stores the information for the specify architecture of this build
 // This stores the information for the specify architecture of this build
 struct BuildContext {
 struct BuildContext {
@@ -124,6 +153,7 @@ struct BuildContext {
 	i64    word_size; // Size of a pointer, must be >= 4
 	i64    word_size; // Size of a pointer, must be >= 4
 	i64    max_align; // max alignment, must be >= 1 (and typically >= word_size)
 	i64    max_align; // max alignment, must be >= 1 (and typically >= word_size)
 
 
+	CommandKind command_kind;
 	String command;
 	String command;
 
 
 	TargetMetrics metrics;
 	TargetMetrics metrics;
@@ -167,6 +197,8 @@ struct BuildContext {
 	bool   ignore_microsoft_magic;
 	bool   ignore_microsoft_magic;
 	bool   linker_map_file;
 	bool   linker_map_file;
 
 
+	u32 cmd_doc_flags;
+
 	QueryDataSetSettings query_data_set_settings;
 	QueryDataSetSettings query_data_set_settings;
 
 
 	gbAffinity affinity;
 	gbAffinity affinity;

+ 40 - 0
src/docs.cpp

@@ -50,6 +50,14 @@ GB_COMPARE_PROC(cmp_entities_for_printing) {
 	return res;
 	return res;
 }
 }
 
 
+GB_COMPARE_PROC(cmp_ast_package_by_name) {
+	GB_ASSERT(a != nullptr);
+	GB_ASSERT(b != nullptr);
+	AstPackage *x = *cast(AstPackage **)a;
+	AstPackage *y = *cast(AstPackage **)b;
+	return string_compare(x->name, y->name);
+}
+
 
 
 gbString expr_to_string(Ast *expression);
 gbString expr_to_string(Ast *expression);
 gbString type_to_string(Type *type);
 gbString type_to_string(Type *type);
@@ -84,7 +92,39 @@ String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
 	return make_string(text, len);
 	return make_string(text, len);
 }
 }
 
 
+
+void print_doc_line(i32 indent, char const *fmt, ...) {
+	while (indent --> 0) {
+		gb_printf("\t");
+	}
+	va_list va;
+	va_start(va, fmt);
+	gb_printf_va(fmt, va);
+	va_end(va);
+	gb_printf("\n");
+}
+
+void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
+	print_doc_line(0, "%.*s", LIT(pkg->name));
+}
+
 void generate_documentation(Checker *c) {
 void generate_documentation(Checker *c) {
 	CheckerInfo *info = &c->info;
 	CheckerInfo *info = &c->info;
 
 
+	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
+		auto pkgs = array_make<AstPackage *>(permanent_allocator(), info->packages.entries.count);
+		for_array(i, info->packages.entries) {
+			array_add(&pkgs, info->packages.entries[i].value);
+		}
+
+		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
+
+		for_array(i, pkgs) {
+			print_doc_package(info, pkgs[i]);
+		}
+	} else {
+		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
+		AstPackage *pkg = info->init_scope->pkg;
+		print_doc_package(info, pkg);
+	}
 }
 }

+ 77 - 56
src/main.cpp

@@ -623,10 +623,13 @@ struct BuildFlag {
 	BuildFlagKind      kind;
 	BuildFlagKind      kind;
 	String             name;
 	String             name;
 	BuildFlagParamKind param_kind;
 	BuildFlagParamKind param_kind;
+	u32                command_support;
+	bool               allow_mulitple;
 };
 };
 
 
-void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind) {
-	BuildFlag flag = {kind, name, param_kind};
+
+void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
+	BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
 	array_add(build_flags, flag);
 	array_add(build_flags, flag);
 }
 }
 
 
@@ -667,46 +670,46 @@ ExactValue build_param_to_exact_value(String name, String param) {
 
 
 bool parse_build_flags(Array<String> args) {
 bool parse_build_flags(Array<String> args) {
 	auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
 	auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
-	add_flag(&build_flags, BuildFlag_Help,              str_lit("help"),                BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_OutFile,           str_lit("out"),                 BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"),                 BuildFlagParam_Integer);
-	add_flag(&build_flags, BuildFlag_ShowTimings,       str_lit("show-timings"),        BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ShowUnused,        str_lit("show-unused"),         BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ShowUnusedWithLocation, str_lit("show-unused-with-location"), BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ShowMoreTimings,   str_lit("show-more-timings"),   BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ShowSystemCalls,   str_lit("show-system-calls"),   BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ThreadCount,       str_lit("thread-count"),        BuildFlagParam_Integer);
-	add_flag(&build_flags, BuildFlag_KeepTempFiles,     str_lit("keep-temp-files"),     BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_Collection,        str_lit("collection"),          BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_Define,            str_lit("define"),              BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_BuildMode,         str_lit("build-mode"),          BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_Target,            str_lit("target"),              BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_Debug,             str_lit("debug"),               BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_DisableAssert,     str_lit("disable-assert"),      BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_NoBoundsCheck,     str_lit("no-bounds-check"),     BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_NoCRT,             str_lit("no-crt"),              BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_NoEntryPoint,      str_lit("no-entry-point"),      BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_UseLLD,            str_lit("lld"),                 BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_Vet,               str_lit("vet"),                 BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_UseLLVMApi,        str_lit("llvm-api"),            BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ExtraLinkerFlags,  str_lit("extra-linker-flags"),              BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_Microarch,         str_lit("microarch"),                       BuildFlagParam_String);
-
-	add_flag(&build_flags, BuildFlag_DisallowDo,            str_lit("disallow-do"),              BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None);
-
-	add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None);
+	add_flag(&build_flags, BuildFlag_Help,              str_lit("help"),                BuildFlagParam_None, Command_all);
+	add_flag(&build_flags, BuildFlag_OutFile,           str_lit("out"),                 BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_OptimizationLevel, str_lit("opt"),                 BuildFlagParam_Integer, Command__does_build);
+	add_flag(&build_flags, BuildFlag_ShowTimings,       str_lit("show-timings"),        BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_ShowMoreTimings,   str_lit("show-more-timings"),   BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_ShowUnused,        str_lit("show-unused"),         BuildFlagParam_None, Command_check);
+	add_flag(&build_flags, BuildFlag_ShowUnusedWithLocation, str_lit("show-unused-with-location"), BuildFlagParam_None, Command_check);
+	add_flag(&build_flags, BuildFlag_ShowSystemCalls,   str_lit("show-system-calls"),   BuildFlagParam_None, Command_all);
+	add_flag(&build_flags, BuildFlag_ThreadCount,       str_lit("thread-count"),        BuildFlagParam_Integer, Command_all);
+	add_flag(&build_flags, BuildFlag_KeepTempFiles,     str_lit("keep-temp-files"),     BuildFlagParam_None, Command__does_build);
+	add_flag(&build_flags, BuildFlag_Collection,        str_lit("collection"),          BuildFlagParam_String, Command__does_check);
+	add_flag(&build_flags, BuildFlag_Define,            str_lit("define"),              BuildFlagParam_String, Command__does_check, true);
+	add_flag(&build_flags, BuildFlag_BuildMode,         str_lit("build-mode"),          BuildFlagParam_String, Command__does_build); // Commands_build is not used to allow for a better error message
+	add_flag(&build_flags, BuildFlag_Target,            str_lit("target"),              BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_Debug,             str_lit("debug"),               BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_DisableAssert,     str_lit("disable-assert"),      BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_NoBoundsCheck,     str_lit("no-bounds-check"),     BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_NoCRT,             str_lit("no-crt"),              BuildFlagParam_None, Command__does_build);
+	add_flag(&build_flags, BuildFlag_NoEntryPoint,      str_lit("no-entry-point"),      BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_UseLLD,            str_lit("lld"),                 BuildFlagParam_None, Command__does_build);
+	add_flag(&build_flags, BuildFlag_Vet,               str_lit("vet"),                 BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_UseLLVMApi,        str_lit("llvm-api"),            BuildFlagParam_None, Command__does_build);
+	add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_ExtraLinkerFlags,  str_lit("extra-linker-flags"),              BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_Microarch,         str_lit("microarch"),                       BuildFlagParam_String, Command__does_build);
+
+	add_flag(&build_flags, BuildFlag_DisallowDo,            str_lit("disallow-do"),              BuildFlagParam_None, Command__does_check);
+	add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check);
+
+	add_flag(&build_flags, BuildFlag_Compact,           str_lit("compact"),            BuildFlagParam_None, Command_query);
+	add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
+	add_flag(&build_flags, BuildFlag_GoToDefinitions,   str_lit("go-to-definitions"),  BuildFlagParam_None, Command_query);
 
 
 
 
 #if defined(GB_SYSTEM_WINDOWS)
 #if defined(GB_SYSTEM_WINDOWS)
-	add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"),  BuildFlagParam_None);
-	add_flag(&build_flags, BuildFlag_ResourceFile,   str_lit("resource"),  BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"),  BuildFlagParam_String);
-	add_flag(&build_flags, BuildFlag_Subsystem,      str_lit("subsystem"), BuildFlagParam_String);
+	add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"),  BuildFlagParam_None, Command__does_build);
+	add_flag(&build_flags, BuildFlag_ResourceFile,   str_lit("resource"),          BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_WindowsPdbName, str_lit("pdb-name"),          BuildFlagParam_String, Command__does_build);
+	add_flag(&build_flags, BuildFlag_Subsystem,      str_lit("subsystem"),         BuildFlagParam_String, Command__does_build);
 #endif
 #endif
 
 
 	GB_ASSERT(args.count >= 3);
 	GB_ASSERT(args.count >= 3);
@@ -736,11 +739,19 @@ bool parse_build_flags(Array<String> args) {
 		String param = {};
 		String param = {};
 		if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
 		if (end < flag.len-1) param = substring(flag, 2+end, flag.len);
 
 
+		bool is_supported = true;
 		bool found = false;
 		bool found = false;
+		BuildFlag found_bf = {};
 		for_array(build_flag_index, build_flags) {
 		for_array(build_flag_index, build_flags) {
 			BuildFlag bf = build_flags[build_flag_index];
 			BuildFlag bf = build_flags[build_flag_index];
 			if (bf.name == name) {
 			if (bf.name == name) {
 				found = true;
 				found = true;
+				found_bf = bf;
+				if ((bf.command_support & build_context.command_kind) == 0) {
+					is_supported = false;
+					break;
+				}
+
 				if (set_flags[bf.kind]) {
 				if (set_flags[bf.kind]) {
 					gb_printf_err("Previous flag set: '%.*s'\n", LIT(name));
 					gb_printf_err("Previous flag set: '%.*s'\n", LIT(name));
 					bad_flags = true;
 					bad_flags = true;
@@ -867,19 +878,11 @@ bool parse_build_flags(Array<String> args) {
 						case BuildFlag_ShowUnused:
 						case BuildFlag_ShowUnused:
 							GB_ASSERT(value.kind == ExactValue_Invalid);
 							GB_ASSERT(value.kind == ExactValue_Invalid);
 							build_context.show_unused = true;
 							build_context.show_unused = true;
-							if (build_context.command != "check") {
-								gb_printf_err("%.*s is only allowed with 'odin check'\n", LIT(name));
-								bad_flags = true;
-							}
 							break;
 							break;
 						case BuildFlag_ShowUnusedWithLocation:
 						case BuildFlag_ShowUnusedWithLocation:
 							GB_ASSERT(value.kind == ExactValue_Invalid);
 							GB_ASSERT(value.kind == ExactValue_Invalid);
 							build_context.show_unused = true;
 							build_context.show_unused = true;
 							build_context.show_unused_with_location = true;
 							build_context.show_unused_with_location = true;
-							if (build_context.command != "check") {
-								gb_printf_err("%.*s is only allowed with 'odin check'\n", LIT(name));
-								bad_flags = true;
-							}
 							break;
 							break;
 						case BuildFlag_ShowMoreTimings:
 						case BuildFlag_ShowMoreTimings:
 							GB_ASSERT(value.kind == ExactValue_Invalid);
 							GB_ASSERT(value.kind == ExactValue_Invalid);
@@ -1252,20 +1255,30 @@ bool parse_build_flags(Array<String> args) {
 						}
 						}
 					}
 					}
 
 
-
-					switch (bf.kind) {
-					case BuildFlag_Define:
-						// Allow for multiple
-						break;
-					default:
+					if (!bf.allow_mulitple) {
 						set_flags[bf.kind] = ok;
 						set_flags[bf.kind] = ok;
-						break;
 					}
 					}
 				}
 				}
 				break;
 				break;
 			}
 			}
 		}
 		}
-		if (!found) {
+		if (found && !is_supported) {
+			gb_printf_err("Unknown flag for 'odin %.*s': '%.*s'\n", LIT(build_context.command), LIT(name));
+			gb_printf_err("'%.*s' is supported with the following commands:\n", LIT(name));
+			gb_printf_err("\t");
+			i32 count = 0;
+			for (u32 i = 0; i < 32; i++) {
+				if (found_bf.command_support & (1<<i)) {
+					if (count > 0) {
+						gb_printf_err(", ");
+					}
+					gb_printf_err("%s", odin_command_strings[i]);
+					count += 1;
+				}
+			}
+			gb_printf_err("\n");
+			bad_flags = true;
+		} else if (!found) {
 			gb_printf_err("Unknown flag: '%.*s'\n", LIT(name));
 			gb_printf_err("Unknown flag: '%.*s'\n", LIT(name));
 			bad_flags = true;
 			bad_flags = true;
 		}
 		}
@@ -1795,6 +1808,7 @@ int main(int arg_count, char const **arg_ptr) {
 			usage(args[0]);
 			usage(args[0]);
 			return 1;
 			return 1;
 		}
 		}
+		build_context.command_kind = Command_run;
 
 
 		Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
 		Array<String> run_args = array_make<String>(heap_allocator(), 0, arg_count);
 		defer (array_free(&run_args));
 		defer (array_free(&run_args));
@@ -1814,17 +1828,20 @@ int main(int arg_count, char const **arg_ptr) {
 		run_args_string = string_join_and_quote(heap_allocator(), run_args);
 		run_args_string = string_join_and_quote(heap_allocator(), run_args);
 		init_filename = args[2];
 		init_filename = args[2];
 		run_output = true;
 		run_output = true;
+
 	} else if (command == "build") {
 	} else if (command == "build") {
 		if (args.count < 3) {
 		if (args.count < 3) {
 			usage(args[0]);
 			usage(args[0]);
 			return 1;
 			return 1;
 		}
 		}
+		build_context.command_kind = Command_build;
 		init_filename = args[2];
 		init_filename = args[2];
 	} else if (command == "check") {
 	} else if (command == "check") {
 		if (args.count < 3) {
 		if (args.count < 3) {
 			usage(args[0]);
 			usage(args[0]);
 			return 1;
 			return 1;
 		}
 		}
+		build_context.command_kind = Command_check;
 		build_context.no_output_files = true;
 		build_context.no_output_files = true;
 		init_filename = args[2];
 		init_filename = args[2];
 	} else if (command == "query") {
 	} else if (command == "query") {
@@ -1832,6 +1849,7 @@ int main(int arg_count, char const **arg_ptr) {
 			usage(args[0]);
 			usage(args[0]);
 			return 1;
 			return 1;
 		}
 		}
+		build_context.command_kind = Command_query;
 		build_context.no_output_files = true;
 		build_context.no_output_files = true;
 		build_context.query_data_set_settings.ok = true;
 		build_context.query_data_set_settings.ok = true;
 		init_filename = args[2];
 		init_filename = args[2];
@@ -1841,14 +1859,17 @@ int main(int arg_count, char const **arg_ptr) {
 			return 1;
 			return 1;
 		}
 		}
 
 
+		build_context.command_kind = Command_doc;
 		init_filename = args[2];
 		init_filename = args[2];
+		build_context.no_output_files = true;
 		build_context.generate_docs = true;
 		build_context.generate_docs = true;
 		build_context.no_entry_point = true; // ignore entry point
 		build_context.no_entry_point = true; // ignore entry point
-		#if 1
+		#if 0
 		print_usage_line(0, "Documentation generation is not yet supported");
 		print_usage_line(0, "Documentation generation is not yet supported");
 		return 1;
 		return 1;
 		#endif
 		#endif
 	} else if (command == "version") {
 	} else if (command == "version") {
+		build_context.command_kind = Command_version;
 		gb_printf("%.*s version %.*s", LIT(args[0]), LIT(ODIN_VERSION));
 		gb_printf("%.*s version %.*s", LIT(args[0]), LIT(ODIN_VERSION));
 
 
 		#ifdef NIGHTLY
 		#ifdef NIGHTLY