|
|
|
@@ -1,4 +1,11 @@ |
|
|
|
proc visualize_lisp_machine() -> void { |
|
|
|
struct Drawn_Area { |
|
|
|
int x; |
|
|
|
int y; |
|
|
|
int width; |
|
|
|
int height; |
|
|
|
}; |
|
|
|
|
|
|
|
fprintf(stderr, "Drawing visualization..."); |
|
|
|
defer { |
|
|
|
fprintf(stderr, "Done!\n"); |
|
|
|
@@ -29,14 +36,20 @@ proc visualize_lisp_machine() -> void { |
|
|
|
write_y = 0; |
|
|
|
|
|
|
|
|
|
|
|
proc draw_margin = [&](int count = 1) { |
|
|
|
proc draw_margin = [&](int count = 1) -> Drawn_Area { |
|
|
|
write_x += margin * count; |
|
|
|
return { |
|
|
|
write_x - margin * count, |
|
|
|
write_y, |
|
|
|
margin * count, |
|
|
|
write_y |
|
|
|
}; |
|
|
|
}; |
|
|
|
proc draw_new_line = [&](int count = 1) { |
|
|
|
write_x = 0; |
|
|
|
write_y += 25 * count; |
|
|
|
}; |
|
|
|
proc draw_text = [&](const char* text, const char* color = "#000000", bool draw_quotes = false, int max_length = 200) { |
|
|
|
proc draw_text = [&](const char* text, const char* color = "#000000", bool draw_quotes = false, int max_length = 200) -> Drawn_Area { |
|
|
|
// take care of escaping sensitive chars |
|
|
|
int text_length = 0; |
|
|
|
int extra_needed_chars = draw_quotes ? 10 : 0; |
|
|
|
@@ -97,50 +110,140 @@ proc visualize_lisp_machine() -> void { |
|
|
|
|
|
|
|
int text_width = 12 * (text_length + (draw_quotes ? 2 : 0)); |
|
|
|
if (write_x + text_width > max_x) max_x = write_x + text_width; |
|
|
|
if (write_y > max_y) max_y = write_y; |
|
|
|
if (write_y + 12 > max_y) max_y = write_y + 12; |
|
|
|
|
|
|
|
const char* quote = draw_quotes ? """ : ""; |
|
|
|
if (extra_needed_chars) { |
|
|
|
fprintf(f, draw_text_template, write_x, write_y, color, quote, new_text, quote); |
|
|
|
fprintf(f, draw_text_template, write_x, write_y+12, color, quote, new_text, quote); |
|
|
|
free(new_text); |
|
|
|
} else { |
|
|
|
fprintf(f, draw_text_template, write_x, write_y, color, quote, text, quote, color); |
|
|
|
fprintf(f, draw_text_template, write_x, write_y+12, color, quote, text, quote, color); |
|
|
|
} |
|
|
|
|
|
|
|
write_x += text_width; |
|
|
|
// write_x += text_width; |
|
|
|
|
|
|
|
return { |
|
|
|
write_x - text_width, |
|
|
|
write_y, |
|
|
|
text_width, |
|
|
|
12 |
|
|
|
}; |
|
|
|
}; |
|
|
|
proc draw_integer = [&](int number) { |
|
|
|
proc draw_integer = [&](int number) -> Drawn_Area { |
|
|
|
int text_width = 12 * ((int)log10(number)+1); |
|
|
|
|
|
|
|
if (write_x + text_width > max_x) max_x = write_x + text_width; |
|
|
|
if (write_y > max_y) max_y = write_y; |
|
|
|
|
|
|
|
fprintf(f, draw_integer_template, write_x, write_y, number); |
|
|
|
fprintf(f, draw_integer_template, write_x, write_y+12, number); |
|
|
|
|
|
|
|
write_x += text_width; |
|
|
|
return { |
|
|
|
write_x, |
|
|
|
write_y, |
|
|
|
text_width, |
|
|
|
12 |
|
|
|
}; |
|
|
|
}; |
|
|
|
proc draw_float = [&](float number) { |
|
|
|
proc draw_float = [&](float number) -> Drawn_Area { |
|
|
|
int text_width = 12 * 12; |
|
|
|
|
|
|
|
if (write_x + text_width > max_x) max_x = write_x + text_width; |
|
|
|
if (write_y > max_y) max_y = write_y; |
|
|
|
|
|
|
|
fprintf(f, draw_float_template, write_x, write_y, number); |
|
|
|
fprintf(f, draw_float_template, write_x, write_y+12, number); |
|
|
|
|
|
|
|
write_x += text_width; |
|
|
|
return { |
|
|
|
write_x, |
|
|
|
write_y, |
|
|
|
text_width, |
|
|
|
12 |
|
|
|
}; |
|
|
|
}; |
|
|
|
std::function<Drawn_Area(Lisp_Object*)> draw_pair; |
|
|
|
proc draw_lisp_object = [&](Lisp_Object* obj) -> Drawn_Area { |
|
|
|
switch (Memory::get_type(obj)) { |
|
|
|
case Lisp_Object_Type::T: return draw_text("t"); |
|
|
|
case Lisp_Object_Type::Nil: return draw_text("()"); |
|
|
|
case Lisp_Object_Type::Pair: return draw_pair(obj); |
|
|
|
case Lisp_Object_Type::Number: return draw_float(obj->value.number); |
|
|
|
case Lisp_Object_Type::Symbol: return draw_text(&obj->value.string->data); |
|
|
|
case Lisp_Object_Type::Keyword: { |
|
|
|
Drawn_Area colon = draw_text(":", "#c61b6e"); |
|
|
|
write_x += colon.width; |
|
|
|
Drawn_Area text = draw_text(&obj->value.identifier->data, "#c61b6e"); |
|
|
|
write_x -= colon.width; |
|
|
|
return { |
|
|
|
colon.x, |
|
|
|
colon.y, |
|
|
|
colon.width + text.width, |
|
|
|
colon.height |
|
|
|
}; |
|
|
|
} |
|
|
|
case Lisp_Object_Type::String: return draw_text(&obj->value.string->data, "#2aa198", true, 20); |
|
|
|
default: return {0}; |
|
|
|
} |
|
|
|
}; |
|
|
|
proc draw_pair = [&](Lisp_Object* pair) { |
|
|
|
draw_pair = [&](Lisp_Object* pair) -> Drawn_Area { |
|
|
|
Drawn_Area ret; |
|
|
|
Drawn_Area child; |
|
|
|
|
|
|
|
ret.x = write_x; |
|
|
|
ret.y = write_y; |
|
|
|
ret.width = 100; |
|
|
|
ret.height = 100; |
|
|
|
|
|
|
|
fprintf(f, |
|
|
|
" <rect x='%d' y='%d' width='100' height='50' stroke-width='3' stroke='black' fill='white'/>" |
|
|
|
" <line x1='%d' y1='%d' x2='%d' y2='%d' stroke-width='3' stroke='black'/>", |
|
|
|
write_x, write_y, write_x+50, write_y, write_x+50, write_y+50); |
|
|
|
|
|
|
|
// arrow to first |
|
|
|
fprintf(f, |
|
|
|
" <line x1='%d' y1='%d' x2='%d' y2='%d' stroke-width='3' stroke='black'/>", |
|
|
|
write_x+25, write_y+25, write_x+25, write_y+100); |
|
|
|
|
|
|
|
write_y += 110; |
|
|
|
child = draw_lisp_object(pair->value.pair.first); |
|
|
|
if (ret.width < child.width) |
|
|
|
ret.width = child.width; |
|
|
|
if (ret.height < child.height) |
|
|
|
ret.height = child.height; |
|
|
|
|
|
|
|
write_y -= 110; |
|
|
|
|
|
|
|
if (pair->value.pair.rest == Memory::nil) { |
|
|
|
fprintf(f, |
|
|
|
" <line x1='%d' y1='%d' x2='%d' y2='%d' stroke-width='3' stroke='black'/>", |
|
|
|
write_x+50, write_y+50, write_x+100, write_y); |
|
|
|
} else { |
|
|
|
// arrow to rest |
|
|
|
int x_offset = 150; |
|
|
|
if (child.width+margin > x_offset) |
|
|
|
x_offset = child.width+margin; |
|
|
|
|
|
|
|
fprintf(f, |
|
|
|
" <line x1='%d' y1='%d' x2='%d' y2='%d' stroke-width='3' stroke='black'/>", |
|
|
|
write_x+75, write_y+25, write_x+75+x_offset, write_y+25); |
|
|
|
|
|
|
|
write_x += x_offset; |
|
|
|
ret.width += 50; |
|
|
|
|
|
|
|
child = draw_lisp_object(pair->value.pair.rest); |
|
|
|
ret.width += child.width; |
|
|
|
if (ret.height < 70 + child.height) |
|
|
|
ret.height = 70 + child.height; |
|
|
|
|
|
|
|
write_x -= x_offset; |
|
|
|
} |
|
|
|
|
|
|
|
fprintf(f, "\n"); |
|
|
|
|
|
|
|
if (max_x < ret.x + ret.width) |
|
|
|
max_x = ret.x + ret.width; |
|
|
|
if (max_y < ret.y + ret.height) |
|
|
|
max_y = ret.y + ret.height; |
|
|
|
|
|
|
|
return ret; |
|
|
|
}; |
|
|
|
proc draw_header = [&]() { |
|
|
|
proc draw_separator = [&]() { |
|
|
|
@@ -160,8 +263,8 @@ proc visualize_lisp_machine() -> void { |
|
|
|
char date[12]; |
|
|
|
snprintf(date, 12, "%02d.%02d.%d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900); |
|
|
|
|
|
|
|
draw_text("Date: "); |
|
|
|
draw_text(date); |
|
|
|
write_x += draw_text("Date: ").width; |
|
|
|
write_x += draw_text(date).width; |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
|
|
|
|
@@ -171,8 +274,8 @@ proc visualize_lisp_machine() -> void { |
|
|
|
char time[12]; |
|
|
|
snprintf(time, 12, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); |
|
|
|
|
|
|
|
draw_text("Time: "); |
|
|
|
draw_text(time); |
|
|
|
write_x += draw_text("Time: ").width; |
|
|
|
write_x += draw_text(time).width; |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
|
|
|
|
@@ -187,22 +290,22 @@ proc visualize_lisp_machine() -> void { |
|
|
|
} |
|
|
|
int used_string_memory = Memory::string_memory_size - free_string_memory; |
|
|
|
|
|
|
|
draw_text("String Memory:"); |
|
|
|
write_x += draw_text("String Memory:").width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[allocated chars] "); |
|
|
|
draw_integer(Memory::string_memory_size); |
|
|
|
write_x += draw_text("[allocated chars] ").width; |
|
|
|
write_x += draw_integer(Memory::string_memory_size).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[free] "); |
|
|
|
draw_integer(free_string_memory); |
|
|
|
write_x += draw_text("[free] ").width; |
|
|
|
write_x += draw_integer(free_string_memory).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[used] "); |
|
|
|
draw_integer(used_string_memory); |
|
|
|
write_x += draw_text("[used] ").width; |
|
|
|
write_x += draw_integer(used_string_memory).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%free] "); |
|
|
|
draw_float(100.0f * free_string_memory / Memory::string_memory_size); |
|
|
|
write_x += draw_text("[%free] ").width; |
|
|
|
write_x += draw_float(100.0f * free_string_memory / Memory::string_memory_size).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%used] "); |
|
|
|
draw_float(100.0f * used_string_memory / Memory::string_memory_size); |
|
|
|
write_x += draw_text("[%used] ").width; |
|
|
|
write_x += draw_float(100.0f * used_string_memory / Memory::string_memory_size).width; |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
draw_new_line(); |
|
|
|
@@ -214,22 +317,22 @@ proc visualize_lisp_machine() -> void { |
|
|
|
int free_object_memory_cells = Memory::object_memory_size - (Memory::next_index_in_object_memory - Memory::free_spots_in_object_memory->next_index); |
|
|
|
int used_object_memory_cells = Memory::next_index_in_object_memory - Memory::free_spots_in_object_memory->next_index; |
|
|
|
|
|
|
|
draw_text("Object Memory:"); |
|
|
|
write_x += draw_text("Object Memory:").width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[#allocated] "); |
|
|
|
draw_integer(Memory::object_memory_size); |
|
|
|
write_x += draw_text("[#allocated] ").width; |
|
|
|
write_x += draw_integer(Memory::object_memory_size).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[#free] "); |
|
|
|
draw_integer(free_object_memory_cells); |
|
|
|
write_x += draw_text("[#free] ").width; |
|
|
|
write_x += draw_integer(free_object_memory_cells).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[#used] "); |
|
|
|
draw_integer(used_object_memory_cells); |
|
|
|
write_x += draw_text("[#used] ").width; |
|
|
|
write_x += draw_integer(used_object_memory_cells).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%free] "); |
|
|
|
draw_float(100.0f * free_object_memory_cells / Memory::object_memory_size); |
|
|
|
write_x += draw_text("[%free] ").width; |
|
|
|
write_x += draw_float(100.0f * free_object_memory_cells / Memory::object_memory_size).width; |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%used] "); |
|
|
|
draw_float(100.0f * used_object_memory_cells / Memory::object_memory_size); |
|
|
|
write_x += draw_text("[%used] ").width; |
|
|
|
write_x += draw_float(100.0f * used_object_memory_cells / Memory::object_memory_size).width; |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
|
|
|
|
@@ -241,6 +344,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
Lisp_Object_Array_List* numbers = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* strings = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* pairs = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* lists = create_Lisp_Object_array_list(); |
|
|
|
|
|
|
|
// loop over all used memory |
|
|
|
for (int i = 0; i < Memory::next_index_in_object_memory; ++i) { |
|
|
|
@@ -262,13 +366,43 @@ proc visualize_lisp_machine() -> void { |
|
|
|
} |
|
|
|
|
|
|
|
// create the lists-list by filtering the pairs-list. |
|
|
|
Lisp_Oject_Array_List* pairs_to_filter = create_Int_array_list(); |
|
|
|
Lisp_Object_Array_List* pairs_to_filter = create_Lisp_Object_array_list(); |
|
|
|
Int_Array_List* indices_to_filter = create_Int_array_list(); |
|
|
|
|
|
|
|
// helper lambda: |
|
|
|
proc remove_doubles_from_lisp_object_array_list = [&](Lisp_Object_Array_List* list) -> void { |
|
|
|
if (list->next_index == 0) |
|
|
|
return; |
|
|
|
|
|
|
|
sort_array_list(list); |
|
|
|
Int_Array_List* indices_to_filter = create_Int_array_list(); |
|
|
|
|
|
|
|
size_t last = (size_t)list->data[0]; |
|
|
|
for (int i = 1; i < list->next_index; ++i) { |
|
|
|
if ((size_t)list->data[i] == last) |
|
|
|
append_to_array_list(indices_to_filter, i); |
|
|
|
else |
|
|
|
last = (size_t)list->data[i]; |
|
|
|
} |
|
|
|
|
|
|
|
for (int i = indices_to_filter->next_index; i >= 0; --i) { |
|
|
|
remove_index_from_array_list(list, indices_to_filter->data[i]); |
|
|
|
} |
|
|
|
|
|
|
|
// sort again as removing items destroys the order |
|
|
|
sort_array_list(list); |
|
|
|
}; |
|
|
|
|
|
|
|
// recursive lambda |
|
|
|
std::function<void(Lisp_Object*)> filter_pair_and_children; |
|
|
|
filter_pair_and_children = [&](Lisp_Object* pair) { |
|
|
|
|
|
|
|
append_to_array_list(pairs_to_filter, pair); |
|
|
|
|
|
|
|
if (Memory::get_type(pair->value.pair.first) == Lisp_Object_Type::Pair) |
|
|
|
filter_pair_and_children(pair->value.pair.first); |
|
|
|
|
|
|
|
if (Memory::get_type(pair->value.pair.rest) == Lisp_Object_Type::Pair) |
|
|
|
filter_pair_and_children(pair->value.pair.rest); |
|
|
|
}; |
|
|
|
for (int i = 0; i < pairs->next_index; ++i) { |
|
|
|
if (Memory::get_type(pairs->data[i]->value.pair.first) == Lisp_Object_Type::Pair) |
|
|
|
@@ -279,6 +413,15 @@ proc visualize_lisp_machine() -> void { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
remove_doubles_from_lisp_object_array_list(pairs_to_filter); |
|
|
|
fprintf(stderr, "removing %d pairs\n", pairs_to_filter->next_index); |
|
|
|
// okay, so pairs_to_filter now only the pairs once each that |
|
|
|
// we want to filter from the pairs list |
|
|
|
for (int i = 0; i < pairs->next_index; ++i) { |
|
|
|
if (sorted_array_list_find(pairs_to_filter, pairs->data[i]) == -1) { |
|
|
|
append_to_array_list(lists, pairs->data[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
draw_text("Memory Contents:"); |
|
|
|
draw_new_line(); |
|
|
|
@@ -287,7 +430,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
int start_x = write_x, |
|
|
|
start_y = write_y; |
|
|
|
|
|
|
|
draw_text("Symbols: "); |
|
|
|
write_x += draw_text("Symbols: ").width; |
|
|
|
draw_integer(symbols->next_index); |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x; |
|
|
|
@@ -303,7 +446,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
write_x = start_x + 300; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Keywords: "); |
|
|
|
write_x += draw_text("Keywords: ").width; |
|
|
|
draw_integer(keywords->next_index); |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x + 300; |
|
|
|
@@ -312,8 +455,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x + 300; |
|
|
|
|
|
|
|
draw_text(":", "#c61b6e"); |
|
|
|
draw_text(&keywords->data[i]->value.identifier->data, "#c61b6e"); |
|
|
|
draw_lisp_object(keywords->data[i]); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@@ -321,7 +463,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
write_x = start_x + 600; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Numbers: "); |
|
|
|
write_x += draw_text("Numbers: ").width; |
|
|
|
draw_integer(numbers->next_index); |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x + 600; |
|
|
|
@@ -336,7 +478,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
write_x = start_x + 900; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Strings: "); |
|
|
|
write_x += draw_text("Strings: ").width; |
|
|
|
draw_integer(strings->next_index); |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x + 900; |
|
|
|
@@ -352,16 +494,18 @@ proc visualize_lisp_machine() -> void { |
|
|
|
write_x = start_x + 2000; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Pairs: "); |
|
|
|
write_x += draw_text("Lists, Pairs: ").width; |
|
|
|
write_x += draw_integer(lists->next_index).width; |
|
|
|
draw_margin(); |
|
|
|
draw_integer(pairs->next_index); |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x + 2000; |
|
|
|
|
|
|
|
for (int i = 0; i < pairs->next_index; ++i) { |
|
|
|
for (int i = 0; i < lists->next_index; ++i) { |
|
|
|
draw_new_line(3); |
|
|
|
write_x = start_x + 2000; |
|
|
|
|
|
|
|
draw_pair(pairs->data[i]); |
|
|
|
write_y += draw_pair(lists->data[i]).height; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
@@ -369,7 +513,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
"<?xml version='1.0' encoding='UTF-8'?>\n" |
|
|
|
"<svg xmlns='http://www.w3.org/2000/svg'\n" |
|
|
|
" version='1.1' baseProfile='full'\n" |
|
|
|
" viewBox='%06d %06d %06d %06d'" |
|
|
|
" viewBox='%012d %012d %012d %012d'" |
|
|
|
">\n\n", -padding, -padding, 0, 0); |
|
|
|
|
|
|
|
draw_header(); |
|
|
|
@@ -385,6 +529,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
"<?xml version='1.0' encoding='UTF-8'?>\n" |
|
|
|
"<svg xmlns='http://www.w3.org/2000/svg'\n" |
|
|
|
" version='1.1' baseProfile='full'\n" |
|
|
|
" viewBox='%06d %06d %06d %06d'", -padding, -padding, max_x + 2*padding, max_y + 2*padding); |
|
|
|
" viewBox='%012d %012d %012d %012d'" |
|
|
|
">", -padding, -padding, max_x + 2*padding, max_y + 2*padding); |
|
|
|
|
|
|
|
} |