about summary refs log tree commit diff stats
path: root/shell/global.mu
Commit message (Expand)AuthorAgeFilesLines
* .Kartik K. Agaram2021-06-121-2/+2
* eliminate some implicit writes to real screenKartik K. Agaram2021-06-121-2/+2
* .Kartik K. Agaram2021-06-121-8/+8
* better nameKartik K. Agaram2021-06-111-2/+3
* back to the pending testKartik K. Agaram2021-06-111-60/+4
* .Kartik K. Agaram2021-06-111-3/+25
* .Kartik K. Agaram2021-06-111-1/+0
* .Kartik K. Agaram2021-06-111-2/+2
* .Kartik K. Agaram2021-06-111-82/+6
* .Kartik K. Agaram2021-06-111-2/+2
* .Kartik K. Agaram2021-06-111-4/+0
* .Kartik K. Agaram2021-06-111-54/+50
* .Kartik K. Agaram2021-06-111-11/+13
* start showing parse errors under definitionsKartik K. Agaram2021-06-111-2/+10
* .Kartik K. Agaram2021-06-111-6/+6
* .Kartik K. Agaram2021-06-111-13/+34
* .Kartik K. Agaram2021-06-091-0/+36
* .Kartik K. Agaram2021-06-091-41/+19
* .Kartik K. Agaram2021-06-091-14/+7
* .Kartik K. Agaram2021-06-091-3/+4
* .Kartik K. Agaram2021-06-091-2/+2
* make tests pass againKartik K. Agaram2021-06-091-0/+5
* snapshot: attempt at modifying a function nameKartik K. Agaram2021-06-091-11/+57
* .Kartik K. Agaram2021-06-081-11/+11
* shell: function modal now also creates functionsKartik K. Agaram2021-06-081-0/+19
* shell: fleshing out the 'standard library'Kartik K. Agaram2021-06-061-1/+1
* refresh edited definitions on ctrl-sKartik K. Agaram2021-06-051-0/+41
* start editing function definitionsKartik K. Agaram2021-06-041-1/+11
* .Kartik K. Agaram2021-06-041-0/+24
* select function to render firstKartik K. Agaram2021-06-041-0/+10
* always render functions starting at the cursorKartik K. Agaram2021-06-041-2/+4
* record the definition the cursor is currently atKartik K. Agaram2021-06-041-1/+10
* conditionally display cursor on function sideKartik K. Agaram2021-06-041-3/+4
* .Kartik K. Agaram2021-06-041-1/+1
* rename the definition primitive to 'def'Kartik K. Agaram2021-06-041-4/+4
* .Kartik K. Agaram2021-06-031-0/+3
* starting to support function editingKartik K. Agaram2021-06-031-0/+3
* .Kartik K. Agaram2021-06-031-1597/+1
* .Kartik K. Agaram2021-06-031-5/+5
* .Kartik Agaram2021-05-311-3/+5
* shell: raise errors when loading code on bootKartik K. Agaram2021-05-301-13/+13
* bugfix: unbound variables were not raising errorKartik K. Agaram2021-05-301-2/+2
* some boot-time heartbeat messagesKartik K. Agaram2021-05-071-1/+11
* clean up Bresenham line-drawingKartik K. Agaram2021-05-071-0/+32
* .Kartik K. Agaram2021-05-071-6/+6
* starting to implement first macrosKartik K. Agaram2021-05-071-0/+6
* more paranoia in shell/globals.muKartik K. Agaram2021-05-061-0/+48
* shell: macroexpand outermost callKartik K. Agaram2021-05-061-0/+22
* cleaner rendering of fake screens and keyboardsKartik K. Agaram2021-05-011-1/+1
* .Kartik K. Agaram2021-05-011-1/+1
span class="n">assert(has_data(in)); assert(in.peek() == '['); out << static_cast<char>(in.get()); // slurp the '[' if (is_code_string(in, out)) slurp_quoted_comment_aware(in, out); else slurp_quoted_comment_oblivious(in, out); return out.str(); } // A string is a code string (ignores comments when scanning for matching // brackets) if it contains a newline at the start before any non-whitespace. bool is_code_string(istream& in, ostream& out) { while (has_data(in)) { char c = in.get(); if (!isspace(c)) { in.putback(c); return false; } out << c; if (c == '\n') { return true; } } return false; } // Read a regular string. Regular strings can only contain other regular // strings. void slurp_quoted_comment_oblivious(istream& in, ostream& out) { int brace_depth = 1; while (has_data(in)) { char c = in.get(); if (c == '\\') { slurp_one_past_backslashes(in, out); continue; } out << c; if (c == '[') ++brace_depth; if (c == ']') --brace_depth; if (brace_depth == 0) break; } if (!has_data(in) && brace_depth > 0) { raise << "unbalanced '['\n" << end(); out.clear(); } } // Read a code string. Code strings can contain either code or regular strings. void slurp_quoted_comment_aware(istream& in, ostream& out) { char c; while (in >> c) { if (c == '\\') { slurp_one_past_backslashes(in, out); continue; } if (c == '#') { out << c; while (has_data(in) && in.peek() != '\n') out << static_cast<char>(in.get()); continue; } if (c == '[') { in.putback(c); // recurse out << slurp_quoted(in); continue; } out << c; if (c == ']') return; } raise << "unbalanced '['\n" << end(); out.clear(); } :(after "Parsing reagent(string s)") if (starts_with(s, "[")) { if (*s.rbegin() != ']') return; // unbalanced bracket; handled elsewhere name = s; // delete [] delimiters name.erase(0, 1); strip_last(name); type = new type_tree("literal-string", 0); return; } //: Unlike other reagents, escape newlines in literal strings to make them //: more friendly to trace(). :(after "string to_string(const reagent& r)") if (is_literal_text(r)) return emit_literal_string(r.name); :(code) bool is_literal_text(const reagent& x) { return x.type && x.type->name == "literal-string"; } string emit_literal_string(string name) { size_t pos = 0; while (pos != string::npos) pos = replace(name, "\n", "\\n", pos); return "{\""+name+"\": \"literal-string\"}"; } size_t replace(string& str, const string& from, const string& to, size_t n) { size_t result = str.find(from, n); if (result != string::npos) str.replace(result, from.length(), to); return result; } void strip_last(string& s) { if (!s.empty()) s.erase(SIZE(s)-1); } void slurp_one_past_backslashes(istream& in, ostream& out) { // When you encounter a backslash, strip it out and pass through any // following run of backslashes. If we 'escaped' a single following // character, then the character '\' would be: // '\\' escaped once // '\\\\' escaped twice // '\\\\\\\\' escaped thrice (8 backslashes) // ..and so on. With our approach it'll be: // '\\' escaped once // '\\\' escaped twice // '\\\\' escaped thrice // This only works as long as backslashes aren't also overloaded to create // special characters. So Mu doesn't follow C's approach of overloading // backslashes both to escape quote characters and also as a notation for // unprintable characters like '\n'. while (has_data(in)) { char c = in.get(); out << c; if (c != '\\') break; } } :(scenario string_literal_nested) def main [ 1:address:array:character <- copy [abc [def]] ] +parse: ingredient: {"abc [def]": "literal-string"} :(scenario string_literal_escaped) def main [ 1:address:array:character <- copy [abc \[def] ] +parse: ingredient: {"abc [def": "literal-string"} :(scenario string_literal_escaped_twice) def main [ 1:address:array:character <- copy [ abc \\[def] ] +parse: ingredient: {"\nabc \[def": "literal-string"} :(scenario string_literal_and_comment) def main [ 1:address:array:character <- copy [abc] # comment ] +parse: --- defining main +parse: instruction: copy +parse: number of ingredients: 1 +parse: ingredient: {"abc": "literal-string"} +parse: product: {1: ("address" "array" "character")} :(scenario string_literal_escapes_newlines_in_trace) def main [ copy [abc def] ] +parse: ingredient: {"abc\ndef": "literal-string"} :(scenario string_literal_can_skip_past_comments) def main [ copy [ # ']' inside comment bar ] ] +parse: ingredient: {"\n # ']' inside comment\n bar\n ": "literal-string"} :(scenario string_literal_empty) def main [ copy [] ] +parse: ingredient: {"": "literal-string"} :(scenario multiple_unfinished_recipes) % Hide_errors = true; def f1 [ def f2 [ +error: unbalanced '['