about summary refs log blame commit diff stats
path: root/029tools.cc
blob: 244b72b25cb251bffa07b1c286dd8c8f3fcd89dd (plain) (tree)
9;\n'; } } //:: Helpers for converting various values to string //: Use to_string() in trace(), and try to keep it stable from run to run. //: Use debug_string() while debugging, and throw everything into it. //: Use inspect() only for emitting a canonical format that can be parsed back //: into the value. string to_string(const recipe& r) { ostringstream out; out << "recipe " << r.name << " [\n"; for (int i = 0; i < SIZE(r.steps); ++i) out << " " << to_string(r.steps.at(i)) << '\n'; out << "]\n"; return out.str(); } string to_original_string(const recipe& r) { ostringstream out; out << "recipe " << r.name << " [\n"; for (int i = 0; i < SIZE(r.steps); ++i) out << " " << to_original_string(r.steps.at(i)) << '\n'; out << "]\n"; return out.str(); } string debug_string(const recipe& x) { ostringstream out; out << "- recipe " << x.name << '\n'; // Begin debug_string(recipe x) for (int index = 0; index < SIZE(x.steps); ++index) { const instruction& inst = x.steps.at(index); out << "inst: " << to_string(inst) << '\n'; out << " ingredients\n"; for (int i = 0; i < SIZE(inst.ingredients); ++i) out << " " << debug_string(inst.ingredients.at(i)) << '\n'; out << " products\n"; for (int i = 0; i < SIZE(inst.products); ++i) out << " " << debug_string(inst.products.at(i)) << '\n'; } return out.str(); } string to_original_string(const instruction& inst) { if (inst.is_label) return inst.label; if (!inst.original_string.empty()) return inst.original_string; ostringstream out; for (int i = 0; i < SIZE(inst.products); ++i) { if (i > 0) out << ", "; out << inst.products.at(i).original_string; } if (!inst.products.empty()) out << " <- "; out << inst.name; if (!inst.ingredients.empty()) out << ' '; for (int i = 0; i < SIZE(inst.ingredients); ++i) { if (i > 0) out << ", "; out << inst.ingredients.at(i).original_string; } return out.str(); } string to_string(const instruction& inst) { if (inst.is_label) return inst.label; ostringstream out; for (int i = 0; i < SIZE(inst.products); ++i) { if (i > 0) out << ", "; out << to_string(inst.products.at(i)); } if (!inst.products.empty()) out << " <- "; out << inst.name << ' '; for (int i = 0; i < SIZE(inst.ingredients); ++i) { if (i > 0) out << ", "; out << to_string(inst.ingredients.at(i)); } return out.str(); } string to_string(const reagent& r) { if (is_dummy(r)) return "_"; ostringstream out; out << "{"; out << r.name << ": " << names_to_string(r.type); if (!r.properties.empty()) { for (int i = 0; i < SIZE(r.properties); ++i) out << ", \"" << r.properties.at(i).first << "\": " << to_string(r.properties.at(i).second); } out << "}"; return out.str(); } // special name for ignoring some products bool is_dummy(const reagent& x) { return x.name == "_"; } string debug_string(const reagent& x) { ostringstream out; out << x.name << ": " << x.value << ' ' << to_string(x.type) << " -- " << to_string(x); return out.str(); } string to_string(const string_tree* property) { if (!property) return "()"; ostringstream out; dump(property, out); return out.str(); } void dump(const string_tree* x, ostream& out) { if (!x) return; if (x->atom) { out << '"' << x->value << '"'; return; } out << '('; const string_tree* curr = x; while (curr && !curr->atom) { dump(curr->left, out); if (curr->right) out << ' '; curr = curr->right; } // check for dotted list; should never happen if (curr) { out << ". "; dump(curr, out); } out << ')'; } string to_string(const type_tree* type) { if (type == NULL) return "()"; ostringstream out; dump(type, out); return out.str(); } void dump(const type_tree* x, ostream& out) { if (!x) return; if (x->atom) { dump(x->value, out); return; } out << '('; const type_tree* curr = x; while (curr && !curr->atom) { dump(curr->left, out); if (curr->right) out << ' '; curr = curr->right; } // check for dotted list; should never happen if (curr) { out << ". "; dump(curr, out); } out << ')'; } void dump(type_ordinal type, ostream& out) { if (contains_key(Type, type)) out << get(Type, type).name; else out << "?" << type; } string names_to_string(const type_tree* type) { if (type == NULL) return "()"; // should never happen ostringstream out; dump_names(type, out); return out.str(); } void dump_names(const type_tree* x, ostream& out) { if (!x) return; if (x->atom) { out << '"' << x->name << '"'; return; } out << '('; const type_tree* curr = x; while (curr && !curr->atom) { dump_names(curr->left, out); if (curr->right) out << ' '; curr = curr->right; } // check for dotted list; should never happen if (curr) { out << ". "; dump_names(curr, out); } out << ')'; } string names_to_string_without_quotes(const type_tree* type) { if (type == NULL) return "()"; ostringstream out; dump_names_without_quotes(type, out); return out.str(); } void dump_names_without_quotes(const type_tree* x, ostream& out) { if (!x) return; if (x->atom) { out << x->name; return; } out << '('; const type_tree* curr = x; while (curr && !curr->atom) { dump_names_without_quotes(curr->left, out); if (curr->right) out << ' '; curr = curr->right; } // check for dotted list; should never happen if (curr) { out << ". "; dump_names_without_quotes(curr, out); } out << ')'; } bool is_integer(const string& s) { return s.find_first_not_of("0123456789-") == string::npos // no other characters && s.find_first_of("0123456789") != string::npos // at least one digit && s.find('-', 1) == string::npos; // '-' only at first position } int to_integer(string n) { char* end = NULL; // safe because string.c_str() is guaranteed to be null-terminated int result = strtoll(n.c_str(), &end, /*any base*/0); if (*end != '\0') cerr << "tried to convert " << n << " to number\n"; assert(*end == '\0'); return result; } void test_is_integer() { CHECK(is_integer("1234")); CHECK(is_integer("-1")); CHECK(!is_integer("234.0")); CHECK(is_integer("-567")); CHECK(!is_integer("89-0")); CHECK(!is_integer("-")); CHECK(!is_integer("1e3")); // not supported } //: helper to print numbers without excessive precision :(before "End Types") struct no_scientific { double x; explicit no_scientific(double y) :x(y) {} }; :(code) ostream& operator<<(ostream& os, no_scientific x) { if (!isfinite(x.x)) { // Infinity or NaN os << x.x; return os; } ostringstream tmp; // more accurate, but too slow //? tmp.precision(308); // for 64-bit numbers tmp << std::fixed << x.x; os << trim_floating_point(tmp.str()); return os; } string trim_floating_point(const string& in) { if (in.empty()) return ""; if (in.find('.') == string::npos) return in; int length = SIZE(in); while (length > 1) { if (in.at(length-1) != '0') break; --length; } if (in.at(length-1) == '.') --length; if (length == 0) return "0"; return in.substr(0, length); } void test_trim_floating_point() { CHECK_EQ(trim_floating_point(""), ""); CHECK_EQ(trim_floating_point(".0"), "0"); CHECK_EQ(trim_floating_point("1.5000"), "1.5"); CHECK_EQ(trim_floating_point("1.000001"), "1.000001"); CHECK_EQ(trim_floating_point("23.000000"), "23"); CHECK_EQ(trim_floating_point("23.0"), "23"); CHECK_EQ(trim_floating_point("23."), "23"); CHECK_EQ(trim_floating_point("23"), "23"); CHECK_EQ(trim_floating_point("230"), "230"); CHECK_EQ(trim_floating_point("3.000000"), "3"); CHECK_EQ(trim_floating_point("3.0"), "3"); CHECK_EQ(trim_floating_point("3."), "3"); CHECK_EQ(trim_floating_point("3"), "3"); } :(before "End Includes") #include <utility> using std::pair; #include <math.h>