about summary refs log blame commit diff stats
path: root/cpp/002main.cc
blob: c6b721047ceb586a72b3e2b8140ce6ed829b2190 (plain) (tree)






















































































                                                                













                                                                          
                         

  
                                               
                                           

                         
                               




                                             


                                



                                                                                
                                                                                       
                     
   

  

                   
                    




                                                    
                                                    
                                                                                                        



                           
  
 



                                                   











                                


                                     

                                                            

 
                      


                                         



                                                           
                           

                         
 



                                                                                           

                                     
                                                


                                                            








                                                               


                                       


                                                       




















                                                                                     







                                                        



                                                              
                              










                                                  
                            


                                                   







                                                                                                    
                   



                               
                                                    
                      
                                                    
                      
                                                    





                                            




                         

                                
                                 








                                    

                                                   
             
   

 










                                 











                                             


























                                                                    

                 
                  










                                                       















                                               
//? enum recipe_number {
//?   // arithmetic
//?   add = 1,
//?   subtract,
//?   multiply,
//?   divide,
//?   divide_with_remainder,
//? 
//?   // boolean
//?   conjunction,  // 'and' is a keyword
//?   disjunction,  // 'or' is a keyword
//?   negation,  // 'not' is a keyword
//? 
//?   // comparison
//?   equal,
//?   not_equal,
//?   less_than,
//?   greater_than,
//?   lesser_or_equal,
//?   greater_or_equal,
//? 
//?   // control flow
//?   jump,
//?   jump_if,
//?   jump_unless,
//? 
//?   // data management: scalars, arrays, and_records (structs)
//?   copy,
//?   get,
//?   get_address,
//?   index,
//?   index_address,
//?   allocate,
//?   size,
//?   length,
//? 
//?   // tagged_values require one primitive
//?   save_type,
//? 
//?   // code points for characters
//?   character_to_integer,
//?   integer_to_character,
//? 
//?   // multiprocessing
//?   fork,
//?   fork_helper,
//?   sleep,
//?   assert,
//?   assert_false,
//? 
//?   // cursor-based (text mode) interaction
//?   cursor_mode,
//?   retro_mode,
//?   clear_host_screen,
//?   clear_line_on_host,
//?   cursor_on_host,
//?   cursor_on_host_to_next_line,
//?   cursor_up_on_host,
//?   cursor_down_on_host,
//?   cursor_right_on_host,
//?   cursor_left_on_host,
//?   print_character_to_host,
//?   read_key_from_host,
//? 
//?   // debugging aides
//?   _dump_memory,
//?   _dump_trace,
//?   _start_tracing,
//?   _stop_tracing,
//?   _dump_routine,
//?   _dump_channel,
//?   _quit,
//?   _wait_for_key_from_host,
//?   _print,
//? 
//?   // first-class continuations
//?   current_continuation,
//?   continue_from,
//? 
//?   // user-defined functions
//?   next_input,
//?   input,
//?   prepare_reply,
//?   reply,
//? 
//?   Max_primitive_recipe,
//? };

struct property {
  vector<string> values;
};

typedef int type_number;

struct type_info {
  int size;
  bool is_address;
  bool is_record;
  bool is_array;
  vector<type_number> target;  // only if is_address
  vector<vector<type_number> > elements;  // only if is_record or is_array
  type_info() :size(0) {}
};

unordered_map<string, type_number> Type_number;
unordered_map<type_number, type_info> Type;
int Next_type_number = 1;

unordered_map<int, int> Memory;

struct reagent {
  string name;
  vector<type_number> types;
  vector<pair<string, property> > properties;
  reagent(string s) {
    istringstream in(s);
    name = slurp_until(in, ':');
    types.push_back(Type_number[slurp_until(in, '/')]);  // todo: multiple types
  }
  string to_string() {
    ostringstream out;
    out << "{name: \"" << name << "\", type: " << types[0] << "}";  // todo: properties
    return out.str();
  }
};

const int idle = 0;

struct instruction {
  bool is_label;
  string label;  // only if is_label
  recipe_number operation;  // only if !is_label
  vector<reagent> ingredients;  // only if !is_label
  vector<reagent> products;  // only if !is_label
  instruction() :is_label(false), operation(idle) {}
  void clear() { is_label=false; label.clear(); operation=idle; ingredients.clear(); products.clear(); }
};

struct recipe {
  vector<instruction> step;
};

typedef int recipe_number;
unordered_map<string, recipe_number> Recipe_number;
unordered_map<recipe_number, recipe> Recipe;
int Next_recipe_number = 1;

void load(string filename) {
}

void run(string function_name) {
}

void setup_memory() {
  Memory.clear();
}

void setup_types() {
  Type.clear();  Type_number.clear();
  Type_number["literal"] = 0;
  Next_type_number = 1;
  int integer = Type_number["integer"] = Next_type_number++;
  Type[integer].size = 1;
}

void setup_recipes() {
  Recipe.clear();  Recipe_number.clear();
  Recipe_number["idle"] = 0;
  Next_recipe_number = 1;
  Recipe_number["copy"] = Next_recipe_number++;
//?   dbg << "AAA " << Recipe_number["copy"] << '\n'; //? 1
}

void compile(string form) {
  istringstream in(form);
  in >> std::noskipws;

  string _recipe = next_word(in);
//?   cout << _recipe << '\n'; //? 1
  if (_recipe != "recipe")
    raise << "top-level forms must be of the form 'recipe _name_ [ _instruction_ ... ]'\n";

  string recipe_name = next_word(in);
//?   cout << '^' << recipe_name << "$\n"; //? 1
  if (recipe_name.empty())
    raise << "empty recipe name in " << form << '\n';
  int r = Recipe_number[recipe_name] = Next_recipe_number++;

//?   string foo = next_word(in); //? 1
//?   cout << '^' << foo << "$ (" << foo.size() << ")\n"; //? 1
  if (next_word(in) != "[")
    raise << "recipe body must begin with '['\n";

  skip_newlines(in);

  instruction curr;
  while (next_instruction(in, &curr)) {
    Recipe[r].step.push_back(curr);
  }
}

bool next_instruction(istream& in, instruction* curr) {
  curr->clear();
  if (in.eof()) return false;
  skip_whitespace(in);  if (in.eof()) return false;
  skip_newlines(in);  if (in.eof()) return false;

//?   vector<string> ingredients, products; //? 1
  vector<string> words;
  while (in.peek() != '\n') {
    skip_whitespace(in);  if (in.eof()) return false;
    string word = next_word(in);  if (in.eof()) return false;
    words.push_back(word);
    skip_whitespace(in);  if (in.eof()) return false;
  }
  skip_newlines(in);  if (in.eof()) return false;
//?   cout << "words: "; //? 1
//?   for (vector<string>::iterator p = words.begin(); p != words.end(); ++p) { //? 1
//?     cout << *p << "; "; //? 1
//?   } //? 1
//?   cout << '\n'; //? 1
//?   return true; //? 1

  if (words.size() == 1 && *(words[0].end()-1) == ':') {
    curr->is_label = true;
    words[0].erase(words[0].end()-1);
    curr->label = words[0];
    trace("parse") << "label: " << curr->label;
    return !in.eof();
  }

  vector<string>::iterator p = words.begin();
  if (find(words.begin(), words.end(), "<-") != words.end()) {
//?     cout << "instruction yields products\n"; //? 1
    for (; *p != "<-"; ++p) {
      if (*p == ",") continue;
//?       cout << "product: " << *p << '\n'; //? 1
//?       products.push_back(*p); //? 1
      curr->products.push_back(reagent(*p));
    }
    ++p;  // skip <-
  }
//?   return true; //? 1

  curr->operation = Recipe_number[*p];  ++p;

  for (; p != words.end(); ++p) {
    if (*p == ",") continue;
//?     cout << "ingredient: " << *p << '\n'; //? 1
    curr->ingredients.push_back(reagent(*p));
  }

  trace("parse") << "instruction: " << curr->operation;
  for (vector<reagent>::iterator p = curr->ingredients.begin(); p != curr->ingredients.end(); ++p) {
    trace("parse") << "  ingredient: " << p->to_string();
  }
  for (vector<reagent>::iterator p = curr->products.begin(); p != curr->products.end(); ++p) {
    trace("parse") << "  product: " << p->to_string();
  }
  return !in.eof();
}

string next_word(istream& in) {
  ostringstream out;
//?   cout << "1: " << (int)in.peek() << '\n'; //? 1
  skip_whitespace(in);
//?   cout << "2: " << (int)in.peek() << '\n'; //? 1
  slurp_word(in, out);
//?   cout << "3: " << (int)in.peek() << '\n'; //? 1
//?   cout << out.str() << '\n'; //? 1
  return out.str();
}

void slurp_word(istream& in, ostream& out) {
  char c;
  if (in.peek() == ',') {
    in >> c;
    out << c;
    return;
  }
  while (in >> c) {
//?     cout << c << '\n'; //? 1
    if (isspace(c) || c == ',') {
//?       cout << "  space\n"; //? 1
      in.putback(c);
      break;
    }
    out << c;
  }
}

void skip_whitespace(istream& in) {
  while (isspace(in.peek()) && in.peek() != '\n') {
//?     cout << "skip\n"; //? 1
    in.get();
  }
}

void skip_newlines(istream& in) {
  while (in.peek() == '\n')
    in.get();
}

void skip_comma(istream& in) {
  skip_whitespace(in);
  if (in.peek() == ',') in.get();
  skip_whitespace(in);
}

string slurp_until(istream& in, char delim) {
  ostringstream out;
  char c;
  while (in >> c) {
    if (c == delim) {
      break;
    }
    out << c;
  }
  return out.str();
}



//// test harness

void run_tests() {
  for (unsigned long i=0; i < sizeof(Tests)/sizeof(Tests[0]); ++i) {
    START_TRACING_UNTIL_END_OF_SCOPE;
    setup();
    CLEAR_TRACE;
    (*Tests[i])();
    verify();
  }
  cerr << '\n';
  if (Num_failures > 0)
    cerr << Num_failures << " failure"
         << (Num_failures > 1 ? "s" : "")
         << '\n';
}

void verify() {
  if (!Passed)
    ;
  else
    cerr << ".";
}

void setup() {
  setup_memory();
  setup_types();
  setup_recipes();
  Passed = true;
}

string time_string() {
  time_t t;
  time(&t);
  char buffer[10];
  if (!strftime(buffer, 10, "%H:%M:%S", localtime(&t)))
    return "";
  return buffer;
}

}  // end namespace mu

int main(int argc, const char* argv[]) {
  if (argc == 2 && string(argv[1]) == "test") {
    mu::run_tests();
    return 0;
  }

  for (int i = 1; i < argc; ++i) {
    mu::load(argv[i]);
  }
  mu::run("main");
}

namespace mu {