about summary refs log blame commit diff stats
path: root/apps/tile/main.mu
blob: 120913c4bfc1b81f84e3f00e1697719691c45e46 (plain) (tree)
1
2
3
                                                                   

                                                                  






























                                                        
     


                
     
   





                                                                 

 
                

                                


                                                        
   
              
                                                        
                                 

                    

        

                           

 
         


                                                         
            













                                                                  

 
         

            

                                    

                                                            








                                                          
     

                                                  
                 


                                               
     









                                                              


                                                                 



                                                

     

        
 
fn main args-on-stack: (addr array addr array byte) -> _/ebx: int {
  var args/eax: (addr array addr array byte) <- copy args-on-stack
  var len/ecx: int <- length args
  compare len, 2
  {
    break-if-!=
    # if single arg is 'test', run tests
    var tmp/ecx: (addr addr array byte) <- index args, 1
    var tmp2/eax: boolean <- string-equal? *tmp, "test"
    compare tmp2, 0  # false
    {
      break-if-=
      run-tests
      return 0  # TODO: get at Num-test-failures somehow
    }
    # if single arg is 'screen', run in full-screen mode
    tmp2 <- string-equal? *tmp, "screen"
    compare tmp2, 0  # false
    {
      break-if-=
      interactive
      return 0
    }
    # if single arg is 'type', run in typewriter mode
    tmp2 <- string-equal? *tmp, "type"
    compare tmp2, 0  # false
    {
      break-if-=
      repl
      return 0
    }
    # if single arg is 'test' ...
    tmp2 <- string-equal? *tmp, "test2"
    compare tmp2, 0  # false
    {
      break-if-=
      test
      return 0
    }
  }
  # otherwise error message
  print-string-to-real-screen "usage:\n"
  print-string-to-real-screen "  to run tests: tile test\n"
  print-string-to-real-screen "  full-screen mode: tile screen\n"
  print-string-to-real-screen "  regular REPL: tile type\n"
  return 1
}

fn interactive {
  enable-screen-grid-mode
  enable-keyboard-immediate-mode
  var env-storage: environment
  var env/esi: (addr environment) <- address env-storage
  initialize-environment env
  {
    render env
    var key/eax: grapheme <- read-key-from-real-keyboard
    compare key, 0x11  # 'ctrl-q'
    break-if-=
    process env, key
    loop
  }
  enable-keyboard-type-mode
  enable-screen-type-mode
}

fn test {
  var env-storage: environment
  var env/esi: (addr environment) <- address env-storage
  initialize-environment-with-fake-screen env, 0x20, 0xa0
  render env
}

fn process-all env: (addr environment), cmds: (addr array byte) {
  var cmds-stream: (stream byte 0x100)
  var cmds-stream-a/esi: (addr stream byte) <- address cmds-stream
  write cmds-stream-a, cmds
  {
    var done?/eax: boolean <- stream-empty? cmds-stream-a
    compare done?, 0  # false
    break-if-!=
    var g/eax: grapheme <- read-grapheme cmds-stream-a
    process env, g
    loop
  }
}

fn repl {
  {
    # prompt
    print-string-to-real-screen "> "
    # read
    var line-storage: (stream byte 0x100)
    var line/ecx: (addr stream byte) <- address line-storage
    clear-stream line
    read-line-from-real-keyboard line
    var done?/eax: boolean <- stream-empty? line
    compare done?, 0  # false
    break-if-!=
    # parse
    var env-storage: environment
    var env/esi: (addr environment) <- address env-storage
    initialize-environment env
    {
      var done?/eax: boolean <- stream-empty? line
      compare done?, 0  # false
      break-if-!=
      var g/eax: grapheme <- read-grapheme line
      process env, g
      loop
    }
    # eval
    var stack-storage: value-stack
    var stack/edi: (addr value-stack) <- address stack-storage
    initialize-value-stack stack, 0x10
    evaluate-environment env, stack
    # print
    var empty?/eax: boolean <- value-stack-empty? stack
    {
      compare empty?, 0  # false
      break-if-!=
      var result/xmm0: float <- pop-number-from-value-stack stack
      print-float-decimal-approximate 0, result, 3
      print-string 0, "\n"
      print-string 0, "width: "
      var width/eax: int <- float-size result, 3
      print-int32-decimal 0, width
      print-string 0, "\n"
    }
    #
    loop
  }
}
="n">istringstream; using std::ostringstream; #include<fstream> using std::ifstream; using std::ofstream; #include <locale> using std::isspace; // unicode-aware struct syminfo { string filename; int line_num; syminfo() :line_num(0) {} }; bool has_data(istream& in) { in.peek(); if (in.eof()) return false; assert(in); return true; } bool starts_with(const string& s, const string& pat) { string::const_iterator a=s.begin(), b=pat.begin(); for (/*nada*/; a!=s.end() && b!=pat.end(); ++a, ++b) if (*a != *b) return false; return b == pat.end(); } bool ends_with(const string& s, const string& pat) { string::const_reverse_iterator a=s.rbegin(), b=pat.rbegin(); for (/*nada*/; a!=s.rend() && b!=pat.rend(); ++a, ++b) if (*a != *b) return false; return b == pat.rend(); } void encode_some_html_entities(string& s) { std::string::size_type pos = 0; while (true) { pos = s.find_first_of("<>", pos); if (pos == std::string::npos) break; std::string replacement; switch (s.at(pos)) { case '<': replacement = "&lt;"; break; case '>': replacement = "&gt;"; break; } s.replace(pos, 1, replacement); pos += replacement.size(); }; } void read_tags(const string& filename, map<string, syminfo>& info) { ifstream in(filename.c_str()); //? cerr << "reading " << filename << '\n'; string dummy; while (has_data(in)) { string symbol; in >> symbol; if (symbol == "operator") { // unsupported getline(in, dummy); // skip continue; } encode_some_html_entities(symbol); //? cerr << symbol << '\n'; if (info.find(symbol) != info.end()) { info[symbol].line_num = -1; info[symbol].filename.clear(); } else { in >> dummy; in >> info[symbol].line_num; in >> info[symbol].filename; } getline(in, dummy); // skip rest of line //? cerr << symbol << ": " << info[symbol].filename << ':' << info[symbol].line_num << '\n'; } in.close(); } void replace_tags_in_file(const string& filename, const map<string, syminfo>& info) { //? cerr << info.size() << " symbols\n"; ifstream in(filename.c_str()); ofstream out((filename+".out").c_str()); while (has_data(in)) { // send lines that don't start with '<span' straight through string line; getline(in, line); if (!starts_with(line, "<span ")) { out << line << '\n'; } else { static int span_size = string("</span>").size(); int skip_first_span = line.find("</span>") + span_size; out << line.substr(0, skip_first_span); istringstream in2(line.substr(skip_first_span)); in2 >> std::noskipws; // only in .subx files, refuse to linkify the first word on a line bool at_start_of_line = ends_with(filename, ".subx.html"); //? cerr << filename << ": " << at_start_of_line << '\n'; while (has_data(in2)) { if (isspace(in2.peek())) { //? cerr << "space\n"; char c; in2 >> c; out << c; at_start_of_line = false; } // within a line, send straight through all characters inside '<..>' else if (in2.peek() == '<') { //? cerr << "tag\n"; char c = '\0'; while (in2 >> c) { //? cerr << "span: " << c << '\n'; out << c; if (c == '>') break; } // don't include initial tag when computing 'at_start_of_line' //? cerr << "end tag\n"; } else { // send straight through all characters inside strings (handling escapes) char c = in2.get(); if (c == '"') { //? cerr << "string\n"; out << c; while (in2 >> c) { out << c; if (c == '\\') { in2 >> c; out << c; } else if (c == '"') { break; } } at_start_of_line = false; } else if (c == '\'') { //? cerr << "character\n"; out << c; while (in2 >> c) { out << c; if (c == '\\') { in2 >> c; out << c; } else if (c == '\'') { break; } } at_start_of_line = false; } // send straight through any characters after '#' (comments) else if (c == '#') { //? cerr << "comment\n"; out << c; while (in2 >> c) out << c; at_start_of_line = false; } // send straight through any characters after '//' (comments) else if (c == '/' && in2.peek() == '/') { //? cerr << "comment\n"; out << c; while (in2 >> c) out << c; at_start_of_line = false; } // send through open parens at start of line else if (c == '(') { out << c; at_start_of_line = false; } else if (c == ')') { out << c; at_start_of_line = false; } else { //? cerr << "rest\n"; if (c == ',' || c == ':') { out << c; at_start_of_line = false; continue; } ostringstream out2; out2 << c; while (in2 >> c) { if (isspace(c) || c == '<' || c == '"' || c == '\'' || c == '/' || c == ',' || c == ':' || c == '(' || c == ')') { // keep sync'd with other clauses above in2.putback(c); break; } out2 << c; } string symbol = out2.str(); if (symbol == "equal" || symbol == "index" || symbol == "put-index" || symbol == "length") { //? cerr << " blacklisted\n"; out << symbol; } else if (info.find(symbol) == info.end()) { //? cerr << " no info\n"; out << symbol; } else { const syminfo& s = info.find(symbol)->second; if (s.filename.empty()) { //? cerr << " empty info\n"; out << symbol; } else { if (at_start_of_line) { //? cerr << " at start of line; refusing to linkify " << symbol << "\n"; out << symbol; } else { //? cerr << " link\n"; out << "<a href='" << s.filename << ".html#L" << s.line_num << "'>" << symbol << "</a>"; } } } } // end rest } } // done parsing line out << '\n'; } } in.close(); out.close(); } int main(int argc, const char* argv[]) { map<string, syminfo> info; read_tags(argv[1], info); for (int i = 2; i < argc; ++i) replace_tags_in_file(argv[i], info); return 0; }