about summary refs log blame commit diff stats
path: root/themes/whiteness
blob: 5bf83850dea335dbe291af05a763805f9c1fa24d (plain) (tree)
fbc30231 ^

















<
//: Introduce a new transform to perform various checks in instructions before
//: we start running them. It'll be extensible, so that we can add checks for
//: new recipes as we extend 'run' to support them.
//:
//: Doing checking in a separate part complicates things, because the values
//: of variables in memory and the processor (current_recipe_name,
//: current_instruction) aren't available at checking time. If I had a more
//: sophisticated layer system I'd introduce the simpler version first and
//: transform it in a separate layer or set of layers.

:(before "End Checks")
Transform.push_back(check_instructionpre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
[colours]
bkgnd=white
titlebar=blue
titlebar.text=white
titlebar.brackets=white
titlebar.unencrypted=red
titlebar.encrypted=white
titlebar.untrusted=yellow
titlebar.trusted=white
titlebar.online=white
titlebar.offline=red
titlebar.away=white
titlebar.chat=white
titlebar.dnd=red
titlebar.xa=white
statusbar=blue
statusbar.text=white
statusbar.brackets=white
statusbar.active=megenta
statusbar.new=red
main.text=black
main.text.me=black
main.text.them=black
main.splash=black
main.time=black
input.text=black
subscribed=green
unsubscribed=red
otr.started.trusted=green
otr.started.untrusted=yellow
otr.ended=red
otr.trusted=green
otr.untrusted=yellow
online=green
away=cyan
chat=green
dnd=red
xa=cyan
offline=red
incoming=yellow
mention=yellow
trigger=yellow
typing=yellow
gone=red
error=red
roominfo=yellow
roommention=yellow
roommention.term=yellow
roomtrigger=yellow
roomtrigger.term=yellow
me=black
them=black
roster.header=black
roster.chat=green
roster.online=green
roster.away=cyan
roster.xa=cyan
roster.dnd=red
roster.offline=red
roster.chat.active=green
roster.online.active=green
roster.away.active=cyan
roster.xa.active=cyan
roster.dnd.active=red
roster.offline.active=red
roster.chat.unread=green
roster.online.unread=green
roster.away.unread=cyan
roster.xa.unread=cyan
roster.dnd.unread=red
roster.offline.unread=red
roster.room=green
roster.room.unread=green
roster.room.mention=green
roster.room.trigger=green
occupants.header=black
receipt.sent=red
/span>maybe(get(Recipe, r).name) << "can't copy '" << inst.ingredients.at(i).original_string << "' to '" << inst.products.at(i).original_string << "'; types don't match\n" << end(); goto finish_checking_instruction; } } break; } // End Primitive Recipe Checks default: { // Defined Recipe Checks // End Defined Recipe Checks } } finish_checking_instruction:; } } void test_copy_checks_reagent_count() { Hide_errors = true; run( "def main [\n" " 1:num, 2:num <- copy 34\n" "]\n" ); CHECK_TRACE_CONTENTS( "error: main: too many products in '1:num, 2:num <- copy 34'\n" ); } void test_write_scalar_to_array_disallowed() { Hide_errors = true; run( "def main [\n" " 1:array:num <- copy 34\n" "]\n" ); CHECK_TRACE_CONTENTS( "error: main: can't copy '34' to '1:array:num'; types don't match\n" ); } void test_write_scalar_to_array_disallowed_2() { Hide_errors = true; run( "def main [\n" " 1:num, 2:array:num <- copy 34, 35\n" "]\n" ); CHECK_TRACE_CONTENTS( "error: main: can't copy '35' to '2:array:num'; types don't match\n" ); } void test_write_scalar_to_address_disallowed() { Hide_errors = true; run( "def main [\n" " 1:&:num <- copy 34\n" "]\n" ); CHECK_TRACE_CONTENTS( "error: main: can't copy '34' to '1:&:num'; types don't match\n" ); } void test_write_address_to_character_disallowed() { Hide_errors = true; run( "def main [\n" " 1:&:num <- copy 12/unsafe\n" " 2:char <- copy 1:&:num\n" "]\n" ); CHECK_TRACE_CONTENTS( "error: main: can't copy '1:&:num' to '2:char'; types don't match\n" ); } void test_write_number_to_character_allowed() { run( "def main [\n" " 1:num <- copy 97\n" " 2:char <- copy 1:num\n" "]\n" ); CHECK_TRACE_COUNT("error", 0); } :(code) // types_match with some leniency bool types_coercible(reagent/*copy*/ to, reagent/*copy*/ from) { // Begin types_coercible(reagent to, reagent from) if (types_match_sub(to, from)) return true; if (is_real_mu_number(from) && is_mu_character(to)) return true; // End types_coercible Special-cases return false; } bool types_match_sub(const reagent& to, const reagent& from) { // to sidestep type-checking, use /unsafe in the source. // this will be highlighted in red inside vim. just for setting up some tests. if (is_unsafe(from)) return true; if (is_literal(from)) { if (is_mu_array(to)) return false; // End Matching Types For Literal(to) if (!to.type) return false; // allow writing null to any address if (is_mu_address(to)) return from.name == "null"; return size_of(to) == 1; // literals are always scalars } return types_strictly_match_sub(to, from); } // variant for others to call bool types_match(reagent/*copy*/ to, reagent/*copy*/ from) { // Begin types_match(reagent to, reagent from) return types_match_sub(to, from); } //: copy arguments for later layers bool types_strictly_match_sub(const reagent& to, const reagent& from) { if (to.type == NULL) return false; // error if (is_literal(from) && to.type->value == Number_type_ordinal) return true; // to sidestep type-checking, use /unsafe in the source. // this will be highlighted in red inside vim. just for setting up some tests. if (is_unsafe(from)) return true; // '_' never raises type error if (is_dummy(to)) return true; if (!to.type) return !from.type; return types_strictly_match(to.type, from.type); } // variant for others to call bool types_strictly_match(reagent/*copy*/ to, reagent/*copy*/ from) { // Begin types_strictly_match(reagent to, reagent from) return types_strictly_match_sub(to, from); } bool types_strictly_match(const type_tree* to, const type_tree* from) { if (from == to) return true; if (!to) return false; if (!from) return to->atom && to->value == 0; if (from->atom != to->atom) return false; if (from->atom) { if (from->value == -1) return from->name == to->name; return from->value == to->value; } if (types_strictly_match(to->left, from->left) && types_strictly_match(to->right, from->right)) return true; // fallback: (x) == x if (to->right == NULL && types_strictly_match(to->left, from)) return true; if (from->right == NULL && types_strictly_match(to, from->left)) return true; return false; } void test_unknown_type_does_not_match_unknown_type() { reagent a("a:foo"); reagent b("b:bar"); CHECK(!types_strictly_match(a, b)); } void test_unknown_type_matches_itself() { reagent a("a:foo"); reagent b("b:foo"); CHECK(types_strictly_match(a, b)); } void test_type_abbreviations_match_raw_types() { put(Type_abbreviations, "text", new_type_tree("address:array:character")); // a has type (address buffer (address array character)) reagent a("a:address:buffer:text"); expand_type_abbreviations(a.type); // b has type (address buffer address array character) reagent b("b:address:buffer:address:array:character"); CHECK(types_strictly_match(a, b)); delete Type_abbreviations["text"]; put(Type_abbreviations, "text", NULL); } //: helpers bool is_unsafe(const reagent& r) { return has_property(r, "unsafe"); } bool is_mu_array(reagent/*copy*/ r) { // End Preprocess is_mu_array(reagent r) return is_mu_array(r.type); } bool is_mu_array(const type_tree* type) { if (!type) return false; if (is_literal(type)) return false; if (type->atom) return false; if (!type->left->atom) { raise << "invalid type " << to_string(type) << '\n' << end(); return false; } return type->left->value == Array_type_ordinal; } bool is_mu_boolean(reagent/*copy*/ r) { // End Preprocess is_mu_boolean(reagent r) if (!r.type) return false; if (is_literal(r)) return false; if (!r.type->atom) return false; return r.type->value == Boolean_type_ordinal; } bool is_mu_number(reagent/*copy*/ r) { if (is_mu_character(r.type)) return true; // permit arithmetic on unicode code points return is_real_mu_number(r); } bool is_real_mu_number(reagent/*copy*/ r) { // End Preprocess is_mu_number(reagent r) if (!r.type) return false; if (!r.type->atom) return false; if (is_literal(r)) { return r.type->name == "literal-fractional-number" || r.type->name == "literal"; } return r.type->value == Number_type_ordinal; } bool is_mu_character(reagent/*copy*/ r) { // End Preprocess is_mu_character(reagent r) return is_mu_character(r.type); } bool is_mu_character(const type_tree* type) { if (!type) return false; if (!type->atom) return false; if (is_literal(type)) return false; return type->value == Character_type_ordinal; }