about summary refs log blame commit diff stats
path: root/counters.mu
blob: 0e4145131104963cfea960374db5433031e6cb76 (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                               
                                                                                                             















                                                               
                                                 
                                                   
                             
                                                   
                           


                                               
(function init-counter [
  (default-space:space-address <- new space:literal 30:literal)
  (n:integer <- next-input)
  (reply default-space:space-address)
 ])

(function increment-counter [
  (default-space:space-address <- new space:literal 30:literal)
  (0:space-address/names:init-counter <- next-input)  ; setup outer space; it *must* come from 'init-counter'
  (x:integer <- next-input)
  (n:integer/space:1 <- add n:integer/space:1 x:integer)
  (reply n:integer/space:1)
 ])

(function main [
  (default-space:space-address <- new space:literal 30:literal)
  ; counter A
  (a:space-address <- init-counter 34:literal)
  ; counter B
  (b:space-address <- init-counter 23:literal)
  ; increment both by 2 but in different ways
  (increment-counter a:space-address 1:literal)
  (bres:integer <- increment-counter b:space-address 2:literal)
  (ares:integer <- increment-counter a:space-address 1:literal)
  ; check results
  ($print (("Contents of counters a: " literal)))
  (print-integer nil:literal/terminal ares:integer)
  ($print ((" b: " literal)))
  (print-integer nil:literal/terminal bres:integer)
  ($print (("\n" literal)))
 ])

; compare http://www.paulgraham.com/accgen.html
n class="w"> vector<pair<string, vector<string> > > properties; string name; double value; bool initialized; vector<type_ordinal> types; reagent(string s); reagent(); void set_value(double v) { value = v; initialized = true; } string to_string() const; }; :(before "struct reagent") struct property { vector<string> values; }; :(before "End Globals") // Locations refer to a common 'memory'. Each location can store a number. map<long long int, double> Memory; :(before "End Setup") Memory.clear(); :(after "Types") // Mu types encode how the numbers stored in different parts of memory are // interpreted. A location tagged as a 'character' type will interpret the // number 97 as the letter 'a', while a different location of type 'number' // would not. // // Unlike most computers today, mu stores types in a single big table, shared // by all the mu programs on the computer. This is useful in providing a // seamless experience to help understand arbitrary mu programs. typedef long long int type_ordinal; :(before "End Globals") map<string, type_ordinal> Type_ordinal; map<type_ordinal, type_info> Type; type_ordinal Next_type_ordinal = 1; :(code) void setup_types() { Type.clear(); Type_ordinal.clear(); Type_ordinal["literal"] = 0; Next_type_ordinal = 1; // Mu Types Initialization type_ordinal number = Type_ordinal["number"] = Next_type_ordinal++; Type_ordinal["location"] = Type_ordinal["number"]; // wildcard type: either a pointer or a scalar Type[number].name = "number"; type_ordinal address = Type_ordinal["address"] = Next_type_ordinal++; Type[address].name = "address"; type_ordinal boolean = Type_ordinal["boolean"] = Next_type_ordinal++; Type[boolean].name = "boolean"; type_ordinal character = Type_ordinal["character"] = Next_type_ordinal++; Type[character].name = "character"; // Array types are a special modifier to any other type. For example, // array:number or array:address:boolean. type_ordinal array = Type_ordinal["array"] = Next_type_ordinal++; Type[array].name = "array"; // End Mu Types Initialization } :(before "End One-time Setup") setup_types(); :(before "End Types") // You can construct arbitrary new types. New types are either 'containers' // with multiple 'elements' of other types, or 'exclusive containers' containing // one of multiple 'variants'. (These are similar to C structs and unions, // respectively, though exclusive containers implicitly include a tag element // recording which variant they should be interpreted as.) // // For example, storing bank balance and name for an account might require a // container, but if bank accounts may be either for individuals or groups, // with different properties for each, that may require an exclusive container // whose variants are individual-account and joint-account containers. enum kind_of_type { primitive, container, exclusive_container }; struct type_info { string name; kind_of_type kind; long long int size; // only if type is not primitive; primitives and addresses have size 1 (except arrays are dynamic) vector<vector<type_ordinal> > elements; vector<string> element_names; // End type_info Fields type_info() :kind(primitive), size(0) {} }; enum primitive_recipes { IDLE = 0, COPY, // End Primitive Recipe Declarations MAX_PRIMITIVE_RECIPES, }; :(code) //: It's all very well to construct recipes out of other recipes, but we need //: to know how to do *something* out of the box. For the following //: recipes there are only codes, no entries in the book, because mu just knows //: what to do for them. void setup_recipes() { Recipe.clear(); Recipe_ordinal.clear(); Recipe_ordinal["idle"] = IDLE; // Primitive Recipe Numbers Recipe_ordinal["copy"] = COPY; // End Primitive Recipe Numbers } //: We could just reset the recipe table after every test, but that gets slow //: all too quickly. Instead, initialize the common stuff just once at //: startup. Later layers will carefully undo each test's additions after //: itself. :(before "End One-time Setup") setup_recipes(); assert(MAX_PRIMITIVE_RECIPES < 200); // level 0 is primitives; until 199 Next_recipe_ordinal = 200; Recipe_ordinal["main"] = Next_recipe_ordinal++; // End Load Recipes :(before "End Test Run Initialization") assert(Next_recipe_ordinal < 1000); // recipes being tested didn't overflow into test space :(before "End Setup") Next_recipe_ordinal = 1000; // consistent new numbers for each test //:: Helpers :(code) instruction::instruction() :is_label(false), operation(IDLE) { // End instruction Constructor } void instruction::clear() { is_label=false; label.clear(); operation=IDLE; ingredients.clear(); products.clear(); } // Reagents have the form <name>:<type>:<type>:.../<property>/<property>/... reagent::reagent(string s) :original_string(s), value(0), initialized(false) { // Parsing reagent(string s) istringstream in(s); in >> std::noskipws; // properties while (!in.eof()) { istringstream row(slurp_until(in, '/')); row >> std::noskipws; string name = slurp_until(row, ':'); vector<string> values; while (!row.eof()) values.push_back(slurp_until(row, ':')); properties.push_back(pair<string, vector<string> >(name, values)); } // structures for the first row of properties name = properties.at(0).first; for (long long int i = 0; i < SIZE(properties.at(0).second); ++i) { string type = properties.at(0).second.at(i); if (Type_ordinal.find(type) == Type_ordinal.end() // types can contain integers, like for array sizes && !is_integer(type)) { Type_ordinal[type] = Next_type_ordinal++; } types.push_back(Type_ordinal[type]); } if (is_integer(name) && types.empty()) { types.push_back(0); properties.at(0).second.push_back("literal"); } if (name == "_" && types.empty()) { types.push_back(0); properties.at(0).second.push_back("dummy"); } // End Parsing reagent } reagent::reagent() :value(0), initialized(false) { // The first property is special, so ensure we always have it. // Other properties can be pushed back, but the first must always be // assigned to. properties.push_back(pair<string, vector<string> >("", vector<string>())); } string reagent::to_string() const { ostringstream out; out << "{name: \"" << name << "\""; if (!properties.empty()) { out << ", properties: ["; for (long long int i = 0; i < SIZE(properties); ++i) { out << "\"" << properties.at(i).first << "\": "; for (long long int j = 0; j < SIZE(properties.at(i).second); ++j) { if (j > 0) out << ':'; out << "\"" << properties.at(i).second.at(j) << "\""; } if (i < SIZE(properties)-1) out << ", "; else out << "]"; } } out << "}"; return out.str(); } string instruction::to_string() const { if (is_label) return label; ostringstream out; for (long long int i = 0; i < SIZE(products); ++i) { if (i > 0) out << ", "; out << products.at(i).original_string; } if (!products.empty()) out << " <- "; out << name << ' '; for (long long int i = 0; i < SIZE(ingredients); ++i) { if (i > 0) out << ", "; out << ingredients.at(i).original_string; } return out.str(); } string slurp_until(istream& in, char delim) { ostringstream out; char c; while (in >> c) { if (c == delim) { // drop the delim break; } out << c; } return out.str(); } bool has_property(reagent x, string name) { for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) { if (x.properties.at(i).first == name) return true; } return false; } vector<string> property(const reagent& r, const string& name) { for (long long int p = /*skip name:type*/1; p != SIZE(r.properties); ++p) { if (r.properties.at(p).first == name) return r.properties.at(p).second; } return vector<string>(); } void dump_memory() { for (map<long long int, double>::iterator p = Memory.begin(); p != Memory.end(); ++p) { cout << p->first << ": " << no_scientific(p->second) << '\n'; } } void dump_recipe(const string& recipe_name) { const recipe& r = Recipe[Recipe_ordinal[recipe_name]]; cout << "recipe " << r.name << " [\n"; for (long long int i = 0; i < SIZE(r.steps); ++i) { cout << " " << r.steps.at(i).to_string() << '\n'; } cout << "]\n"; } :(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; tmp << std::fixed << x.x; os << trim_floating_point(tmp.str()); return os; } string trim_floating_point(const string& in) { if (in.empty()) return ""; long long int len = SIZE(in); while (len > 1) { if (in.at(len-1) != '0') break; --len; } if (in.at(len-1) == '.') --len; //? cerr << in << ": " << in.substr(0, len) << '\n'; return in.substr(0, len); } void test_trim_floating_point() { CHECK_EQ("", trim_floating_point("")); CHECK_EQ("0", trim_floating_point("000000000")); CHECK_EQ("1.5", trim_floating_point("1.5000")); CHECK_EQ("1.000001", trim_floating_point("1.000001")); CHECK_EQ("23", trim_floating_point("23.000000")); CHECK_EQ("23", trim_floating_point("23.0")); CHECK_EQ("23", trim_floating_point("23.")); CHECK_EQ("23", trim_floating_point("23")); CHECK_EQ("3", trim_floating_point("3.000000")); CHECK_EQ("3", trim_floating_point("3.0")); CHECK_EQ("3", trim_floating_point("3.")); CHECK_EQ("3", trim_floating_point("3")); } :(before "End Includes") #include<utility> using std::pair; #include<math.h>