//: For convenience, allow Mu types to be abbreviated. void test_type_abbreviations() { transform( "type foo = number\n" "def main [\n" " a:foo <- copy 34\n" "]\n" ); CHECK_TRACE_CONTENTS( "transform: product type after expanding abbreviations: \"number\"\n" ); } :(before "End Globals") map Type_abbreviations, Type_abbreviations_snapshot; //:: Defining type abbreviations. :(before "End Command Handlers") else if (command == "type") { load_type_abbreviations(in); } :(code) void load_type_abbreviations(istream& in) { string new_type_name = next_word(in); assert(has_data(in) || !new_type_name.empty()); if (!has_data(in) || new_type_name.empty()) { raise << "incomplete 'type' statement; must be of the form 'type = '\n" << end(); return; } string arrow = next_word(in); assert(has_data(in) || !arrow.empty()); if (arrow.empty()) { raise << "incomplete 'type' statement 'type " << new_type_name << "'\n" << end(); return; } if (arrow != "=") { raise << "'type' statements must be of the form 'type = ' but got 'type " << new_type_name << ' ' << arrow << "'\n" << end(); return; } if (!has_data(in)) { raise << "incomplete 'type' statement 'type " << new_type_name << " ='\n" << end(); return; } string old = next_word(in); if (old.empty()) { raise << "incomplete 'type' statement 'type " << new_type_name << " ='\n" << end(); raise << "'type' statements must be of the form 'type = ' but got 'type " << new_type_name << ' ' << arrow << "'\n" << end(); return; } if (contains_key(Type_abbreviations, new_type_name)) { raise << "'type' conflict: '" << new_type_name << "' defined as both '" << names_to_string_without_quotes(get(Type_abbreviations, new_type_name)) << "' and '" << old << "'\n" << end(); return; } trace(100, "type") << "alias " << new_type_name << " = " << old << end(); type_tree* old_type = new_type_tree(old); put(Type_abbreviations, new_type_name, old_type); } type_tree* new_type_tree(const string& x) { string_tree* type_names = starts_with(x, "(") ? parse_string_tree(x) : parse_string_list(x); type_tree* result = new_type_tree(type_names); delete type_names; expand_type_abbreviations(result); return result; } string_tree* parse_string_list(const string& s) { istringstream in(s); in >> std::noskipws; return parse_property_list(in); } void test_type_error1() { Hide_errors = true; transform( "type foo\n" ); CHECK_TRACE_CONTENTS( "error: incomplete 'type' statement 'type foo'\n" ); } void test_type_error2() { Hide_errors = true; transform( "type foo =\n" ); CHECK_TRACE_CONTENTS( "error: incomplete 'type' statement 'type foo ='\n" ); } void test_type_error3() { Hide_errors = true; transform( "type foo bar baz\n" ); CHECK_TRACE_CONTENTS( "error: 'type' statements must be of the form 'type = ' but got 'type foo bar'\n" ); } void test_type_conflict_error() { Hide_errors = true; transform( "type foo = bar\n" "type foo = baz\n" ); CHECK_TRACE_CONTENTS( "error: 'type' conflict: 'foo' defined as both 'bar' and 'baz'\n" ); } void test_type_abbreviation_for_compound() { transform( "type foo = address:number\n" "def main [\n" " 1:foo <- copy null\n" "]\n" ); CHECK_TRACE_CONTENTS( "transform: product type after expanding abbreviations: (\"address\" \"number\")\n" ); } //: cleaning up type abbreviations between tests and before exiting :(before "End save_snapshots") Type_abbreviations_snapshot = Type_abbreviations; :(before "End restore_snapshots") restore_type_abbreviations(); :(before "End One-time Setup") atexit(clear_type_abbreviations); :(code) void restore_type_abbreviations() { for (map::iterator p = Type_abbreviations.begin(); p != Type_abbreviations.end(); ++p) { if (!contains_key(Type_abbreviations_snapshot, p->first)) delete p->second; } Type_abbreviations.clear(); Type_abbreviations = Type_abbreviations_snapshot; } void clear_type_abbreviations() { for (map::iterator p = Type_abbreviations.begin(); p != Type_abbreviations.end(); ++p) delete p->second; Type_abbreviations.clear(); } //:: A few de