about summary refs log tree commit diff stats
path: root/apps/hex
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2019-09-23 09:21:40 -0700
committerKartik Agaram <vc@akkartik.com>2019-09-23 09:21:40 -0700
commit5ef9597631302f6288e5e26d52fde957bfebd237 (patch)
tree886aeb1783a15553f15ec8b8aad193d3c656e6c2 /apps/hex
parent31bbb6ac955a9043777c8f7c1926184d622a9626 (diff)
downloadmu-5ef9597631302f6288e5e26d52fde957bfebd237.tar.gz
5687
Move stack operations to a layer of their own.

It was some short-term pain to take out the syntax sugar from it, but we
need access to this layer from braces, which can't depend on sugar since
it's part of sugar. Just simpler to keep one clear line and not have to
build sometimes with some sugar but not others.
Diffstat (limited to 'apps/hex')
-rwxr-xr-xapps/hexbin44119 -> 45319 bytes
1 files changed, 0 insertions, 0 deletions
diff --git a/apps/hex b/apps/hex
index 172bf918..eade5fa7 100755
--- a/apps/hex
+++ b/apps/hex
Binary files differ
0).original_string << "'\n" << end(); break; } if (!is_literal_text(inst.ingredients.at(1))) { raise << maybe(get(Recipe, r).name) << "second ingredient of 'screen-should-contain-in-color' should be a literal string, but got '" << inst.ingredients.at(1).original_string << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") case SCREEN_SHOULD_CONTAIN_IN_COLOR: { if (!Passed) break; assert(scalar(ingredients.at(0))); assert(scalar(ingredients.at(1))); check_screen(current_instruction().ingredients.at(1).name, ingredients.at(0).at(0)); break; } :(before "End Types") // scan an array of characters in a unicode-aware, bounds-checked manner struct raw_string_stream { int index; const int max; const char* buf; raw_string_stream(const string&); uint32_t get(); // unicode codepoint uint32_t peek(); // unicode codepoint bool at_end() const; void skip_whitespace_and_comments(); }; :(code) void check_screen(const string& expected_contents, const int color) { int screen_location = get_or_insert(Memory, SCREEN)+/*skip refcount*/1; int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", ""); assert(data_offset >= 0); int screen_data_location = screen_location+data_offset; // type: address:array:character int screen_data_start = get_or_insert(Memory, screen_data_location) + /*skip refcount*/1; // type: array:character int width_offset = find_element_name(get(Type_ordinal, "screen"), "num-columns", ""); int screen_width = get_or_insert(Memory, screen_location+width_offset); int height_offset = find_element_name(get(Type_ordinal, "screen"), "num-rows", ""); int screen_height = get_or_insert(Memory, screen_location+height_offset); raw_string_stream cursor(expected_contents); // todo: too-long expected_contents should fail int top_index_offset = find_element_name(get(Type_ordinal, "screen"), "top-idx", ""); int top_index = get_or_insert(Memory, screen_location+top_index_offset); for (int i=0, row=top_index/screen_width; i < screen_height; ++i, row=(row+1)%screen_height) { cursor.skip_whitespace_and_comments(); if (cursor.at_end()) break; if (cursor.get() != '.') { raise << maybe(current_recipe_name()) << "each row of the expected screen should start with a '.'\n" << end(); if (!Scenario_testing_scenario) Passed = false; return; } int addr = screen_data_start+/*length*/1+row*screen_width* /*size of screen-cell*/2; for (int column = 0; column < screen_width; ++column, addr+= /*size of screen-cell*/2) { const int cell_color_offset = 1; uint32_t curr = cursor.get(); if (get_or_insert(Memory, addr) == 0 && isspace(curr)) continue; if (curr == ' ' && color != -1 && color != get_or_insert(Memory, addr+cell_color_offset)) { // filter out other colors continue; } if (get_or_insert(Memory, addr) != 0 && get_or_insert(Memory, addr) == curr) { if (color == -1 || color == get_or_insert(Memory, addr+cell_color_offset)) continue; // contents match but color is off if (!Hide_errors) cerr << '\n'; raise << "F - " << maybe(current_recipe_name()) << "expected screen location (" << row << ", " << column << ") to contain '" << unicode_character_at(addr) << "' in color " << color << " instead of " << no_scientific(get_or_insert(Memory, addr+cell_color_offset)) << "\n" << end(); if (!Hide_errors) dump_screen(); if (!Scenario_testing_scenario) Passed = false; return; } // really a mismatch // can't print multi-byte unicode characters in errors just yet. not very useful for debugging anyway. char expected_pretty[10] = {0}; if (curr < 256 && !iscntrl(curr)) { // " ('')" expected_pretty[0] = ' ', expected_pretty[1] = '(', expected_pretty[2] = '\'', expected_pretty[3] = static_cast(curr), expected_pretty[4] = '\'', expected_pretty[5] = ')', expected_pretty[6] = '\0'; } char actual_pretty[10] = {0}; if (get_or_insert(Memory, addr) < 256 && !iscntrl(get_or_insert(Memory, addr))) { // " ('')" actual_pretty[0] = ' ', actual_pretty[1] = '(', actual_pretty[2] = '\'', actual_pretty[3] = static_cast(get_or_insert(Memory, addr)), actual_pretty[4] = '\'', actual_pretty[5] = ')', actual_pretty[6] = '\0'; } ostringstream color_phrase; if (color != -1) color_phrase << " in color " << color; if (!Hide_errors) cerr << '\n'; raise << "F - " << maybe(current_recipe_name()) << "expected screen location (" << row << ", " << column << ") to contain " << curr << expected_pretty << color_phrase.str() << " instead of " << no_scientific(get_or_insert(Memory, addr)) << actual_pretty << '\n' << end(); if (!Hide_errors) dump_screen(); if (!Scenario_testing_scenario) Passed = false; return; } if (cursor.get() != '.') { raise << maybe(current_recipe_name()) << "row " << row << " of the expected screen is too long\n" << end(); if (!Scenario_testing_scenario) Passed = false; return; } } cursor.skip_whitespace_and_comments(); if (!cursor.at_end()) { raise << maybe(current_recipe_name()) << "expected screen has too many rows\n" << end(); Passed = false; } } const char* unicode_character_at(int addr) { int unicode_code_point = static_cast(get_or_insert(Memory, addr)); return to_unicode(unicode_code_point); } raw_string_stream::raw_string_stream(const string& backing) :index(0), max(SIZE(backing)), buf(backing.c_str()) {} bool raw_string_stream::at_end() const { if (index >= max) return true; if (tb_utf8_char_length(buf[index]) > max-index) { raise << "unicode string seems corrupted at index "<< index << " character " << static_cast(buf[index]) << '\n' << end(); return true; } return false; } uint32_t raw_string_stream::get() { assert(index < max); // caller must check bounds before calling 'get' uint32_t result = 0; int length = tb_utf8_char_to_unicode(&result, &buf[index]); assert(length != TB_EOF); index += length; return result; } uint32_t raw_string_stream::peek() { assert(index < max); // caller must check bounds before calling 'get' uint32_t result = 0; int length = tb_utf8_char_to_unicode(&result, &buf[index]); assert(length != TB_EOF); return result; } void raw_string_stream::skip_whitespace_and_comments() { while (!at_end()) { if (isspace(peek())) get(); else if (peek() == '#') { // skip comment get(); while (peek() != '\n') get(); // implicitly also handles CRLF } else break; } } :(before "End Primitive Recipe Declarations") _DUMP_SCREEN, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$dump-screen", _DUMP_SCREEN); :(before "End Primitive Recipe Checks") case _DUMP_SCREEN: { break; } :(before "End Primitive Recipe Implementations") case _DUMP_SCREEN: { dump_screen(); break; } :(code) void dump_screen() { int screen_location = get_or_insert(Memory, SCREEN) + /*skip refcount*/1; int width_offset = find_element_name(get(Type_ordinal, "screen"), "num-columns", ""); int screen_width = get_or_insert(Memory, screen_location+width_offset); int height_offset = find_element_name(get(Type_ordinal, "screen"), "num-rows", ""); int screen_height = get_or_insert(Memory, screen_location+height_offset); int data_offset = find_element_name(get(Type_ordinal, "screen"), "data", ""); assert(data_offset >= 0); int screen_data_location = screen_location+data_offset; // type: address:array:character int screen_data_start = get_or_insert(Memory, screen_data_location) + /*skip refcount*/1; // type: array:character assert(get_or_insert(Memory, screen_data_start) == screen_width*screen_height); int top_index_offset = find_element_name(get(Type_ordinal, "screen"), "top-idx", ""); int top_index = get_or_insert(Memory, screen_location+top_index_offset); for (int i=0, row=top_index/screen_width; i < screen_height; ++i, row=(row+1)%screen_height) { cerr << '.'; int curr = screen_data_start+/*length*/1+row*screen_width* /*size of screen-cell*/2; for (int col = 0; col < screen_width; ++col) { if (get_or_insert(Memory, curr)) cerr << to_unicode(static_cast(get_or_insert(Memory, curr))); else cerr << ' '; curr += /*size of screen-cell*/2; } cerr << ".\n"; } }