/*
* contact_list.h
*
* Copyright (C) 2012, 2013 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CONTACT_LIST_H
#define CONTACT_LIST_H
#include <glib.h>
#include "contact.h"
void contact_list_init(pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */:(after "Types")
// A program is a book of 'recipes' (functions)
typedef size_t recipe_number;
:(before "End Globals")
map<string, recipe_number> Recipe_number;
map<recipe_number, recipe> Recipe;
recipe_number Next_recipe_number = 1;
:(before "End Types")
// Recipes are lists of instructions. To run a recipe, the computer runs its
// instructions.
struct recipe {
string name;
vector<instruction> steps;
// End recipe Fields
};
:(before "struct recipe")
// Each instruction is either of the form:
// product1, product2, product3, ... <- operation ingredient1, ingredient2, ingredient3, ...
// or just a single 'label' starting with a non-alphanumeric character
// +label
// Labels don't do anything, they're just waypoints.
struct instruction {
bool is_label;
string label; // only if is_label
string name; // only if !is_label
recipe_number operation; // Recipe_number[name]
vector<reagent> ingredients; // only if !is_label
vector<reagent> products; // only if !is_label
instruction();
void clear();
string to_string() const;
};
:(before "struct instruction")
// Ingredients and products are a single species -- a reagent. Reagents refer
// either to numbers or to locations in memory along with 'type' tags telling
// us how to interpret them. They also can contain arbitrary other lists of
// properties besides types, but we're getting ahead of ourselves.
struct reagent {
vector<pair<string, vector<string> > > properties;
string name;
long long int value;
bool initialized;
vector<type_number> types;
reagent(string s);
reagent();
void set_value(long long int 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<index_t, long long int> 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 'integer'
// 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 size_t type_number;
:(before "End Globals")
map<string, type_number> Type_number;
map<type_number, type_info> Type;
type_number Next_type_number = 1;
:(code)
void setup_types() {
Type.clear(); Type_number.clear();
Type_number["literal"] = 0;
Next_type_number = 1;
// Mu Types Initialization
type_number integer = Type_number["integer"] = Next_type_number++;
Type_number["location"] = Type_number["integer"]; // wildcard type: either a pointer or a scalar
Type[integer].name = "integer";
type_number address = Type_number["address"] = Next_type_number++;
Type[address].name = "address";
type_number boolean = Type_number["boolean"] = Next_type_number++;
Type[boolean].name = "boolean";
type_number character = Type_number["character"] = Next_type_number++;
Type[character].name = "character";
// Array types are a special modifier to any other type. For example,
// array:integer or array:address:boolean.
type_number array = Type_number["array"] = Next_type_number++;
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;
size_t size; // only if type is not primitive; primitives and addresses have size 1 (except arrays are dynamic)
vector<vector<type_number> > 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_number.clear();
Recipe_number["idle"] = IDLE;
// Primitive Recipe Numbers
Recipe_number["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 < 100); // level 0 is primitives; until 99
Next_recipe_number = 100;
// End Load Recipes
:(before "End Test Run Initialization")
assert(Next_recipe_number < 1000); // functions being tested didn't overflow into test space
:(before "End Setup")
Next_recipe_number = 1000; // consistent new numbers for each test
//:: Helpers
:(code)
instruction::instruction() :is_label(false), operation(IDLE) {}
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) :value(0), initialized(false) {
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[0].first;
for (index_t i = 0; i < properties[0].second.size(); ++i) {
types.push_back(Type_number[properties[0].second[i]]);
}
if (name == "_" && types.empty()) {
types.push_back(0);
properties[0].second.push_back("dummy");
}
}
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 << "\", value: " << value << ", type: ";
for (index_t i = 0; i < types.size(); ++i) {
out << types[i];
if (i < types.size()-1) out << "-";
}
if (!properties.empty()) {
out << ", properties: [";
for (index_t i = 0; i < properties.size(); ++i) {
out << "\"" << properties[i].first << "\": ";
for (index_t j = 0; j < properties[i].second.size(); ++j) {
out << "\"" << properties[i].second[j] << "\"";
if (j < properties[i].second.size()-1) out << ":";
}
if (i < properties.size()-1) out << ", ";
else out << "]";
}
}
out << "}";
return out.str();
}
string instruction::to_string() const {
if (is_label) return label;
ostringstream out;
for (index_t i = 0; i < products.size(); ++i) {
if (i > 0) out << ", ";
out << products[i].to_string();
}
if (!products.empty()) out << " <- ";
out << name << '/' << operation << ' ';
for (index_t i = 0; i < ingredients.size(); ++i) {
if (i > 0) out << ", ";
out << ingredients[i].to_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();
}
void dump_memory() {
map<int, int> ordered(Memory.begin(), Memory.end());
for (map<int, int>::iterator p = ordered.begin(); p != ordered.end(); ++p) {
cout << p->first << ": " << p->second << '\n';
}
}
:(before "End Includes")
#include <map>
using std::map;