Browse Source

Basic `odin doc` support

gingerBill 4 years ago
parent
commit
d90fc18bef
8 changed files with 363 additions and 99 deletions
  1. 2 0
      src/build_settings.cpp
  2. 126 82
      src/check_expr.cpp
  3. 3 1
      src/checker.cpp
  4. 1 0
      src/checker.hpp
  5. 204 8
      src/docs.cpp
  6. 3 3
      src/exact_value.cpp
  7. 23 0
      src/main.cpp
  8. 1 5
      src/parser.cpp

+ 2 - 0
src/build_settings.cpp

@@ -130,6 +130,7 @@ char const *odin_command_strings[32] = {
 
 
 enum CmdDocFlag : u32 {
 enum CmdDocFlag : u32 {
 	CmdDocFlag_All = 1<<0,
 	CmdDocFlag_All = 1<<0,
+	CmdDocFlag_AllPackages = 1<<1,
 };
 };
 
 
 
 
@@ -198,6 +199,7 @@ struct BuildContext {
 	bool   linker_map_file;
 	bool   linker_map_file;
 
 
 	u32 cmd_doc_flags;
 	u32 cmd_doc_flags;
+	Array<String> doc_packages;
 
 
 	QueryDataSetSettings query_data_set_settings;
 	QueryDataSetSettings query_data_set_settings;
 
 

+ 126 - 82
src/check_expr.cpp

@@ -10208,14 +10208,14 @@ void check_expr_or_type(CheckerContext *c, Operand *o, Ast *e, Type *type_hint)
 }
 }
 
 
 
 
-gbString write_expr_to_string(gbString str, Ast *node);
+gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
 
 
 gbString write_struct_fields_to_string(gbString str, Slice<Ast *> const &params) {
 gbString write_struct_fields_to_string(gbString str, Slice<Ast *> const &params) {
 	for_array(i, params) {
 	for_array(i, params) {
 		if (i > 0) {
 		if (i > 0) {
 			str = gb_string_appendc(str, ", ");
 			str = gb_string_appendc(str, ", ");
 		}
 		}
-		str = write_expr_to_string(str, params[i]);
+		str = write_expr_to_string(str, params[i], false);
 	}
 	}
 	return str;
 	return str;
 }
 }
@@ -10229,11 +10229,23 @@ gbString string_append_string(gbString str, String string) {
 
 
 
 
 gbString string_append_token(gbString str, Token token) {
 gbString string_append_token(gbString str, Token token) {
-	return string_append_string(str, token.string);
+	if (token.kind == Token_String) {
+		str = gb_string_append_rune(str, '"');
+	} else if (token.kind == Token_Rune) {
+		str = gb_string_append_rune(str, '\'');
+	}
+	str = string_append_string(str, token.string);
+	if (token.kind == Token_String) {
+		str = gb_string_append_rune(str, '"');
+	} else if (token.kind == Token_Rune) {
+		str = gb_string_append_rune(str, '\'');
+	}
+
+	return str;
 }
 }
 
 
 
 
-gbString write_expr_to_string(gbString str, Ast *node) {
+gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
 	if (node == nullptr)
 	if (node == nullptr)
 		return str;
 		return str;
 
 
@@ -10271,21 +10283,30 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		str = gb_string_appendc(str, "proc{");
 		str = gb_string_appendc(str, "proc{");
 		for_array(i, pg->args) {
 		for_array(i, pg->args) {
 			if (i > 0) str = gb_string_appendc(str, ", ");
 			if (i > 0) str = gb_string_appendc(str, ", ");
-			str = write_expr_to_string(str, pg->args[i]);
+			str = write_expr_to_string(str, pg->args[i], shorthand);
 		}
 		}
 		str = gb_string_append_rune(str, '}');
 		str = gb_string_append_rune(str, '}');
 	case_end;
 	case_end;
 
 
 	case_ast_node(pl, ProcLit, node);
 	case_ast_node(pl, ProcLit, node);
-		str = write_expr_to_string(str, pl->type);
+		str = write_expr_to_string(str, pl->type, shorthand);
+		if (pl->body) {
+			str = gb_string_appendc(str, " {...}");
+		} else {
+			str = gb_string_appendc(str, " ---");
+		}
 	case_end;
 	case_end;
 
 
 	case_ast_node(cl, CompoundLit, node);
 	case_ast_node(cl, CompoundLit, node);
-		str = write_expr_to_string(str, cl->type);
+		str = write_expr_to_string(str, cl->type, shorthand);
 		str = gb_string_append_rune(str, '{');
 		str = gb_string_append_rune(str, '{');
-		for_array(i, cl->elems) {
-			if (i > 0) str = gb_string_appendc(str, ", ");
-			str = write_expr_to_string(str, cl->elems[i]);
+		if (shorthand) {
+			str = gb_string_appendc(str, "...");
+		} else {
+			for_array(i, cl->elems) {
+				if (i > 0) str = gb_string_appendc(str, ", ");
+				str = write_expr_to_string(str, cl->elems[i], shorthand);
+			}
 		}
 		}
 		str = gb_string_append_rune(str, '}');
 		str = gb_string_append_rune(str, '}');
 	case_end;
 	case_end;
@@ -10294,71 +10315,71 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 	case_ast_node(te, TagExpr, node);
 	case_ast_node(te, TagExpr, node);
 		str = gb_string_append_rune(str, '#');
 		str = gb_string_append_rune(str, '#');
 		str = string_append_token(str, te->name);
 		str = string_append_token(str, te->name);
-		str = write_expr_to_string(str, te->expr);
+		str = write_expr_to_string(str, te->expr, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ue, UnaryExpr, node);
 	case_ast_node(ue, UnaryExpr, node);
 		str = string_append_token(str, ue->op);
 		str = string_append_token(str, ue->op);
-		str = write_expr_to_string(str, ue->expr);
+		str = write_expr_to_string(str, ue->expr, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(de, DerefExpr, node);
 	case_ast_node(de, DerefExpr, node);
-		str = write_expr_to_string(str, de->expr);
+		str = write_expr_to_string(str, de->expr, shorthand);
 		str = gb_string_append_rune(str, '^');
 		str = gb_string_append_rune(str, '^');
 	case_end;
 	case_end;
 
 
 	case_ast_node(be, BinaryExpr, node);
 	case_ast_node(be, BinaryExpr, node);
-		str = write_expr_to_string(str, be->left);
+		str = write_expr_to_string(str, be->left, shorthand);
 		str = gb_string_append_rune(str, ' ');
 		str = gb_string_append_rune(str, ' ');
 		str = string_append_token(str, be->op);
 		str = string_append_token(str, be->op);
 		str = gb_string_append_rune(str, ' ');
 		str = gb_string_append_rune(str, ' ');
-		str = write_expr_to_string(str, be->right);
+		str = write_expr_to_string(str, be->right, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(te, TernaryExpr, node);
 	case_ast_node(te, TernaryExpr, node);
-		str = write_expr_to_string(str, te->cond);
+		str = write_expr_to_string(str, te->cond, shorthand);
 		str = gb_string_appendc(str, " ? ");
 		str = gb_string_appendc(str, " ? ");
-		str = write_expr_to_string(str, te->x);
+		str = write_expr_to_string(str, te->x, shorthand);
 		str = gb_string_appendc(str, " : ");
 		str = gb_string_appendc(str, " : ");
-		str = write_expr_to_string(str, te->y);
+		str = write_expr_to_string(str, te->y, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(te, TernaryIfExpr, node);
 	case_ast_node(te, TernaryIfExpr, node);
-		str = write_expr_to_string(str, te->x);
+		str = write_expr_to_string(str, te->x, shorthand);
 		str = gb_string_appendc(str, " if ");
 		str = gb_string_appendc(str, " if ");
-		str = write_expr_to_string(str, te->cond);
+		str = write_expr_to_string(str, te->cond, shorthand);
 		str = gb_string_appendc(str, " else ");
 		str = gb_string_appendc(str, " else ");
-		str = write_expr_to_string(str, te->y);
+		str = write_expr_to_string(str, te->y, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(te, TernaryWhenExpr, node);
 	case_ast_node(te, TernaryWhenExpr, node);
-		str = write_expr_to_string(str, te->x);
+		str = write_expr_to_string(str, te->x, shorthand);
 		str = gb_string_appendc(str, " when ");
 		str = gb_string_appendc(str, " when ");
-		str = write_expr_to_string(str, te->cond);
+		str = write_expr_to_string(str, te->cond, shorthand);
 		str = gb_string_appendc(str, " else ");
 		str = gb_string_appendc(str, " else ");
-		str = write_expr_to_string(str, te->y);
+		str = write_expr_to_string(str, te->y, shorthand);
 	case_end;
 	case_end;
 
 
 
 
 	case_ast_node(pe, ParenExpr, node);
 	case_ast_node(pe, ParenExpr, node);
 		str = gb_string_append_rune(str, '(');
 		str = gb_string_append_rune(str, '(');
-		str = write_expr_to_string(str, pe->expr);
+		str = write_expr_to_string(str, pe->expr, shorthand);
 		str = gb_string_append_rune(str, ')');
 		str = gb_string_append_rune(str, ')');
 	case_end;
 	case_end;
 
 
 	case_ast_node(se, SelectorExpr, node);
 	case_ast_node(se, SelectorExpr, node);
-		str = write_expr_to_string(str, se->expr);
+		str = write_expr_to_string(str, se->expr, shorthand);
 		str = string_append_token(str, se->token);
 		str = string_append_token(str, se->token);
-		str = write_expr_to_string(str, se->selector);
+		str = write_expr_to_string(str, se->selector, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(se, ImplicitSelectorExpr, node);
 	case_ast_node(se, ImplicitSelectorExpr, node);
 		str = gb_string_append_rune(str, '.');
 		str = gb_string_append_rune(str, '.');
-		str = write_expr_to_string(str, se->selector);
+		str = write_expr_to_string(str, se->selector, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(se, SelectorCallExpr, node);
 	case_ast_node(se, SelectorCallExpr, node);
-		str = write_expr_to_string(str, se->expr);
+		str = write_expr_to_string(str, se->expr, shorthand);
 		str = gb_string_appendc(str, "(");
 		str = gb_string_appendc(str, "(");
 		ast_node(ce, CallExpr, se->call);
 		ast_node(ce, CallExpr, se->call);
 		isize start = se->modified_call ? 1 : 0;
 		isize start = se->modified_call ? 1 : 0;
@@ -10367,86 +10388,86 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 			if (i > start) {
 			if (i > start) {
 				str = gb_string_appendc(str, ", ");
 				str = gb_string_appendc(str, ", ");
 			}
 			}
-			str = write_expr_to_string(str, arg);
+			str = write_expr_to_string(str, arg, shorthand);
 		}
 		}
 		str = gb_string_appendc(str, ")");
 		str = gb_string_appendc(str, ")");
 	case_end;
 	case_end;
 
 
 	case_ast_node(ta, TypeAssertion, node);
 	case_ast_node(ta, TypeAssertion, node);
-		str = write_expr_to_string(str, ta->expr);
+		str = write_expr_to_string(str, ta->expr, shorthand);
 		str = gb_string_appendc(str, ".(");
 		str = gb_string_appendc(str, ".(");
-		str = write_expr_to_string(str, ta->type);
+		str = write_expr_to_string(str, ta->type, shorthand);
 		str = gb_string_append_rune(str, ')');
 		str = gb_string_append_rune(str, ')');
 	case_end;
 	case_end;
 
 
 	case_ast_node(tc, TypeCast, node);
 	case_ast_node(tc, TypeCast, node);
 		str = string_append_token(str, tc->token);
 		str = string_append_token(str, tc->token);
 		str = gb_string_append_rune(str, '(');
 		str = gb_string_append_rune(str, '(');
-		str = write_expr_to_string(str, tc->type);
+		str = write_expr_to_string(str, tc->type, shorthand);
 		str = gb_string_append_rune(str, ')');
 		str = gb_string_append_rune(str, ')');
-		str = write_expr_to_string(str, tc->expr);
+		str = write_expr_to_string(str, tc->expr, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ac, AutoCast, node);
 	case_ast_node(ac, AutoCast, node);
 		str = string_append_token(str, ac->token);
 		str = string_append_token(str, ac->token);
 		str = gb_string_append_rune(str, ' ');
 		str = gb_string_append_rune(str, ' ');
-		str = write_expr_to_string(str, ac->expr);
+		str = write_expr_to_string(str, ac->expr, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ie, IndexExpr, node);
 	case_ast_node(ie, IndexExpr, node);
-		str = write_expr_to_string(str, ie->expr);
+		str = write_expr_to_string(str, ie->expr, shorthand);
 		str = gb_string_append_rune(str, '[');
 		str = gb_string_append_rune(str, '[');
-		str = write_expr_to_string(str, ie->index);
+		str = write_expr_to_string(str, ie->index, shorthand);
 		str = gb_string_append_rune(str, ']');
 		str = gb_string_append_rune(str, ']');
 	case_end;
 	case_end;
 
 
 	case_ast_node(se, SliceExpr, node);
 	case_ast_node(se, SliceExpr, node);
-		str = write_expr_to_string(str, se->expr);
+		str = write_expr_to_string(str, se->expr, shorthand);
 		str = gb_string_append_rune(str, '[');
 		str = gb_string_append_rune(str, '[');
-		str = write_expr_to_string(str, se->low);
+		str = write_expr_to_string(str, se->low, shorthand);
 		str = string_append_token(str, se->interval);
 		str = string_append_token(str, se->interval);
-		str = write_expr_to_string(str, se->high);
+		str = write_expr_to_string(str, se->high, shorthand);
 		str = gb_string_append_rune(str, ']');
 		str = gb_string_append_rune(str, ']');
 	case_end;
 	case_end;
 
 
 	case_ast_node(e, Ellipsis, node);
 	case_ast_node(e, Ellipsis, node);
 		str = gb_string_appendc(str, "..");
 		str = gb_string_appendc(str, "..");
-		str = write_expr_to_string(str, e->expr);
+		str = write_expr_to_string(str, e->expr, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(fv, FieldValue, node);
 	case_ast_node(fv, FieldValue, node);
-		str = write_expr_to_string(str, fv->field);
+		str = write_expr_to_string(str, fv->field, shorthand);
 		str = gb_string_appendc(str, " = ");
 		str = gb_string_appendc(str, " = ");
-		str = write_expr_to_string(str, fv->value);
+		str = write_expr_to_string(str, fv->value, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ht, HelperType, node);
 	case_ast_node(ht, HelperType, node);
 		str = gb_string_appendc(str, "#type ");
 		str = gb_string_appendc(str, "#type ");
-		str = write_expr_to_string(str, ht->type);
+		str = write_expr_to_string(str, ht->type, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ht, DistinctType, node);
 	case_ast_node(ht, DistinctType, node);
 		str = gb_string_appendc(str, "distinct ");
 		str = gb_string_appendc(str, "distinct ");
-		str = write_expr_to_string(str, ht->type);
+		str = write_expr_to_string(str, ht->type, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(ht, OpaqueType, node);
 	case_ast_node(ht, OpaqueType, node);
 		str = gb_string_appendc(str, "opaque ");
 		str = gb_string_appendc(str, "opaque ");
-		str = write_expr_to_string(str, ht->type);
+		str = write_expr_to_string(str, ht->type, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(pt, PolyType, node);
 	case_ast_node(pt, PolyType, node);
 		str = gb_string_append_rune(str, '$');
 		str = gb_string_append_rune(str, '$');
-		str = write_expr_to_string(str, pt->type);
+		str = write_expr_to_string(str, pt->type, shorthand);
 		if (pt->specialization != nullptr) {
 		if (pt->specialization != nullptr) {
 			str = gb_string_append_rune(str, '/');
 			str = gb_string_append_rune(str, '/');
-			str = write_expr_to_string(str, pt->specialization);
+			str = write_expr_to_string(str, pt->specialization, shorthand);
 		}
 		}
 	case_end;
 	case_end;
 
 
 	case_ast_node(pt, PointerType, node);
 	case_ast_node(pt, PointerType, node);
 		str = gb_string_append_rune(str, '^');
 		str = gb_string_append_rune(str, '^');
-		str = write_expr_to_string(str, pt->type);
+		str = write_expr_to_string(str, pt->type, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(at, ArrayType, node);
 	case_ast_node(at, ArrayType, node);
@@ -10456,40 +10477,44 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		    at->count->UnaryExpr.op.kind == Token_Question) {
 		    at->count->UnaryExpr.op.kind == Token_Question) {
 			str = gb_string_appendc(str, "?");
 			str = gb_string_appendc(str, "?");
 		} else {
 		} else {
-			str = write_expr_to_string(str, at->count);
+			str = write_expr_to_string(str, at->count, shorthand);
 		}
 		}
 		str = gb_string_append_rune(str, ']');
 		str = gb_string_append_rune(str, ']');
-		str = write_expr_to_string(str, at->elem);
+		str = write_expr_to_string(str, at->elem, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(at, DynamicArrayType, node);
 	case_ast_node(at, DynamicArrayType, node);
 		str = gb_string_appendc(str, "[dynamic]");
 		str = gb_string_appendc(str, "[dynamic]");
-		str = write_expr_to_string(str, at->elem);
+		str = write_expr_to_string(str, at->elem, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(bf, BitFieldType, node);
 	case_ast_node(bf, BitFieldType, node);
 		str = gb_string_appendc(str, "bit_field ");
 		str = gb_string_appendc(str, "bit_field ");
 		if (bf->align) {
 		if (bf->align) {
 			str = gb_string_appendc(str, "#align ");
 			str = gb_string_appendc(str, "#align ");
-			str = write_expr_to_string(str, bf->align);
+			str = write_expr_to_string(str, bf->align, shorthand);
 		}
 		}
 		str = gb_string_appendc(str, "{");
 		str = gb_string_appendc(str, "{");
-		str = write_struct_fields_to_string(str, bf->fields);
+		if (shorthand) {
+			str = gb_string_appendc(str, "...");
+		} else {
+			str = write_struct_fields_to_string(str, bf->fields);
+		}
 		str = gb_string_appendc(str, "}");
 		str = gb_string_appendc(str, "}");
 	case_end;
 	case_end;
 
 
 	case_ast_node(bs, BitSetType, node);
 	case_ast_node(bs, BitSetType, node);
 		str = gb_string_appendc(str, "bit_set[");
 		str = gb_string_appendc(str, "bit_set[");
-		str = write_expr_to_string(str, bs->elem);
+		str = write_expr_to_string(str, bs->elem, shorthand);
 		str = gb_string_appendc(str, "]");
 		str = gb_string_appendc(str, "]");
 	case_end;
 	case_end;
 
 
 
 
 	case_ast_node(mt, MapType, node);
 	case_ast_node(mt, MapType, node);
 		str = gb_string_appendc(str, "map[");
 		str = gb_string_appendc(str, "map[");
-		str = write_expr_to_string(str, mt->key);
+		str = write_expr_to_string(str, mt->key, shorthand);
 		str = gb_string_append_rune(str, ']');
 		str = gb_string_append_rune(str, ']');
-		str = write_expr_to_string(str, mt->value);
+		str = write_expr_to_string(str, mt->value, shorthand);
 	case_end;
 	case_end;
 
 
 	case_ast_node(f, Field, node);
 	case_ast_node(f, Field, node);
@@ -10509,7 +10534,7 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		for_array(i, f->names) {
 		for_array(i, f->names) {
 			Ast *name = f->names[i];
 			Ast *name = f->names[i];
 			if (i > 0) str = gb_string_appendc(str, ", ");
 			if (i > 0) str = gb_string_appendc(str, ", ");
-			str = write_expr_to_string(str, name);
+			str = write_expr_to_string(str, name, shorthand);
 		}
 		}
 		if (f->names.count > 0) {
 		if (f->names.count > 0) {
 			if (f->type == nullptr && f->default_value != nullptr) {
 			if (f->type == nullptr && f->default_value != nullptr) {
@@ -10519,14 +10544,14 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		}
 		}
 		if (f->type != nullptr) {
 		if (f->type != nullptr) {
 			str = gb_string_append_rune(str, ' ');
 			str = gb_string_append_rune(str, ' ');
-			str = write_expr_to_string(str, f->type);
+			str = write_expr_to_string(str, f->type, shorthand);
 		}
 		}
 		if (f->default_value != nullptr) {
 		if (f->default_value != nullptr) {
 			if (f->type != nullptr) {
 			if (f->type != nullptr) {
 				str = gb_string_append_rune(str, ' ');
 				str = gb_string_append_rune(str, ' ');
 			}
 			}
 			str = gb_string_appendc(str, "= ");
 			str = gb_string_appendc(str, "= ");
-			str = write_expr_to_string(str, f->default_value);
+			str = write_expr_to_string(str, f->default_value, shorthand);
 		}
 		}
 
 
 	case_end;
 	case_end;
@@ -10552,7 +10577,7 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		for_array(i, f->list) {
 		for_array(i, f->list) {
 			if (i > 0) str = gb_string_appendc(str, ", ");
 			if (i > 0) str = gb_string_appendc(str, ", ");
 			if (has_name) {
 			if (has_name) {
-				str = write_expr_to_string(str, f->list[i]);
+				str = write_expr_to_string(str, f->list[i], shorthand);
 			} else {
 			} else {
 				ast_node(field, Field, f->list[i]);
 				ast_node(field, Field, f->list[i]);
 
 
@@ -10566,7 +10591,7 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 					str = gb_string_appendc(str, "#c_vararg ");
 					str = gb_string_appendc(str, "#c_vararg ");
 				}
 				}
 
 
-				str = write_expr_to_string(str, field->type);
+				str = write_expr_to_string(str, field->type, shorthand);
 			}
 			}
 		}
 		}
 	case_end;
 	case_end;
@@ -10581,7 +10606,7 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 			break;
 			break;
 		}
 		}
 
 
-		str = write_expr_to_string(str, ce->proc);
+		str = write_expr_to_string(str, ce->proc, shorthand);
 		str = gb_string_appendc(str, "(");
 		str = gb_string_appendc(str, "(");
 
 
 		for_array(i, ce->args) {
 		for_array(i, ce->args) {
@@ -10589,7 +10614,7 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 			if (i > 0) {
 			if (i > 0) {
 				str = gb_string_appendc(str, ", ");
 				str = gb_string_appendc(str, ", ");
 			}
 			}
-			str = write_expr_to_string(str, arg);
+			str = write_expr_to_string(str, arg, shorthand);
 		}
 		}
 		str = gb_string_appendc(str, ")");
 		str = gb_string_appendc(str, ")");
 	case_end;
 	case_end;
@@ -10598,17 +10623,17 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		str = gb_string_appendc(str, "typeid");
 		str = gb_string_appendc(str, "typeid");
 		if (tt->specialization) {
 		if (tt->specialization) {
 			str = gb_string_appendc(str, "/");
 			str = gb_string_appendc(str, "/");
-			str = write_expr_to_string(str, tt->specialization);
+			str = write_expr_to_string(str, tt->specialization, shorthand);
 		}
 		}
 	case_end;
 	case_end;
 
 
 	case_ast_node(pt, ProcType, node);
 	case_ast_node(pt, ProcType, node);
 		str = gb_string_appendc(str, "proc(");
 		str = gb_string_appendc(str, "proc(");
-		str = write_expr_to_string(str, pt->params);
+		str = write_expr_to_string(str, pt->params, shorthand);
 		str = gb_string_appendc(str, ")");
 		str = gb_string_appendc(str, ")");
 		if (pt->results != nullptr) {
 		if (pt->results != nullptr) {
 			str = gb_string_appendc(str, " -> ");
 			str = gb_string_appendc(str, " -> ");
-			str = write_expr_to_string(str, pt->results);
+			str = write_expr_to_string(str, pt->results, shorthand);
 		}
 		}
 
 
 	case_end;
 	case_end;
@@ -10618,7 +10643,11 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 		if (st->is_packed)    str = gb_string_appendc(str, "#packed ");
 		if (st->is_packed)    str = gb_string_appendc(str, "#packed ");
 		if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
 		if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union ");
 		str = gb_string_append_rune(str, '{');
 		str = gb_string_append_rune(str, '{');
-		str = write_struct_fields_to_string(str, st->fields);
+		if (shorthand) {
+			str = gb_string_appendc(str, "...");
+		} else {
+			str = write_struct_fields_to_string(str, st->fields);
+		}
 		str = gb_string_append_rune(str, '}');
 		str = gb_string_append_rune(str, '}');
 	case_end;
 	case_end;
 
 
@@ -10626,30 +10655,38 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 	case_ast_node(st, UnionType, node);
 	case_ast_node(st, UnionType, node);
 		str = gb_string_appendc(str, "union ");
 		str = gb_string_appendc(str, "union ");
 		str = gb_string_append_rune(str, '{');
 		str = gb_string_append_rune(str, '{');
-		str = write_struct_fields_to_string(str, st->variants);
+		if (shorthand) {
+			str = gb_string_appendc(str, "...");
+		} else {
+			str = write_struct_fields_to_string(str, st->variants);
+		}
 		str = gb_string_append_rune(str, '}');
 		str = gb_string_append_rune(str, '}');
 	case_end;
 	case_end;
 
 
 	case_ast_node(et, EnumType, node);
 	case_ast_node(et, EnumType, node);
 		str = gb_string_appendc(str, "enum ");
 		str = gb_string_appendc(str, "enum ");
 		if (et->base_type != nullptr) {
 		if (et->base_type != nullptr) {
-			str = write_expr_to_string(str, et->base_type);
+			str = write_expr_to_string(str, et->base_type, shorthand);
 			str = gb_string_append_rune(str, ' ');
 			str = gb_string_append_rune(str, ' ');
 		}
 		}
 		str = gb_string_append_rune(str, '{');
 		str = gb_string_append_rune(str, '{');
-		for_array(i, et->fields) {
-			if (i > 0) {
-				str = gb_string_appendc(str, ", ");
+		if (shorthand) {
+			str = gb_string_appendc(str, "...");
+		} else {
+			for_array(i, et->fields) {
+				if (i > 0) {
+					str = gb_string_appendc(str, ", ");
+				}
+				str = write_expr_to_string(str, et->fields[i], shorthand);
 			}
 			}
-			str = write_expr_to_string(str, et->fields[i]);
 		}
 		}
 		str = gb_string_append_rune(str, '}');
 		str = gb_string_append_rune(str, '}');
 	case_end;
 	case_end;
 
 
 	case_ast_node(rt, RelativeType, node);
 	case_ast_node(rt, RelativeType, node);
-		str = write_expr_to_string(str, rt->tag);
+		str = write_expr_to_string(str, rt->tag, shorthand);
 		str = gb_string_appendc(str, "" );
 		str = gb_string_appendc(str, "" );
-		str = write_expr_to_string(str, rt->type);
+		str = write_expr_to_string(str, rt->type, shorthand);
 	case_end;
 	case_end;
 
 
 
 
@@ -10659,12 +10696,12 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 			if (i > 0) {
 			if (i > 0) {
 				str = gb_string_appendc(str, ", ");
 				str = gb_string_appendc(str, ", ");
 			}
 			}
-			str = write_expr_to_string(str, ia->param_types[i]);
+			str = write_expr_to_string(str, ia->param_types[i], shorthand);
 		}
 		}
 		str = gb_string_appendc(str, ")");
 		str = gb_string_appendc(str, ")");
 		if (ia->return_type != nullptr) {
 		if (ia->return_type != nullptr) {
 			str = gb_string_appendc(str, " -> ");
 			str = gb_string_appendc(str, " -> ");
-			str = write_expr_to_string(str, ia->return_type);
+			str = write_expr_to_string(str, ia->return_type, shorthand);
 		}
 		}
 		if (ia->has_side_effects) {
 		if (ia->has_side_effects) {
 			str = gb_string_appendc(str, " #side_effects");
 			str = gb_string_appendc(str, " #side_effects");
@@ -10677,9 +10714,13 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 			str = gb_string_appendc(str, inline_asm_dialect_strings[ia->dialect]);
 			str = gb_string_appendc(str, inline_asm_dialect_strings[ia->dialect]);
 		}
 		}
 		str = gb_string_appendc(str, " {");
 		str = gb_string_appendc(str, " {");
-		str = write_expr_to_string(str, ia->asm_string);
-		str = gb_string_appendc(str, ", ");
-		str = write_expr_to_string(str, ia->constraints_string);
+		if (shorthand) {
+			str = gb_string_appendc(str, "...");
+		} else {
+			str = write_expr_to_string(str, ia->asm_string, shorthand);
+			str = gb_string_appendc(str, ", ");
+			str = write_expr_to_string(str, ia->constraints_string, shorthand);
+		}
 		str = gb_string_appendc(str, "}");
 		str = gb_string_appendc(str, "}");
 	case_end;
 	case_end;
 	}
 	}
@@ -10688,5 +10729,8 @@ gbString write_expr_to_string(gbString str, Ast *node) {
 }
 }
 
 
 gbString expr_to_string(Ast *expression) {
 gbString expr_to_string(Ast *expression) {
-	return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression);
+	return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression, false);
+}
+gbString expr_to_string_shorthand(Ast *expression) {
+	return write_expr_to_string(gb_string_make(heap_allocator(), ""), expression, true);
 }
 }

+ 3 - 1
src/checker.cpp

@@ -3115,6 +3115,7 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 
 
 			Ast *init_expr = value;
 			Ast *init_expr = value;
 			DeclInfo *d = make_decl_info(c->scope, c->decl);
 			DeclInfo *d = make_decl_info(c->scope, c->decl);
+			d->decl_node = decl;
 			d->entity    = e;
 			d->entity    = e;
 			d->type_expr = vd->type;
 			d->type_expr = vd->type;
 			d->init_expr = init_expr;
 			d->init_expr = init_expr;
@@ -3142,9 +3143,10 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 			Token token = name->Ident.token;
 			Token token = name->Ident.token;
 
 
 			Ast *fl = c->foreign_context.curr_library;
 			Ast *fl = c->foreign_context.curr_library;
-			DeclInfo *d = make_decl_info(c->scope, c->decl);
 			Entity *e = nullptr;
 			Entity *e = nullptr;
+			DeclInfo *d = make_decl_info(c->scope, c->decl);
 
 
+			d->decl_node = decl;
 			d->attributes = vd->attributes;
 			d->attributes = vd->attributes;
 			d->type_expr = vd->type;
 			d->type_expr = vd->type;
 			d->init_expr = init;
 			d->init_expr = init;

+ 1 - 0
src/checker.hpp

@@ -132,6 +132,7 @@ struct DeclInfo {
 
 
 	Entity *entity;
 	Entity *entity;
 
 
+	Ast *         decl_node;
 	Ast *         type_expr;
 	Ast *         type_expr;
 	Ast *         init_expr;
 	Ast *         init_expr;
 	Array<Ast *>  attributes;
 	Array<Ast *>  attributes;

+ 204 - 8
src/docs.cpp

@@ -59,9 +59,6 @@ GB_COMPARE_PROC(cmp_ast_package_by_name) {
 }
 }
 
 
 
 
-gbString expr_to_string(Ast *expression);
-gbString type_to_string(Type *type);
-
 String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
 String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
 	isize len = 0;
 	isize len = 0;
 	for_array(i, g.list) {
 	for_array(i, g.list) {
@@ -103,18 +100,216 @@ void print_doc_line(i32 indent, char const *fmt, ...) {
 	va_end(va);
 	va_end(va);
 	gb_printf("\n");
 	gb_printf("\n");
 }
 }
+void print_doc_line_no_newline(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);
+}
+
+bool print_doc_comment_group_string(i32 indent, CommentGroup const &g) {
+	isize len = 0;
+	for_array(i, g.list) {
+		String comment = g.list[i].string;
+		len += comment.len;
+		len += 1; // for \n
+	}
+	if (len == 0) {
+		return false;
+	}
+
+	isize count = 0;
+	for_array(i, g.list) {
+		String comment = g.list[i].string;
+		if (comment[1] == '/') {
+			comment.text += 2;
+			comment.len  -= 2;
+		} else if (comment[1] == '*') {
+			comment.text += 2;
+			comment.len  -= 4;
+		}
+		comment = string_trim_whitespace(comment);
+		if (string_starts_with(comment, str_lit("@("))) {
+			continue;
+		}
+
+		print_doc_line(indent, "%.*s", LIT(comment));
+		count += 1;
+	}
+	return count > 0;
+}
+
+
+
+
+void print_doc_expr(Ast *expr) {
+	gbString s = nullptr;
+	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
+		s = expr_to_string(expr);
+	} else {
+		s = expr_to_string_shorthand(expr);
+	}
+	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
+	gb_string_free(s);
+}
+
 
 
 void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
 void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
-	print_doc_line(0, "%.*s", LIT(pkg->name));
+	if (pkg == nullptr) {
+		return;
+	}
+
+	print_doc_line(0, "package %.*s", LIT(pkg->name));
+
+	if (pkg->scope != nullptr) {
+		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
+		defer (array_free(&entities));
+		for_array(i, pkg->scope->elements.entries) {
+			Entity *e = pkg->scope->elements.entries[i].value;
+			switch (e->kind) {
+			case Entity_Invalid:
+			case Entity_Builtin:
+			case Entity_Nil:
+			case Entity_Label:
+				continue;
+			case Entity_Constant:
+			case Entity_Variable:
+			case Entity_TypeName:
+			case Entity_Procedure:
+			case Entity_ProcGroup:
+			case Entity_ImportName:
+			case Entity_LibraryName:
+				// Fine
+				break;
+			}
+			array_add(&entities, e);
+		}
+		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);
+
+		AstPackage *curr_pkg = nullptr;
+		EntityKind curr_entity_kind = Entity_Invalid;
+		for_array(i, entities) {
+			Entity *e = entities[i];
+			if (e->pkg != pkg) {
+				continue;
+			}
+			if (!is_entity_exported(e)) {
+				continue;
+			}
+
+			if (curr_entity_kind != e->kind) {
+				curr_entity_kind = e->kind;
+				print_doc_line(0, "");
+				print_doc_line(1, "%s", print_entity_names[e->kind]);
+			}
+
+			Ast *type_expr = nullptr;
+			Ast *init_expr = nullptr;
+			Ast *decl_node = nullptr;
+			if (e->decl_info != nullptr) {
+				type_expr = e->decl_info->type_expr;
+				init_expr = e->decl_info->init_expr;
+				decl_node = e->decl_info->decl_node;
+			}
+			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
+			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
+			if (type_expr != nullptr) {
+				gbString t = expr_to_string(type_expr);
+				gb_printf(": %s ", t);
+				gb_string_free(t);
+			} else {
+				gb_printf(" :");
+			}
+			if (e->kind == Entity_Variable) {
+				if (init_expr != nullptr) {
+					gb_printf("= ");
+					print_doc_expr(init_expr);
+				}
+			} else {
+				gb_printf(": ");
+				print_doc_expr(init_expr);
+			}
+
+			gb_printf(";\n");
+
+
+			if (decl_node && (true || (build_context.cmd_doc_flags & CmdDocFlag_All))) {
+				CommentGroup *docs = nullptr;
+				CommentGroup *comment = nullptr;
+				switch (decl_node->kind) {
+				case_ast_node(vd, ValueDecl, decl_node);
+					docs = vd->docs;
+					comment = vd->comment;
+				case_end;
+
+				case_ast_node(id, ImportDecl, decl_node);
+					docs = id->docs;
+					comment = id->comment;
+				case_end;
+
+				case_ast_node(fl, ForeignImportDecl, decl_node);
+					docs = fl->docs;
+					comment = fl->comment;
+				case_end;
+
+				case_ast_node(fb, ForeignBlockDecl, decl_node);
+					docs = fb->docs;
+				case_end;
+				}
+				if (comment) {
+					// gb_printf(" <comment>");
+				}
+				if (docs) {
+					if (print_doc_comment_group_string(3, *docs)) {
+						gb_printf("\n");
+					}
+				}
+			}
+		}
+		print_doc_line(0, "");
+	}
+
+	if (pkg->fullpath.len != 0) {
+		print_doc_line(0, "");
+		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
+		print_doc_line(1, "files:");
+		for_array(i, pkg->files) {
+			AstFile *f = pkg->files[i];
+			String filename = remove_directory_from_path(f->fullpath);
+			print_doc_line(2, "%.*s", LIT(filename));
+		}
+	}
+
 }
 }
 
 
 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);
+	if (build_context.doc_packages.count != 0) {
+		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
+		bool was_error = false;
+		for_array(j, build_context.doc_packages) {
+			bool found = false;
+			String name = build_context.doc_packages[j];
+			for_array(i, info->packages.entries) {
+				AstPackage *pkg = info->packages.entries[i].value;
+				if (name == pkg->name) {
+					found = true;
+					array_add(&pkgs, pkg);
+					break;
+				}
+			}
+			if (!found) {
+				gb_printf_err("Unknown package %.*s\n", LIT(name));
+				was_error = true;
+			}
+		}
+		if (was_error) {
+			gb_exit(1);
+			return;
 		}
 		}
 
 
 		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
 		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);
@@ -126,5 +321,6 @@ void generate_documentation(Checker *c) {
 		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
 		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
 		AstPackage *pkg = info->init_scope->pkg;
 		AstPackage *pkg = info->init_scope->pkg;
 		print_doc_package(info, pkg);
 		print_doc_package(info, pkg);
+
 	}
 	}
 }
 }

+ 3 - 3
src/exact_value.cpp

@@ -945,7 +945,7 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
 Entity *strip_entity_wrapping(Ast *expr);
 Entity *strip_entity_wrapping(Ast *expr);
 Entity *strip_entity_wrapping(Entity *e);
 Entity *strip_entity_wrapping(Entity *e);
 
 
-gbString write_expr_to_string(gbString str, Ast *node);
+gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
 
 
 gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
 gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
 	switch (v.kind) {
 	switch (v.kind) {
@@ -981,9 +981,9 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
 	case ExactValue_Pointer:
 	case ExactValue_Pointer:
 		return str;
 		return str;
 	case ExactValue_Compound:
 	case ExactValue_Compound:
-		return write_expr_to_string(str, v.value_compound);
+		return write_expr_to_string(str, v.value_compound, false);
 	case ExactValue_Procedure:
 	case ExactValue_Procedure:
-		return write_expr_to_string(str, v.value_procedure);
+		return write_expr_to_string(str, v.value_procedure, false);
 	}
 	}
 	return str;
 	return str;
 };
 };

+ 23 - 0
src/main.cpp

@@ -598,6 +598,8 @@ enum BuildFlagKind {
 	BuildFlag_GlobalDefinitions,
 	BuildFlag_GlobalDefinitions,
 	BuildFlag_GoToDefinitions,
 	BuildFlag_GoToDefinitions,
 
 
+	BuildFlag_Package,
+
 #if defined(GB_SYSTEM_WINDOWS)
 #if defined(GB_SYSTEM_WINDOWS)
 	BuildFlag_IgnoreVsSearch,
 	BuildFlag_IgnoreVsSearch,
 	BuildFlag_ResourceFile,
 	BuildFlag_ResourceFile,
@@ -704,6 +706,8 @@ bool parse_build_flags(Array<String> args) {
 	add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), 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);
 	add_flag(&build_flags, BuildFlag_GoToDefinitions,   str_lit("go-to-definitions"),  BuildFlagParam_None, Command_query);
 
 
+	add_flag(&build_flags, BuildFlag_Package,   str_lit("package"),  BuildFlagParam_String, Command_doc, true);
+
 
 
 #if defined(GB_SYSTEM_WINDOWS)
 #if defined(GB_SYSTEM_WINDOWS)
 	add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"),  BuildFlagParam_None, Command__does_build);
 	add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"),  BuildFlagParam_None, Command__does_build);
@@ -1192,6 +1196,15 @@ bool parse_build_flags(Array<String> args) {
 							}
 							}
 							break;
 							break;
 
 
+						case BuildFlag_Package:
+							GB_ASSERT(value.kind == ExactValue_String);
+							if (value.value_string.len == 0) {
+								gb_printf_err("Invalid use of -package flag\n");
+							} else {
+								array_add(&build_context.doc_packages, value.value_string);
+							}
+							break;
+
 					#if defined(GB_SYSTEM_WINDOWS)
 					#if defined(GB_SYSTEM_WINDOWS)
 						case BuildFlag_IgnoreVsSearch:
 						case BuildFlag_IgnoreVsSearch:
 							GB_ASSERT(value.kind == ExactValue_Invalid);
 							GB_ASSERT(value.kind == ExactValue_Invalid);
@@ -1529,6 +1542,14 @@ void print_show_help(String const arg0, String const &command) {
 	print_usage_line(1, "Flags");
 	print_usage_line(1, "Flags");
 	print_usage_line(0, "");
 	print_usage_line(0, "");
 
 
+	if (doc) {
+		print_usage_line(1, "-package:<string>");
+		print_usage_line(2, "Add package name to generate documentation for");
+		print_usage_line(2, "Multiple flags are allowed");
+		print_usage_line(2, "Example: -doc:runtime");
+		print_usage_line(0, "");
+	}
+
 	if (run_or_build) {
 	if (run_or_build) {
 		print_usage_line(1, "-out:<filepath>");
 		print_usage_line(1, "-out:<filepath>");
 		print_usage_line(2, "Set the file name of the outputted executable");
 		print_usage_line(2, "Set the file name of the outputted executable");
@@ -1795,6 +1816,8 @@ int main(int arg_count, char const **arg_ptr) {
 	add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
 	add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
 
 
 	map_init(&build_context.defined_values, heap_allocator());
 	map_init(&build_context.defined_values, heap_allocator());
+	build_context.doc_packages.allocator = heap_allocator();
+
 
 
 	Array<String> args = setup_args(arg_count, arg_ptr);
 	Array<String> args = setup_args(arg_count, arg_ptr);
 
 

+ 1 - 5
src/parser.cpp

@@ -4648,10 +4648,6 @@ void parser_add_foreign_file_to_process(Parser *p, AstPackage *pkg, AstForeignFi
 
 
 // NOTE(bill): Returns true if it's added
 // NOTE(bill): Returns true if it's added
 bool try_add_import_path(Parser *p, String const &path, String const &rel_path, TokenPos pos, PackageKind kind = Package_Normal) {
 bool try_add_import_path(Parser *p, String const &path, String const &rel_path, TokenPos pos, PackageKind kind = Package_Normal) {
-	if (build_context.generate_docs) {
-		return false;
-	}
-
 	String const FILE_EXT = str_lit(".odin");
 	String const FILE_EXT = str_lit(".odin");
 
 
 	gb_mutex_lock(&p->file_add_mutex);
 	gb_mutex_lock(&p->file_add_mutex);
@@ -5253,7 +5249,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) {
 	}
 	}
 
 
 	TokenPos init_pos = {};
 	TokenPos init_pos = {};
-	if (!build_context.generate_docs) {
+	{
 		String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
 		String s = get_fullpath_core(heap_allocator(), str_lit("runtime"));
 		try_add_import_path(p, s, s, init_pos, Package_Runtime);
 		try_add_import_path(p, s, s, init_pos, Package_Runtime);
 	}
 	}