mu/archive/1.vm/052tangle.cc

530 lines
15 KiB
C++
Raw Normal View History

//: Allow code for recipes to be pulled in from multiple places and inserted
//: at special labels called 'waypoints' using two new top-level commands:
//: before
//: after
//: Most labels are local: they must be unique to a recipe, and are invisible
//: outside the recipe. However, waypoints are global: a recipe can have
//: multiple of them, you can't use them as jump targets.
:(before "End is_jump_target Special-cases")
if (is_waypoint(label)) return false;
//: Waypoints are always surrounded by '<>', e.g. <handle-request>.
:(code)
bool is_waypoint(string label) {
return *label.begin() == '<' && *label.rbegin() == '>';
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_before() {
run(
"def main [\n"
" 1:num <- copy 0\n"
" <label1>\n"
" 3:num <- copy 0\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 0\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 0 in location 1\n"
"mem: storing 0 in location 2\n"
"mem: storing 0 in location 3\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 3);
}
//: while loading recipes, load before/after fragments
:(before "End Globals")
map<string /*label*/, recipe> Before_fragments, After_fragments;
set<string /*label*/> Fragments_used;
2017-07-09 21:34:17 +00:00
:(before "End Reset")
Before_fragments.clear();
After_fragments.clear();
Fragments_used.clear();
:(before "End Command Handlers")
else if (command == "before") {
string label = next_word(in);
if (label.empty()) {
assert(!has_data(in));
raise << "incomplete 'before' block at end of file\n" << end();
return result;
}
recipe tmp;
slurp_body(in, tmp);
if (is_waypoint(label))
Before_fragments[label].steps.insert(Before_fragments[label].steps.end(), tmp.steps.begin(), tmp.steps.end());
else
raise << "can't tangle before non-waypoint " << label << '\n' << end();
// End before Command Handler
}
else if (command == "after") {
string label = next_word(in);
if (label.empty()) {
assert(!has_data(in));
raise << "incomplete 'after' block at end of file\n" << end();
return result;
}
recipe tmp;
slurp_body(in, tmp);
if (is_waypoint(label))
After_fragments[label].steps.insert(After_fragments[label].steps.begin(), tmp.steps.begin(), tmp.steps.end());
else
raise << "can't tangle after non-waypoint " << label << '\n' << end();
// End after Command Handler
}
//: after all recipes are loaded, insert fragments at appropriate labels.
:(after "Begin Instruction Inserting/Deleting Transforms")
Transform.push_back(insert_fragments); // NOT idempotent
2015-11-05 03:37:08 +00:00
//: We might need to perform multiple passes, in case inserted fragments
//: include more labels that need further insertions. Track which labels we've
//: already processed using an extra field.
:(before "End instruction Fields")
mutable bool tangle_done;
:(before "End instruction Constructor")
tangle_done = false;
:(code)
void insert_fragments(const recipe_ordinal r) {
2016-05-25 01:58:23 +00:00
insert_fragments(get(Recipe, r));
}
void insert_fragments(recipe& r) {
trace(101, "transform") << "--- insert fragments into recipe " << r.name << end();
bool made_progress = true;
int pass = 0;
while (made_progress) {
made_progress = false;
// create a new vector because insertions invalidate iterators
vector<instruction> result;
2016-10-20 05:10:35 +00:00
for (int i = 0; i < SIZE(r.steps); ++i) {
2016-05-25 01:58:23 +00:00
const instruction& inst = r.steps.at(i);
if (!inst.is_label || !is_waypoint(inst.label) || inst.tangle_done) {
result.push_back(inst);
continue;
}
inst.tangle_done = true;
made_progress = true;
Fragments_used.insert(inst.label);
ostringstream prefix;
2016-05-25 01:58:23 +00:00
prefix << '+' << r.name << '_' << pass << '_' << i;
// ok to use contains_key even though Before_fragments uses [],
// because appending an empty recipe is a noop
if (contains_key(Before_fragments, inst.label)) {
trace(102, "transform") << "insert fragments before label " << inst.label << end();
append_fragment(result, Before_fragments[inst.label].steps, prefix.str());
}
result.push_back(inst);
if (contains_key(After_fragments, inst.label)) {
trace(102, "transform") << "insert fragments after label " << inst.label << end();
append_fragment(result, After_fragments[inst.label].steps, prefix.str());
}
}
2016-05-25 01:58:23 +00:00
r.steps.swap(result);
++pass;
}
}
void append_fragment(vector<instruction>& base, const vector<instruction>& patch, const string prefix) {
// append 'patch' to 'base' while keeping 'base' oblivious to any new jump
// targets in 'patch' oblivious to 'base' by prepending 'prefix' to them.
// we might tangle the same fragment at multiple points in a single recipe,
// and we need to avoid duplicate jump targets.
// so we'll keep jump targets local to the specific before/after fragment
// that introduces them.
set<string> jump_targets;
2016-10-20 05:10:35 +00:00
for (int i = 0; i < SIZE(patch); ++i) {
const instruction& inst = patch.at(i);
if (inst.is_label && is_jump_target(inst.label))
jump_targets.insert(inst.label);
}
2016-10-20 05:10:35 +00:00
for (int i = 0; i < SIZE(patch); ++i) {
instruction inst = patch.at(i);
if (inst.is_label) {
if (contains_key(jump_targets, inst.label))
inst.label = prefix+inst.label;
base.push_back(inst);
continue;
}
2016-10-20 05:10:35 +00:00
for (int j = 0; j < SIZE(inst.ingredients); ++j) {
reagent& x = inst.ingredients.at(j);
if (is_jump_target(x.name) && contains_key(jump_targets, x.name))
x.name = prefix+x.name;
}
base.push_back(inst);
}
}
//: complain about unapplied fragments
//: This can't run during transform because later (shape-shifting recipes)
//: we'll encounter situations where fragments might get used long after
//: they're loaded, and we might run transform_all in between. To avoid
//: spurious errors, run this check right at the end, after all code is
//: loaded, right before we run main.
:(before "End Commandline Parsing")
check_insert_fragments();
:(code)
void check_insert_fragments() {
2016-10-20 05:10:35 +00:00
for (map<string, recipe>::iterator p = Before_fragments.begin(); p != Before_fragments.end(); ++p) {
if (!contains_key(Fragments_used, p->first))
raise << "could not locate insert before label " << p->first << '\n' << end();
}
2016-10-20 05:10:35 +00:00
for (map<string, recipe>::iterator p = After_fragments.begin(); p != After_fragments.end(); ++p) {
if (!contains_key(Fragments_used, p->first))
raise << "could not locate insert after label " << p->first << '\n' << end();
}
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_before_and_after() {
run(
"def main [\n"
" 1:num <- copy 0\n"
" <label1>\n"
" 4:num <- copy 0\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 0\n"
"]\n"
"after <label1> [\n"
" 3:num <- copy 0\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 0 in location 1\n"
"mem: storing 0 in location 2\n"
// label1
"mem: storing 0 in location 3\n"
"mem: storing 0 in location 4\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 4);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_ignores_jump_target() {
Hide_errors = true;
run(
"def main [\n"
" 1:num <- copy 0\n"
" +label1\n"
" 4:num <- copy 0\n"
"]\n"
"before +label1 [\n"
" 2:num <- copy 0\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"error: can't tangle before non-waypoint +label1\n"
);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_keeps_labels_separate() {
run(
"def main [\n"
" 1:num <- copy 0\n"
" <label1>\n"
" <label2>\n"
" 6:num <- copy 0\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 0\n"
"]\n"
"after <label1> [\n"
" 3:num <- copy 0\n"
"]\n"
"before <label2> [\n"
" 4:num <- copy 0\n"
"]\n"
"after <label2> [\n"
" 5:num <- copy 0\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 0 in location 1\n"
"mem: storing 0 in location 2\n"
// label1
"mem: storing 0 in location 3\n"
// 'after' fragments for earlier label always go before 'before'
// fragments for later label
"mem: storing 0 in location 4\n"
// label2
"mem: storing 0 in location 5\n"
"mem: storing 0 in location 6\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 6);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_stacks_multiple_fragments() {
run(
"def main [\n"
" 1:num <- copy 0\n"
" <label1>\n"
" 6:num <- copy 0\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 0\n"
"]\n"
"after <label1> [\n"
" 3:num <- copy 0\n"
"]\n"
"before <label1> [\n"
" 4:num <- copy 0\n"
"]\n"
"after <label1> [\n"
" 5:num <- copy 0\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 0 in location 1\n"
// 'before' fragments stack in order
"mem: storing 0 in location 2\n"
"mem: storing 0 in location 4\n"
// label1
// 'after' fragments stack in reverse order
"mem: storing 0 in location 5\n"
"mem: storing 0 in location 3\n"
"mem: storing 0 in location 6\n"
);
// nothing
CHECK_TRACE_COUNT("mem", 6);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_supports_fragments_with_multiple_instructions() {
run(
"def main [\n"
" 1:num <- copy 0\n"
" <label1>\n"
" 6:num <- copy 0\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 0\n"
" 3:num <- copy 0\n"
"]\n"
"after <label1> [\n"
" 4:num <- copy 0\n"
" 5:num <- copy 0\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 0 in location 1\n"
"mem: storing 0 in location 2\n"
"mem: storing 0 in location 3\n"
// label1
"mem: storing 0 in location 4\n"
"mem: storing 0 in location 5\n"
"mem: storing 0 in location 6\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 6);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_tangles_into_all_labels_with_same_name() {
run(
"def main [\n"
" 1:num <- copy 10\n"
" <label1>\n"
" 4:num <- copy 10\n"
" recipe2\n"
"]\n"
"def recipe2 [\n"
" 1:num <- copy 11\n"
" <label1>\n"
" 4:num <- copy 11\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 12\n"
"]\n"
"after <label1> [\n"
" 3:num <- copy 12\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 10 in location 1\n"
"mem: storing 12 in location 2\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 10 in location 4\n"
// recipe2
"mem: storing 11 in location 1\n"
"mem: storing 12 in location 2\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 11 in location 4\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 8);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_tangles_into_all_labels_with_same_name_2() {
run(
"def main [\n"
" 1:num <- copy 10\n"
" <label1>\n"
" <label1>\n"
" 4:num <- copy 10\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 12\n"
"]\n"
"after <label1> [\n"
" 3:num <- copy 12\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 10 in location 1\n"
"mem: storing 12 in location 2\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 12 in location 2\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 10 in location 4\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 6);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_tangles_into_all_labels_with_same_name_3() {
run(
"def main [\n"
" 1:num <- copy 10\n"
" <label1>\n"
" <foo>\n"
" 4:num <- copy 10\n"
"]\n"
"before <label1> [\n"
" 2:num <- copy 12\n"
"]\n"
"after <label1> [\n"
" 3:num <- copy 12\n"
"]\n"
"after <foo> [\n"
" <label1>\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 10 in location 1\n"
"mem: storing 12 in location 2\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 12 in location 2\n"
// foo/label1
"mem: storing 12 in location 3\n"
"mem: storing 10 in location 4\n"
);
// nothing else
CHECK_TRACE_COUNT("mem", 6);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_handles_jump_target_inside_fragment() {
run(
"def main [\n"
" 1:num <- copy 10\n"
" <label1>\n"
" 4:num <- copy 10\n"
"]\n"
"before <label1> [\n"
" jump +label2:label\n"
" 2:num <- copy 12\n"
" +label2\n"
" 3:num <- copy 12\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 10 in location 1\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 10 in location 4\n"
);
// ignored by jump
CHECK_TRACE_DOESNT_CONTAIN("mem: storing 12 in label 2");
// nothing else
CHECK_TRACE_COUNT("mem", 3);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_renames_jump_target() {
run(
"def main [\n"
" 1:num <- copy 10\n"
" <label1>\n"
" +label2\n"
" 4:num <- copy 10\n"
"]\n"
"before <label1> [\n"
" jump +label2:label\n"
" 2:num <- copy 12\n"
" +label2 # renamed\n"
" 3:num <- copy 12\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 10 in location 1\n"
// label1
"mem: storing 12 in location 3\n"
"mem: storing 10 in location 4\n"
);
// ignored by jump
CHECK_TRACE_DOESNT_CONTAIN("mem: storing 12 in label 2");
// nothing else
CHECK_TRACE_COUNT("mem", 3);
}
5001 - drop the :(scenario) DSL I've been saying for a while[1][2][3] that adding extra abstractions makes things harder for newcomers, and adding new notations doubly so. And then I notice this DSL in my own backyard. Makes me feel like a hypocrite. [1] https://news.ycombinator.com/item?id=13565743#13570092 [2] https://lobste.rs/s/to8wpr/configuration_files_are_canary_warning [3] https://lobste.rs/s/mdmcdi/little_languages_by_jon_bentley_1986#c_3miuf2 The implementation of the DSL was also highly hacky: a) It was happening in the tangle/ tool, but was utterly unrelated to tangling layers. b) There were several persnickety constraints on the different kinds of lines and the specific order they were expected in. I kept finding bugs where the translator would silently do the wrong thing. Or the error messages sucked, and readers may be stuck looking at the generated code to figure out what happened. Fixing error messages would require a lot more code, which is one of my arguments against DSLs in the first place: they may be easy to implement, but they're hard to design to go with the grain of the underlying platform. They require lots of iteration. Is that effort worth prioritizing in this project? On the other hand, the DSL did make at least some readers' life easier, the ones who weren't immediately put off by having to learn a strange syntax. There were fewer quotes to parse, fewer backslash escapes. Anyway, since there are also people who dislike having to put up with strange syntaxes, we'll call that consideration a wash and tear this DSL out. --- This commit was sheer drudgery. Hopefully it won't need to be redone with a new DSL because I grow sick of backslashes.
2019-03-13 01:56:55 +00:00
void test_tangle_jump_to_base_recipe() {
run(
"def main [\n"
" 1:num <- copy 10\n"
" <label1>\n"
" +label2\n"
" 4:num <- copy 10\n"
"]\n"
"before <label1> [\n"
" jump +label2:label\n"
" 2:num <- copy 12\n"
" 3:num <- copy 12\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"mem: storing 10 in location 1\n"
// label1
"mem: storing 10 in location 4\n"
);
// ignored by jump
CHECK_TRACE_DOESNT_CONTAIN("mem: storing 12 in label 2");
CHECK_TRACE_DOESNT_CONTAIN("mem: storing 12 in location 3");
// nothing else
CHECK_TRACE_COUNT("mem", 2);
}
//: ensure that there are no new fragments created for a label after it's already been inserted to
void test_new_fragment_after_tangle() {
// define a recipe
load("def foo [\n"
" local-scope\n"
" <label>\n"
"]\n"
"after <label> [\n"
2016-09-17 17:28:25 +00:00
" 1:num/raw <- copy 34\n"
"]\n");
transform_all();
2016-11-16 05:55:56 +00:00
CHECK_TRACE_DOESNT_CONTAIN_ERRORS();
Hide_errors = true;
// try to tangle into recipe foo after transform
load("before <label> [\n"
2016-09-17 17:28:25 +00:00
" 2:num/raw <- copy 35\n"
"]\n");
2016-11-16 05:55:56 +00:00
CHECK_TRACE_CONTAINS_ERRORS();
}
:(before "End before Command Handler")
if (contains_key(Fragments_used, label))
raise << "we've already tangled some code at label " << label << " in a previous call to transform_all(). Those locations won't be updated.\n" << end();
:(before "End after Command Handler")
if (contains_key(Fragments_used, label))
raise << "we've already tangled some code at label " << label << " in a previous call to transform_all(). Those locations won't be updated.\n" << end();