2283 - represent each /property as a tree

This commit is contained in:
Kartik K. Agaram 2015-10-26 20:00:38 -07:00
parent 7bba6e7bb7
commit ae256ea13e
19 changed files with 150 additions and 94 deletions

143
010vm.cc
View File

@ -48,7 +48,7 @@ struct instruction {
// properties besides types, but we're getting ahead of ourselves.
struct reagent {
string original_string;
vector<pair<string, vector<string> > > properties;
vector<pair<string, string_tree*> > properties;
string name;
double value;
bool initialized;
@ -76,13 +76,27 @@ struct type_tree {
~type_tree();
type_tree(const type_tree& old);
// simple: type ordinal
type_tree(type_ordinal v) :value(v), left(NULL), right(NULL) {}
explicit type_tree(type_ordinal v) :value(v), left(NULL), right(NULL) {}
// intermediate: list of type ordinals
type_tree(type_ordinal v, type_tree* r) :value(v), left(NULL), right(r) {}
// advanced: tree containing type ordinals
type_tree(type_tree* l, type_tree* r) :value(0), left(l), right(r) {}
};
struct string_tree {
string value;
string_tree* left;
string_tree* right;
~string_tree();
string_tree(const string_tree& old);
// simple: flat string
explicit string_tree(string v) :value(v), left(NULL), right(NULL) {}
// intermediate: list of strings
string_tree(string v, string_tree* r) :value(v), left(NULL), right(r) {}
// advanced: tree containing strings
string_tree(string_tree* l, string_tree* r) :left(l), right(r) {}
};
:(before "End Globals")
// Locations refer to a common 'memory'. Each location can store a number.
map<long long int, double> Memory;
@ -218,39 +232,59 @@ reagent::reagent(string s) :original_string(s), value(0), initialized(false), ty
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));
string key = slurp_until(row, ':');
string_tree* value = parse_property_list(row);
properties.push_back(pair<string, string_tree*>(key, value));
}
// structures for the first row of properties: name and list of types
name = properties.at(0).first;
type_tree** curr_type = &type;
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++;
}
*curr_type = new type_tree(Type_ordinal[type]);
curr_type = &(*curr_type)->right;
}
type = new_type_tree(properties.at(0).second);
if (is_integer(name) && type == NULL) {
type = new type_tree(0);
properties.at(0).second.push_back("literal");
assert(!properties.at(0).second);
properties.at(0).second = new string_tree("literal");
}
if (name == "_" && type == NULL) {
type = new type_tree(0);
properties.at(0).second.push_back("dummy");
assert(!properties.at(0).second);
properties.at(0).second = new string_tree("dummy");
}
// End Parsing reagent
}
string_tree* parse_property_list(istream& in) {
skip_whitespace(in);
if (in.eof()) return NULL;
string_tree* result = new string_tree(slurp_until(in, ':'));
result->right = parse_property_list(in);
return result;
}
type_tree* new_type_tree(const string_tree* properties) {
if (!properties) return NULL;
type_tree* result = new type_tree(0);
if (!properties->value.empty()) {
const string& type_name = properties->value;
if (Type_ordinal.find(type_name) == Type_ordinal.end()
// types can contain integers, like for array sizes
&& !is_integer(type_name)) {
Type_ordinal[type_name] = Next_type_ordinal++;
}
result->value = Type_ordinal[type_name];
}
result->left = new_type_tree(properties->left);
result->right = new_type_tree(properties->right);
return result;
}
//: avoid memory leaks for the type tree
reagent::reagent(const reagent& old) :original_string(old.original_string), properties(old.properties), name(old.name), value(old.value), initialized(old.initialized) {
properties.clear();
for (long long int i = 0; i < SIZE(old.properties); ++i) {
properties.push_back(pair<string, string_tree*>(old.properties.at(i).first,
old.properties.at(i).second ? new string_tree(*old.properties.at(i).second) : NULL));
}
type = old.type ? new type_tree(*old.type) : NULL;
}
@ -259,29 +293,45 @@ type_tree::type_tree(const type_tree& old) :value(old.value) {
right = old.right ? new type_tree(*old.right) : NULL;
}
string_tree::string_tree(const string_tree& old) { // :value(old.value) {
value = old.value;
left = old.left ? new string_tree(*old.left) : NULL;
right = old.right ? new string_tree(*old.right) : NULL;
}
reagent& reagent::operator=(const reagent& old) {
original_string = old.original_string;
properties = old.properties;
properties.clear();
for (long long int i = 0; i < SIZE(old.properties); ++i) {
properties.push_back(pair<string, string_tree*>(old.properties.at(i).first, old.properties.at(i).second ? new string_tree(*old.properties.at(i).second) : NULL));
}
name = old.name;
value = old.value;
initialized = old.initialized;
type = old.type? new type_tree(*old.type) : NULL;
type = old.type ? new type_tree(*old.type) : NULL;
return *this;
}
reagent::~reagent() {
for (long long int i = 0; i < SIZE(properties); ++i) {
if (properties.at(i).second) delete properties.at(i).second;
}
delete type;
}
type_tree::~type_tree() {
delete left;
delete right;
}
string_tree::~string_tree() {
delete left;
delete right;
}
reagent::reagent() :value(0), initialized(false), type(NULL) {
// 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>()));
properties.push_back(pair<string, string_tree*>("", NULL));
}
string reagent::to_string() const {
@ -291,26 +341,35 @@ string reagent::to_string() const {
for (long long int i = 0; i < SIZE(properties); ++i) {
if (i > 0) out << ", ";
out << "\"" << properties.at(i).first << "\": ";
if (properties.at(i).second.empty()) {
out << "\"\"";
continue;
}
if (SIZE(properties.at(i).second) == 1) {
out << "\"" << properties.at(i).second.at(0) << "\"";
continue;
}
out << "<";
for (long long int j = 0; j < SIZE(properties.at(i).second); ++j) {
if (j > 0) out << " : ";
out << "\"" << properties.at(i).second.at(j) << "\"";
}
out << ">";
dump_property(properties.at(i).second, out);
}
out << "}";
}
return out.str();
}
void dump_property(const string_tree* property, ostringstream& out) {
if (!property) {
out << "<>";
return;
}
if (!property->left && !property->right) {
out << '"' << property->value << '"';
return;
}
out << "<";
if (property->left)
dump_property(property->left, out);
else
out << '"' << property->value << '"';
out << " : ";
if (property->right)
dump_property(property->right, out);
else
out << " : <>";
out << ">";
}
string dump_types(const reagent& x) {
ostringstream out;
dump_types(x.type, out);
@ -371,12 +430,12 @@ bool has_property(reagent x, string name) {
return false;
}
vector<string> property(const reagent& r, const string& name) {
string_tree* 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>();
return NULL;
}
void dump_memory() {
@ -394,6 +453,12 @@ void dump_recipe(const string& recipe_name) {
cout << "]\n";
}
void skip_whitespace(istream& in) {
while (!in.eof() && isspace(in.peek()) && in.peek() != '\n') {
in.get();
}
}
:(before "End Types")
struct no_scientific {
double x;

View File

@ -186,12 +186,6 @@ void slurp_word(istream& in, ostream& out) {
}
}
void skip_whitespace(istream& in) {
while (!in.eof() && isspace(in.peek()) && in.peek() != '\n') {
in.get();
}
}
void skip_whitespace_and_comments(istream& in) {
while (true) {
if (in.eof()) break;
@ -246,6 +240,7 @@ for (long long int i = 0; i < SIZE(recently_added_recipes); ++i) {
// Clear Other State For recently_added_recipes
recently_added_recipes.clear();
:(code)
:(scenario parse_comment_outside_recipe)
# this comment will be dropped by the tangler, so we need a dummy recipe to stop that
recipe f1 [ ]
@ -350,7 +345,7 @@ recipe main [
recipe main [
1:number:address/lookup <- copy 23
]
+parse: product: {"1": <"number" : "address">, "lookup": ""}
+parse: product: {"1": <"number" : "address">, "lookup": <>}
//: this test we can't represent with a scenario
:(code)

View File

@ -112,8 +112,7 @@ if (s.at(0) == '[') {
strip_last(s);
name = s;
type = new type_tree(0);
properties.push_back(pair<string, vector<string> >(name, vector<string>()));
properties.back().second.push_back("literal-string");
properties.push_back(pair<string, string_tree*>(name, new string_tree("literal-string")));
return;
}
@ -126,7 +125,7 @@ if (s.at(0) == '[') {
:(code)
bool is_literal_string(const reagent& x) {
return !x.properties.at(0).second.empty() && x.properties.at(0).second.at(0) == "literal-string";
return x.properties.at(0).second && x.properties.at(0).second->value == "literal-string";
}
string emit_literal_string(string name) {
@ -172,7 +171,7 @@ recipe main [
]
+parse: instruction: copy
+parse: ingredient: {"abc": "literal-string"}
+parse: product: {"1": <"address" : "array" : "character">}
+parse: product: {"1": <"address" : <"array" : "character">>}
# no other ingredients
$parse: 3

View File

@ -11,8 +11,7 @@ recipe main [
if (is_noninteger(s)) {
name = s;
type = new type_tree(0);
properties.push_back(pair<string, vector<string> >(name, vector<string>()));
properties.back().second.push_back("literal-number");
properties.push_back(pair<string, string_tree*>(name, new string_tree("literal-number")));
set_value(to_double(s));
return;
}

View File

@ -111,8 +111,8 @@ bool is_mu_address(reagent r) {
bool is_mu_number(reagent r) {
if (!r.type) return false;
if (is_literal(r))
return r.properties.at(0).second.at(0) == "literal-number"
|| r.properties.at(0).second.at(0) == "literal";
return r.properties.at(0).second->value == "literal-number"
|| r.properties.at(0).second->value == "literal";
if (r.type->value == Type_ordinal["character"]) return true; // permit arithmetic on unicode code points
return r.type->value == Type_ordinal["number"];
}
@ -120,7 +120,7 @@ bool is_mu_number(reagent r) {
bool is_mu_scalar(reagent r) {
if (!r.type) return false;
if (is_literal(r))
return r.properties.at(0).second.empty() || r.properties.at(0).second.at(0) != "literal-string";
return !r.properties.at(0).second || r.properties.at(0).second->value != "literal-string";
if (is_mu_array(r)) return false;
return size_of(r) == 1;
}

View File

@ -95,7 +95,7 @@ void drop_address_from_type(reagent& r) {
}
void drop_one_lookup(reagent& r) {
for (vector<pair<string, vector<string> > >::iterator p = r.properties.begin(); p != r.properties.end(); ++p) {
for (vector<pair<string, string_tree*> >::iterator p = r.properties.begin(); p != r.properties.end(); ++p) {
if (p->first == "lookup") {
r.properties.erase(p);
return;
@ -161,7 +161,7 @@ recipe main [
{
while (!name.empty() && name.at(0) == '*') {
name.erase(0, 1);
properties.push_back(pair<string, vector<string> >("lookup", vector<string>()));
properties.push_back(pair<string, string_tree*>("lookup", NULL));
}
if (name.empty())
raise_error << "illegal name " << original_string << '\n' << end();

View File

@ -34,12 +34,12 @@ case CREATE_ARRAY: {
break;
}
// 'create-array' will need to check properties rather than types
if (SIZE(product.properties.at(0).second) <= 2) {
if (!product.properties.at(0).second || !product.properties.at(0).second->right || !product.properties.at(0).second->right->right) {
raise_error << maybe(Recipe[r].name) << "create array of what size? " << inst.to_string() << '\n' << end();
break;
}
if (!is_integer(product.properties.at(0).second.at(2))) {
raise_error << maybe(Recipe[r].name) << "'create-array' product should specify size of array after its element type, but got " << product.properties.at(0).second.at(2) << '\n' << end();
if (!is_integer(product.properties.at(0).second->right->right->value)) {
raise_error << maybe(Recipe[r].name) << "'create-array' product should specify size of array after its element type, but got " << product.properties.at(0).second->right->right->value << '\n' << end();
break;
}
break;
@ -49,7 +49,7 @@ case CREATE_ARRAY: {
reagent product = current_instruction().products.at(0);
canonize(product);
long long int base_address = product.value;
long long int array_size= to_integer(product.properties.at(0).second.at(2));
long long int array_size = to_integer(product.properties.at(0).second->right->right->value);
// initialize array size, so that size_of will work
Memory[base_address] = array_size; // in array elements
long long int size = size_of(product); // in locations

View File

@ -53,12 +53,12 @@ case REPLY: {
for (long long int i = 0; i < SIZE(caller_instruction.products); ++i) {
trace(Primitive_recipe_depth, "run") << "result " << i << " is " << to_string(ingredients.at(i)) << end();
if (has_property(reply_inst.ingredients.at(i), "same-as-ingredient")) {
vector<string> tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient");
if (SIZE(tmp) != 1) {
string_tree* tmp = property(reply_inst.ingredients.at(i), "same-as-ingredient");
if (!tmp || tmp->right) {
raise_error << maybe(current_recipe_name()) << "'same-as-ingredient' metadata should take exactly one value in " << reply_inst.to_string() << '\n' << end();
goto finish_reply;
}
long long int ingredient_index = to_integer(tmp.at(0));
long long int ingredient_index = to_integer(tmp->value);
if (ingredient_index >= SIZE(caller_instruction.ingredients))
raise_error << maybe(current_recipe_name()) << "'same-as-ingredient' metadata overflows ingredients in: " << caller_instruction.to_string() << '\n' << end();
if (!is_dummy(caller_instruction.products.at(i)) && caller_instruction.products.at(i).value != caller_instruction.ingredients.at(ingredient_index).value)

View File

@ -31,7 +31,7 @@ type_ordinal recipe_ordinal = Type_ordinal["recipe-ordinal"] = Next_type_ordinal
Type[recipe_ordinal].name = "recipe-ordinal";
:(before "End Reagent-parsing Exceptions")
if (!r.properties.at(0).second.empty() && r.properties.at(0).second.at(0) == "recipe") {
if (r.properties.at(0).second && r.properties.at(0).second->value == "recipe") {
r.set_value(Recipe_ordinal[r.name]);
return;
}

View File

@ -319,8 +319,8 @@ recipe main [
:(before "End NEW Transform Special-cases")
if (!inst.ingredients.empty()
&& !inst.ingredients.at(0).properties.empty()
&& !inst.ingredients.at(0).properties.at(0).second.empty()
&& inst.ingredients.at(0).properties.at(0).second.at(0) == "literal-string") {
&& inst.ingredients.at(0).properties.at(0).second
&& inst.ingredients.at(0).properties.at(0).second->value == "literal-string") {
// skip transform
inst.ingredients.at(0).initialized = true;
goto end_new_transform;
@ -437,5 +437,5 @@ string read_mu_string(long long int address) {
}
bool is_mu_type_literal(reagent r) {
return is_literal(r) && !r.properties.empty() && !r.properties.at(0).second.empty() && r.properties.at(0).second.at(0) == "type";
return is_literal(r) && !r.properties.empty() && r.properties.at(0).second && r.properties.at(0).second->value == "type";
}

View File

@ -56,7 +56,7 @@ void absolutize(reagent& x) {
raise_error << current_instruction().to_string() << ": reagent not initialized: " << x.original_string << '\n' << end();
}
x.set_value(address(x.value, space_base(x)));
x.properties.push_back(pair<string, vector<string> >("raw", vector<string>()));
x.properties.push_back(pair<string, string_tree*>("raw", NULL));
assert(is_raw(x));
}
@ -77,7 +77,7 @@ recipe main [
+mem: storing 35 in location 9
:(after "reagent tmp" following "case GET:")
tmp.properties.push_back(pair<string, vector<string> >("raw", vector<string>()));
tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
//:: fix 'index'
@ -97,7 +97,7 @@ recipe main [
+mem: storing 35 in location 9
:(after "reagent tmp" following "case INDEX:")
tmp.properties.push_back(pair<string, vector<string> >("raw", vector<string>()));
tmp.properties.push_back(pair<string, string_tree*>("raw", NULL));
//:: convenience operation to automatically deduce the amount of space to
//:: allocate in a default space with names

View File

@ -41,9 +41,9 @@ long long int space_base(const reagent& x, long long int space_index, long long
long long int space_index(const reagent& x) {
for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
if (x.properties.at(i).first == "space") {
if (SIZE(x.properties.at(i).second) != 1)
if (!x.properties.at(i).second || x.properties.at(i).second->right)
raise_error << maybe(current_recipe_name()) << "/space metadata should take exactly one value in " << x.original_string << '\n' << end();
return to_integer(x.properties.at(i).second.at(0));
return to_integer(x.properties.at(i).second->value);
}
}
return 0;

View File

@ -57,13 +57,13 @@ void collect_surrounding_spaces(const recipe_ordinal r) {
raise_error << "slot 0 should always have type address:array:location, but is " << inst.products.at(j).to_string() << '\n' << end();
continue;
}
vector<string> s = property(inst.products.at(j), "names");
if (s.empty()) {
string_tree* s = property(inst.products.at(j), "names");
if (!s) {
raise_error << "slot 0 requires a /names property in recipe " << Recipe[r].name << end();
continue;
}
if (SIZE(s) > 1) raise_error << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end();
string surrounding_recipe_name = s.at(0);
if (s->right) raise_error << "slot 0 should have a single value in /names, but got " << inst.products.at(j).to_string() << '\n' << end();
const string& surrounding_recipe_name = s->value;
if (Surrounding_space.find(r) != Surrounding_space.end()
&& Surrounding_space[r] != Recipe_ordinal[surrounding_recipe_name]) {
raise_error << "recipe " << Recipe[r].name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n' << end();
@ -84,9 +84,9 @@ long long int lookup_name(const reagent& x, const recipe_ordinal default_recipe)
if (Name[default_recipe].empty()) raise_error << "name not found: " << x.name << '\n' << end();
return Name[default_recipe][x.name];
}
vector<string> p = property(x, "space");
if (SIZE(p) != 1) raise_error << "/space property should have exactly one (non-negative integer) value\n" << end();
long long int n = to_integer(p.at(0));
string_tree* p = property(x, "space");
if (!p || p->right) raise_error << "/space property should have exactly one (non-negative integer) value\n" << end();
long long int n = to_integer(p->value);
assert(n >= 0);
recipe_ordinal surrounding_recipe = lookup_surrounding_recipe(default_recipe, n);
set<recipe_ordinal> done;
@ -127,12 +127,12 @@ recipe_ordinal lookup_surrounding_recipe(const recipe_ordinal r, long long int n
:(replace{} "bool already_transformed(const reagent& r, const map<string, long long int>& names)")
bool already_transformed(const reagent& r, const map<string, long long int>& names) {
if (has_property(r, "space")) {
vector<string> p = property(r, "space");
if (SIZE(p) != 1) {
string_tree* p = property(r, "space");
if (!p || p->right) {
raise_error << "/space property should have exactly one (non-negative integer) value in " << r.original_string << '\n' << end();
return false;
}
if (p.at(0) != "0") return true;
if (p->value != "0") return true;
}
return names.find(r.name) != names.end();
}

View File

@ -77,7 +77,7 @@ $error: 0
bool is_global(const reagent& x) {
for (long long int i = /*skip name:type*/1; i < SIZE(x.properties); ++i) {
if (x.properties.at(i).first == "space")
return !x.properties.at(i).second.empty() && x.properties.at(i).second.at(0) == "global";
return x.properties.at(i).second && x.properties.at(i).second->value == "global";
}
return false;
}

View File

@ -56,8 +56,8 @@ void deduce_missing_type(map<string, type_tree*>& metadata, reagent& x) {
if (x.type) return;
if (metadata.find(x.name) == metadata.end()) return;
x.type = new type_tree(*metadata[x.name]);
assert(x.properties.at(0).second.empty());
x.properties.at(0).second.push_back("as-before");
assert(!x.properties.at(0).second);
x.properties.at(0).second = new string_tree("as-before");
}
:(scenario transform_fills_in_missing_types_in_product)

View File

@ -305,7 +305,7 @@ void check_memory(const string& s) {
void check_type(const string& lhs, istream& in) {
reagent x(lhs);
if (x.properties.at(0).second.at(0) == "string") {
if (x.properties.at(0).second->value == "string") {
x.set_value(to_integer(x.name));
skip_whitespace_and_comments(in);
string _assign = next_word(in);

View File

@ -119,7 +119,7 @@ void append_fragment(vector<instruction>& base, const vector<instruction>& patch
for (long long int j = 0; j < SIZE(inst.ingredients); ++j) {
reagent& x = inst.ingredients.at(j);
if (!is_literal(x)) continue;
if (x.properties.at(0).second.at(0) == "label" && jump_targets.find(x.name) != jump_targets.end())
if (x.properties.at(0).second->value == "label" && jump_targets.find(x.name) != jump_targets.end())
x.name = prefix+x.name;
}
base.push_back(inst);

View File

@ -258,8 +258,8 @@ call_stack::iterator find_reset(call_stack& c) {
//: overload 'call' for continuations
:(after "Begin Call")
if (!current_instruction().ingredients.at(0).properties.empty()
&& !current_instruction().ingredients.at(0).properties.at(0).second.empty()
&& current_instruction().ingredients.at(0).properties.at(0).second.at(0) == "continuation") {
&& current_instruction().ingredients.at(0).properties.at(0).second
&& current_instruction().ingredients.at(0).properties.at(0).second->value == "continuation") {
// copy multiple calls on to current call stack
assert(scalar(ingredients.at(0)));
if (Delimited_continuation.find(ingredients.at(0).at(0)) == Delimited_continuation.end()) {

View File

@ -80,13 +80,11 @@ if (s.at(0) == '{') {
string key = next_dilated_word(in);
if (key.empty()) continue;
string value = next_dilated_word(in);
vector<string> values;
values.push_back(value);
properties.push_back(pair<string, vector<string> >(key, values));
properties.push_back(pair<string, string_tree*>(key, new string_tree(value)));
}
// structures for the first row of properties
name = properties.at(0).first;
string type_name = properties.at(0).second.at(0);
string type_name = properties.at(0).second->value;
if (Type_ordinal.find(type_name) == Type_ordinal.end()) {
// this type can't be an integer
Type_ordinal[type_name] = Next_type_ordinal++;