about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-06-17 00:05:38 -0700
committerKartik Agaram <vc@akkartik.com>2018-06-17 00:29:22 -0700
commitdd66068298b0a11f2a1f195376cba98e0c8570b5 (patch)
tree06696728fd65cdf38a2ac571943e130e9d60c333
parentb89b822439f47a490a1b764e14a1ed1b73059cba (diff)
downloadmu-dd66068298b0a11f2a1f195376cba98e0c8570b5.tar.gz
4261 - start using literals for 'true' and 'false'
They uncovered one bug: in edit/003-shortcuts.mu
  <scroll-down> was returning 0 for an address in one place where I
  thought it was returning 0 for a boolean.

Now we've eliminated this bad interaction between tangling and punning
literals.
-rw-r--r--021check_instruction.cc19
-rw-r--r--022constant.cc38
-rw-r--r--024boolean.cc24
-rw-r--r--041jump_target.cc4
-rw-r--r--046check_type_by_name.cc2
-rw-r--r--053recipe_header.cc4
-rw-r--r--054static_dispatch.cc84
-rw-r--r--055shape_shifting_container.cc2
-rw-r--r--056shape_shifting_recipe.cc8
-rw-r--r--061text.mu20
-rw-r--r--065duplex_list.mu6
-rw-r--r--066stream.mu8
-rw-r--r--068random.mu2
-rw-r--r--070table.mu2
-rw-r--r--075channel.mu10
-rw-r--r--076continuation.cc4
-rw-r--r--081print.mu26
-rw-r--r--084console.mu12
-rw-r--r--088file.mu14
-rw-r--r--chessboard.mu38
-rw-r--r--continuation2.mu2
-rw-r--r--continuation4.mu2
-rw-r--r--continuation5.mu2
-rw-r--r--edit/002-typing.mu50
-rw-r--r--edit/003-shortcuts.mu91
-rw-r--r--edit/004-programming-environment.mu10
-rw-r--r--edit/005-sandbox.mu2
-rw-r--r--edit/006-sandbox-copy.mu22
-rw-r--r--edit/007-sandbox-delete.mu6
-rw-r--r--edit/008-sandbox-edit.mu10
-rw-r--r--edit/011-errors.mu6
-rw-r--r--edit/012-editor-undo.mu4
-rw-r--r--exception1.mu4
-rw-r--r--exception2.mu4
-rw-r--r--lambda-to-mu.mu6
-rw-r--r--mu.vim1
-rw-r--r--nqueens.mu8
-rw-r--r--same-fringe.mu8
-rw-r--r--sandbox/002-typing.mu50
-rw-r--r--sandbox/003-shortcuts.mu52
-rw-r--r--sandbox/004-programming-environment.mu4
-rw-r--r--sandbox/005-sandbox.mu2
-rw-r--r--sandbox/006-sandbox-copy.mu10
-rw-r--r--sandbox/007-sandbox-delete.mu6
-rw-r--r--sandbox/008-sandbox-edit.mu8
-rw-r--r--sandbox/011-errors.mu6
-rw-r--r--sandbox/012-editor-undo.mu4
-rw-r--r--vimrc.vim1
48 files changed, 340 insertions, 368 deletions
diff --git a/021check_instruction.cc b/021check_instruction.cc
index 44f08f3f..48f90078 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -86,27 +86,10 @@ def main [
 ]
 $error: 0
 
-:(scenario write_boolean_to_number_allowed)
-def main [
-  1:bool <- copy 1/true
-  2:num <- copy 1:bool
-]
-+mem: storing 1 in location 2
-$error: 0
-
-:(scenario write_number_to_boolean_disallowed)
-% Hide_errors = true;
-def main [
-  1:num <- copy 34
-  2:bool <- copy 1:num
-]
-+error: main: can't copy '1:num' to '2:bool'; types don't match
-
 :(code)
 // types_match with some leniency
 bool types_coercible(const reagent& to, const reagent& from) {
   if (types_match(to, from)) return true;
-  if (is_mu_boolean(from) && is_real_mu_number(to)) return true;
   if (is_real_mu_number(from) && is_mu_character(to)) return true;
   // End types_coercible Special-cases
   return false;
@@ -122,7 +105,7 @@ bool types_match(const reagent& to, const reagent& from) {
     // allow writing 0 to any address
     if (is_mu_address(to)) return from.name == "0";
     if (!to.type) return false;
-    if (is_mu_boolean(to)) return from.name == "0" || from.name == "1";
+    // End Literal types_match Special-cases
     return size_of(to) == 1;  // literals are always scalars
   }
   return types_strictly_match(to, from);
diff --git a/022constant.cc b/022constant.cc
new file mode 100644
index 00000000..800e1b2b
--- /dev/null
+++ b/022constant.cc
@@ -0,0 +1,38 @@
+//: A few literal constants.
+
+:(before "End Mu Types Initialization")
+put(Type_ordinal, "literal-boolean", 0);
+
+:(scenario true)
+def main [
+  1:boolean <- copy true
+]
++mem: storing 1 in location 1
+
+:(before "End Parsing reagent")
+if (name == "true") {
+  if (type != NULL) {
+    raise << "'true' is a literal and can't take a type\n" << end();
+    return;
+  }
+  type = new type_tree("literal-boolean");
+  set_value(1);
+}
+:(before "End Literal types_match Special-cases")
+if (is_mu_boolean(to)) return from.name == "false" || from.name == "true";
+
+:(scenario false)
+def main [
+  1:boolean <- copy false
+]
++mem: storing 0 in location 1
+
+:(before "End Parsing reagent")
+if (name == "false") {
+  if (type != NULL) {
+    raise << "'false' is a literal and can't take a type\n" << end();
+    return;
+  }
+  type = new type_tree("literal-boolean");
+  set_value(0);
+}
diff --git a/024boolean.cc b/024boolean.cc
index 3d51fd7a..114d9d8e 100644
--- a/024boolean.cc
+++ b/024boolean.cc
@@ -34,27 +34,27 @@ case AND: {
 
 :(scenario and)
 def main [
-  1:bool <- copy 1
-  2:bool <- copy 0
+  1:bool <- copy true
+  2:bool <- copy false
   3:bool <- and 1:bool, 2:bool
 ]
 +mem: storing 0 in location 3
 
 :(scenario and_2)
 def main [
-  1:bool <- and 1, 1
+  1:bool <- and true, true
 ]
 +mem: storing 1 in location 1
 
 :(scenario and_multiple)
 def main [
-  1:bool <- and 1, 1, 0
+  1:bool <- and true, true, false
 ]
 +mem: storing 0 in location 1
 
 :(scenario and_multiple_2)
 def main [
-  1:bool <- and 1, 1, 1
+  1:bool <- and true, true, true
 ]
 +mem: storing 1 in location 1
 
@@ -92,27 +92,27 @@ case OR: {
 
 :(scenario or)
 def main [
-  1:bool <- copy 1
-  2:bool <- copy 0
+  1:bool <- copy true
+  2:bool <- copy false
   3:bool <- or 1:bool, 2:bool
 ]
 +mem: storing 1 in location 3
 
 :(scenario or_2)
 def main [
-  1:bool <- or 0, 0
+  1:bool <- or false, false
 ]
 +mem: storing 0 in location 1
 
 :(scenario or_multiple)
 def main [
-  1:bool <- and 0, 0, 0
+  1:bool <- or false, false, false
 ]
 +mem: storing 0 in location 1
 
 :(scenario or_multiple_2)
 def main [
-  1:bool <- or 0, 0, 1
+  1:bool <- or false, false, true
 ]
 +mem: storing 1 in location 1
 
@@ -152,14 +152,14 @@ case NOT: {
 
 :(scenario not)
 def main [
-  1:bool <- copy 1
+  1:bool <- copy true
   2:bool <- not 1:bool
 ]
 +mem: storing 0 in location 2
 
 :(scenario not_multiple)
 def main [
-  1:bool, 2:bool, 3:bool <- not 1, 0, 1
+  1:bool, 2:bool, 3:bool <- not true, false, true
 ]
 +mem: storing 0 in location 1
 +mem: storing 1 in location 2
diff --git a/041jump_target.cc b/041jump_target.cc
index ada1eaf5..d8eaf68a 100644
--- a/041jump_target.cc
+++ b/041jump_target.cc
@@ -154,9 +154,9 @@ def main [
 :(scenario jump_fails_without_target_2)
 % Hide_errors = true;
 def main [
-  jump-if 1/true
+  jump-if true
 ]
-+error: main: 'jump-if 1/true' expects 2 ingredients but got 1
++error: main: 'jump-if true' expects 2 ingredients but got 1
 
 :(scenario recipe_fails_on_duplicate_jump_target)
 % Hide_errors = true;
diff --git a/046check_type_by_name.cc b/046check_type_by_name.cc
index df5a2a6d..786714b4 100644
--- a/046check_type_by_name.cc
+++ b/046check_type_by_name.cc
@@ -154,7 +154,7 @@ def foo [  # dummy
 def main [
   local-scope
   0:space/names:foo <- copy 0  # specify surrounding space
-  x:bool <- copy 1/true
+  x:bool <- copy true
   x:num/space:1 <- copy 34
   x/space:1 <- copy 35
 ]
diff --git a/053recipe_header.cc b/053recipe_header.cc
index 057234f9..e299d3c0 100644
--- a/053recipe_header.cc
+++ b/053recipe_header.cc
@@ -362,7 +362,7 @@ def add2 x:num, y:num [
 def foo -> x:num [
   local-scope
   x:num <- copy 0
-  z:bool <- copy 0/false
+  z:bool <- copy false
   return-if z, z
 ]
 +error: foo: replied with the wrong type at 'return-if z, z'
@@ -580,7 +580,7 @@ def add2 x:num, y:num -> z:num [
   local-scope
   load-ingredients
   z <- add x, y  # no type for z
-  return-if 0/false, 34
+  return-if false, 34
 ]
 +mem: storing 8 in location 1
 
diff --git a/054static_dispatch.cc b/054static_dispatch.cc
index 8037892e..5f0fb03c 100644
--- a/054static_dispatch.cc
+++ b/054static_dispatch.cc
@@ -192,17 +192,12 @@ string best_variant(const instruction& inst, const recipe& caller_recipe) {
   candidates = strictly_matching_variants(inst, variants);
   if (!candidates.empty()) return best_variant(inst, candidates).name;
 
-  // Static Dispatch Phase 2
-//?   cerr << inst.name << " phase 2\n";
-  candidates = strictly_matching_variants_except_literal_against_address_or_boolean(inst, variants);
-  if (!candidates.empty()) return best_variant(inst, candidates).name;
-
 //?   cerr << inst.name << " phase 3\n";
-  // Static Dispatch Phase 3
+  // Static Dispatch Phase 2
   //: (shape-shifting recipes in a later layer)
-  // End Static Dispatch Phase 3
+  // End Static Dispatch Phase 2
 
-  // Static Dispatch Phase 4
+  // Static Dispatch Phase 3
 //?   cerr << inst.name << " phase 4\n";
   candidates = matching_variants(inst, variants);
   if (!candidates.empty()) return best_variant(inst, candidates).name;
@@ -270,46 +265,7 @@ bool all_header_reagents_strictly_match(const instruction& inst, const recipe& v
   return true;
 }
 
-// phase 2
-vector<recipe_ordinal> strictly_matching_variants_except_literal_against_address_or_boolean(const instruction& inst, const vector<recipe_ordinal>& variants) {
-  vector<recipe_ordinal> result;
-  for (int i = 0;  i < SIZE(variants);  ++i) {
-    if (variants.at(i) == -1) continue;
-    trace(9992, "transform") << "checking variant (strict except literal-against-boolean) " << i << ": " << header_label(variants.at(i)) << end();
-    if (all_header_reagents_strictly_match_except_literal_against_address_or_boolean(inst, get(Recipe, variants.at(i))))
-      result.push_back(variants.at(i));
-  }
-  return result;
-}
-
-bool all_header_reagents_strictly_match_except_literal_against_address_or_boolean(const instruction& inst, const recipe& variant) {
-  for (int i = 0;  i < min(SIZE(inst.ingredients), SIZE(variant.ingredients));  ++i) {
-    if (!types_strictly_match_except_literal_against_address_or_boolean(variant.ingredients.at(i), inst.ingredients.at(i))) {
-      trace(9993, "transform") << "match failed: ingredient " << i << end();
-      return false;
-    }
-  }
-  for (int i = 0;  i < min(SIZE(variant.products), SIZE(inst.products));  ++i) {
-    if (is_dummy(inst.products.at(i))) continue;
-    if (!types_strictly_match_except_literal_against_address_or_boolean(variant.products.at(i), inst.products.at(i))) {
-      trace(9993, "transform") << "match failed: product " << i << end();
-      return false;
-    }
-  }
-  return true;
-}
-
-bool types_strictly_match_except_literal_against_address_or_boolean(const reagent& to, const reagent& from) {
-  if (is_literal(from) && is_mu_boolean(to))
-    return from.name == "0" || from.name == "1";
-  // Match Literal Zero Against Address {
-  if (is_literal(from) && is_mu_address(to))
-    return from.name == "0";
-  // }
-  return types_strictly_match(to, from);
-}
-
-// phase 4
+// phase 3
 vector<recipe_ordinal> matching_variants(const instruction& inst, const vector<recipe_ordinal>& variants) {
   vector<recipe_ordinal> result;
   for (int i = 0;  i < SIZE(variants);  ++i) {
@@ -422,15 +378,15 @@ def main [
   1:num <- copy 34
   2:num <- copy 34
   3:bool <- equal 1:num, 2:num
-  4:bool <- copy 0/false
-  5:bool <- copy 0/false
+  4:bool <- copy false
+  5:bool <- copy false
   6:bool <- equal 4:bool, 5:bool
 ]
 # temporarily hardcode number equality to always fail
 def equal x:num, y:num -> z:bool [
   local-scope
   load-ingredients
-  z <- copy 0/false
+  z <- copy false
 ]
 # comparing numbers used overload
 +mem: storing 0 in location 3
@@ -524,37 +480,15 @@ def foo x:num -> y:num [
 +error: main: ingredient 0 has the wrong type at '1:num/raw <- foo x'
 -mem: storing 34 in location 1
 
-:(scenario static_dispatch_dispatches_literal_to_boolean_before_character)
-def main [
-  1:num/raw <- foo 0  # valid literal for boolean
-]
-def foo x:char -> y:num [
-  local-scope
-  load-ingredients
-  return 34
-]
-def foo x:bool -> y:num [
-  local-scope
-  load-ingredients
-  return 35
-]
-# boolean variant is preferred
-+mem: storing 35 in location 1
-
-:(scenario static_dispatch_dispatches_literal_to_character_when_out_of_boolean_range)
+:(scenario static_dispatch_dispatches_literal_to_character)
 def main [
-  1:num/raw <- foo 97  # not a valid literal for boolean
+  1:num/raw <- foo 97
 ]
 def foo x:char -> y:num [
   local-scope
   load-ingredients
   return 34
 ]
-def foo x:bool -> y:num [
-  local-scope
-  load-ingredients
-  return 35
-]
 # character variant is preferred
 +mem: storing 34 in location 1
 
diff --git a/055shape_shifting_container.cc b/055shape_shifting_container.cc
index 0e7409d8..02e5214b 100644
--- a/055shape_shifting_container.cc
+++ b/055shape_shifting_container.cc
@@ -55,7 +55,7 @@ container foo:_a:_b [
   y:_b
 ]
 def main [
-  1:foo:num:bool <- merge 34, 1/true
+  1:foo:num:bool <- merge 34, true
 ]
 $error: 0
 
diff --git a/056shape_shifting_recipe.cc b/056shape_shifting_recipe.cc
index 29d443c2..f1145803 100644
--- a/056shape_shifting_recipe.cc
+++ b/056shape_shifting_recipe.cc
@@ -46,7 +46,7 @@ if (Current_routine->calls.front().running_step_index == 0
 :(before "End Matching Types For Literal(to)")
 if (contains_type_ingredient_name(to)) return false;
 
-:(after "Static Dispatch Phase 3")
+:(after "Static Dispatch Phase 2")
 candidates = strictly_matching_shape_shifting_variants(inst, variants);
 if (!candidates.empty()) {
   recipe_ordinal exemplar = best_shape_shifting_variant(inst, candidates);
@@ -68,10 +68,6 @@ if (contains_key(Recipe, inst.operation) && !is_primitive(inst.operation)
   return;
 }
 
-:(replace{} "Match Literal Zero Against Address")
-if (is_literal(from) && is_mu_address(to))
-  return from.name == "0" && !contains_type_ingredient_name(to);
-
 :(code)
 // phase 3 of static dispatch
 vector<recipe_ordinal> strictly_matching_shape_shifting_variants(const instruction& inst, const vector<recipe_ordinal>& variants) {
@@ -1111,7 +1107,7 @@ def foo a:_elem [
 ]
 # tangle some code that refers to the type ingredient
 after <label1> [
-  b:bool <- copy 0  # type abbreviation
+  b:bool <- copy false  # type abbreviation
 ]
 # trigger specialization
 def main [
diff --git a/061text.mu b/061text.mu
index ffc87140..8ef19a9d 100644
--- a/061text.mu
+++ b/061text.mu
@@ -5,15 +5,15 @@ def equal a:text, b:text -> result:bool [
   load-inputs
   an:num, bn:num <- deaddress a, b
   address-equal?:boolean <- equal an, bn
-  return-if address-equal?, 1/true
-  return-unless a, 0/false
-  return-unless b, 0/false
+  return-if address-equal?, true
+  return-unless a, false
+  return-unless b, false
   a-len:num <- length *a
   b-len:num <- length *b
   # compare lengths
   trace 99, [text-equal], [comparing lengths]
   length-equal?:bool <- equal a-len, b-len
-  return-unless length-equal?, 0/false
+  return-unless length-equal?, false
   # compare each corresponding character
   trace 99, [text-equal], [comparing characters]
   i:num <- copy 0
@@ -23,11 +23,11 @@ def equal a:text, b:text -> result:bool [
     a2:char <- index *a, i
     b2:char <- index *b, i
     chars-match?:bool <- equal a2, b2
-    return-unless chars-match?, 0/false
+    return-unless chars-match?, false
     i <- add i, 1
     loop
   }
-  return 1/true
+  return true
 ]
 
 scenario text-equal-reflexive [
@@ -358,7 +358,7 @@ def buffer-to-array in:&:buffer:_elem -> result:&:@:_elem [
 def blank? x:&:@:_elem -> result:bool [
   local-scope
   load-inputs
-  return-unless x, 1/true
+  return-unless x, true
   len:num <- length *x
   result <- equal len, 0
 ]
@@ -997,7 +997,7 @@ def match-at text:text, pattern:text, idx:num -> result:bool [
   x:num <- length *text
   x <- subtract x, pattern-len
   enough-room?:bool <- lesser-or-equal idx, x
-  return-unless enough-room?, 0/not-found
+  return-unless enough-room?, false/not-found
   # check each character of pattern
   pattern-idx:num <- copy 0
   {
@@ -1006,12 +1006,12 @@ def match-at text:text, pattern:text, idx:num -> result:bool [
     c:char <- index *text, idx
     exp:char <- index *pattern, pattern-idx
     match?:bool <- equal c, exp
-    return-unless match?, 0/not-found
+    return-unless match?, false/not-found
     idx <- add idx, 1
     pattern-idx <- add pattern-idx, 1
     loop
   }
-  return 1/found
+  return true/found
 ]
 
 scenario match-at-checks-pattern-at-index [
diff --git a/065duplex_list.mu b/065duplex_list.mu
index bf0c896a..129da96c 100644
--- a/065duplex_list.mu
+++ b/065duplex_list.mu
@@ -591,15 +591,15 @@ def match x:&:duplex-list:_elem, y:&:@:_elem -> result:bool [
     done?:bool <- greater-or-equal i, max
     break-if done?
     expected:_elem <- index *y, i
-    return-unless x, 0/no-match
+    return-unless x, false/no-match
     curr:_elem <- first x
     curr-matches?:bool <- equal curr, expected
-    return-unless curr-matches?, 0/no-match
+    return-unless curr-matches?, false/no-match
     x <- next x
     i <- add i, 1
     loop
   }
-  return 1/successful-match
+  return true/successful-match
 ]
 
 scenario duplex-list-match [
diff --git a/066stream.mu b/066stream.mu
index 6d5d0520..86ce26ed 100644
--- a/066stream.mu
+++ b/066stream.mu
@@ -24,7 +24,7 @@ def read in:&:stream:_elem -> result:_elem, empty?:bool, in:&:stream:_elem [
   local-scope
   load-inputs
   assert in, [cannot read; stream has no data]
-  empty? <- copy 0/false
+  empty? <- copy false
   idx:num <- get *in, index:offset
   s:&:@:_elem <- get *in, data:offset
   len:num <- length *s
@@ -32,7 +32,7 @@ def read in:&:stream:_elem -> result:_elem, empty?:bool, in:&:stream:_elem [
   {
     break-unless at-end?
     empty-result:&:_elem <- new _elem:type
-    return *empty-result, 1/true
+    return *empty-result, true
   }
   result <- index *s, idx
   idx <- add idx, 1
@@ -43,7 +43,7 @@ def peek in:&:stream:_elem -> result:_elem, empty?:bool [
   local-scope
   load-inputs
   assert in, [cannot peek; stream has no data]
-  empty?:bool <- copy 0/false
+  empty?:bool <- copy false
   idx:num <- get *in, index:offset
   s:&:@:_elem <- get *in, data:offset
   len:num <- length *s
@@ -51,7 +51,7 @@ def peek in:&:stream:_elem -> result:_elem, empty?:bool [
   {
     break-unless at-end?
     empty-result:&:_elem <- new _elem:type
-    return *empty-result, 1/true
+    return *empty-result, true
   }
   result <- index *s, idx
 ]
diff --git a/068random.mu b/068random.mu
index 78c059de..3d73356c 100644
--- a/068random.mu
+++ b/068random.mu
@@ -5,7 +5,7 @@ def random generator:&:stream:num -> result:num, fail?:bool, generator:&:stream:
     break-if generator
     # generator is 0? use real random-number generator
     result <- real-random
-    return result, 0/false
+    return result, false
   }
   result, fail?, generator <- read generator
 ]
diff --git a/070table.mu b/070table.mu
index a4ec5afb..21184084 100644
--- a/070table.mu
+++ b/070table.mu
@@ -76,7 +76,7 @@ def put-index table:&:table:_key:_value, key:_key, value:_value -> table:&:table
   occupied?:bool <- get x, occupied?:offset
   not-occupied?:bool <- not occupied?:bool
   assert not-occupied?, [can't handle collisions yet]
-  new-row:table-row:_key:_value <- merge 1/true, key, value
+  new-row:table-row:_key:_value <- merge true, key, value
   *table-data <- put-index *table-data, hash-key, new-row
 ]
 
diff --git a/075channel.mu b/075channel.mu
index 422b2ab8..c64492cb 100644
--- a/075channel.mu
+++ b/075channel.mu
@@ -106,7 +106,7 @@ def read in:&:source:_elem -> result:_elem, eof?:bool, in:&:source:_elem [
   local-scope
   load-inputs
   assert in, [read on null channel]
-  eof? <- copy 0/false  # default result
+  eof? <- copy false  # default result
   chan:&:channel:_elem <- get *in, chan:offset
   # block until lock is acquired AND queue has data
   lock:location <- get-location *chan, lock:offset
@@ -327,13 +327,13 @@ def close x:&:source:_elem -> x:&:source:_elem [
   local-scope
   load-inputs
   chan:&:channel:_elem <- get *x, chan:offset
-  *chan <- put *chan, closed?:offset, 1/true
+  *chan <- put *chan, closed?:offset, true
 ]
 def close x:&:sink:_elem -> x:&:sink:_elem [
   local-scope
   load-inputs
   chan:&:channel:_elem <- get *x, chan:offset
-  *chan <- put *chan, closed?:offset, 1/true
+  *chan <- put *chan, closed?:offset, true
 ]
 
 # once a channel is closed from one side, no further operations are expected from that side
@@ -352,7 +352,7 @@ after <channel-read-empty> [
     break-unless closed?
     empty-result:&:_elem <- new _elem:type
     current-routine-is-unblocked
-    return *empty-result, 1/true
+    return *empty-result, true
   }
 ]
 
@@ -401,7 +401,7 @@ def buffer-lines in:&:source:char, buffered-out:&:sink:char -> buffered-out:&:si
   local-scope
   load-inputs
   # repeat forever
-  eof?:bool <- copy 0/false
+  eof?:bool <- copy false
   {
     line:&:buffer:char <- new-buffer 30
     # read characters from 'in' until newline, copy into line
diff --git a/076continuation.cc b/076continuation.cc
index fd51869d..b5b9288b 100644
--- a/076continuation.cc
+++ b/076continuation.cc
@@ -152,7 +152,7 @@ case CALL_WITH_CONTINUATION_MARK: {
 
 :(scenario next_ingredient_inside_continuation)
 recipe main [
-  call-with-continuation-mark 233/mark, f, 1/true
+  call-with-continuation-mark 233/mark, f, true
 ]
 recipe f [
   10:bool <- next-input
@@ -162,7 +162,7 @@ recipe f [
 :(scenario delimited_continuation_out_of_recipe_variable)
 recipe main [
   x:recipe <- copy f
-  call-with-continuation-mark 233/mark, x, 1/true
+  call-with-continuation-mark 233/mark, x, true
 ]
 recipe f [
   10:bool <- next-input
diff --git a/081print.mu b/081print.mu
index 50b6485a..df58f831 100644
--- a/081print.mu
+++ b/081print.mu
@@ -39,7 +39,7 @@ def new-fake-screen w:num, h:num -> result:&:screen [
   assert non-zero-height?, [screen can't have zero height]
   bufsize:num <- multiply w, h
   data:&:@:screen-cell <- new screen-cell:type, bufsize
-  *result <- merge h/num-rows, w/num-columns, 0/cursor-row, 0/cursor-column, data, 0/pending-scroll?, 0/top-idx
+  *result <- merge h/num-rows, w/num-columns, 0/cursor-row, 0/cursor-column, data, false/pending-scroll?, 0/top-idx
   result <- clear-screen result
 ]
 
@@ -75,7 +75,7 @@ def fake-screen-is-empty? screen:&:screen -> result:bool [
   local-scope
   load-inputs
 #?   stash [fake-screen-is-empty?]
-  return-unless screen, 1/true  # do nothing for real screens
+  return-unless screen, true  # do nothing for real screens
   buf:&:@:screen-cell <- get *screen, data:offset
   i:num <- copy 0
   len:num <- length *buf
@@ -87,9 +87,9 @@ def fake-screen-is-empty? screen:&:screen -> result:bool [
     i <- add i, 1
     loop-unless curr-contents
     # not 0
-    return 0/false
+    return false
   }
-  return 1/true
+  return true
 ]
 
 def print screen:&:screen, c:char -> screen:&:screen [
@@ -150,7 +150,7 @@ def print screen:&:screen, c:char -> screen:&:screen [
     break-unless pending-scroll?
 #?     stash [scroll]
     scroll-fake-screen screen
-    *screen <- put *screen, pending-scroll?:offset, 0/false
+    *screen <- put *screen, pending-scroll?:offset, false
   }
 #?     $print [print-character (], row, [, ], column, [): ], c, 10/newline
   # special-case: newline
@@ -196,7 +196,7 @@ def print screen:&:screen, c:char -> screen:&:screen [
     break-unless past-bottom?
     # queue up a scroll
 #?     stash [pending scroll]
-    *screen <- put *screen, pending-scroll?:offset, 1/true
+    *screen <- put *screen, pending-scroll?:offset, true
     row <- subtract row, 1  # update cursor as if scroll already happened
   }
   *screen <- put *screen, cursor-row:offset, row
@@ -455,7 +455,7 @@ scenario print-character-at-bottom-right [
     10:num/raw <- get *fake-screen, cursor-row:offset
     11:num/raw <- get *fake-screen, cursor-column:offset
     12:num/raw <- get *fake-screen, top-idx:offset
-    13:num/raw <- get *fake-screen, pending-scroll?:offset
+    13:bool/raw <- get *fake-screen, pending-scroll?:offset
     cell:&:@:screen-cell <- get *fake-screen, data:offset
     20:@:screen-cell/raw <- copy *cell
   ]
@@ -607,7 +607,7 @@ def move-cursor screen:&:screen, new-row:num, new-column:num -> screen:&:screen
     scroll?:bool <- greater-or-equal new-column, width
     break-if scroll?
 #?     stash [resetting pending-scroll?]
-    *screen <- put *screen, pending-scroll?:offset, 0/false
+    *screen <- put *screen, pending-scroll?:offset, false
   }
 ]
 
@@ -884,8 +884,14 @@ def print screen:&:screen, n:bool -> screen:&:screen [
     break-if bg-color-found?
     bg-color <- copy 0/black
   }
-  n2:num <- copy n
-  screen <- print screen, n2, color, bg-color
+  {
+    break-if n
+    screen <- print screen, [false], color, bg-color
+  }
+  {
+    break-unless n
+    screen <- print screen, [true], color, bg-color
+  }
 ]
 
 def print screen:&:screen, n:&:_elem -> screen:&:screen [
diff --git a/084console.mu b/084console.mu
index 6aee5702..bd18226a 100644
--- a/084console.mu
+++ b/084console.mu
@@ -44,16 +44,16 @@ def read-event console:&:console -> result:event, found?:bool, quit?:bool, conso
       done?:bool <- greater-or-equal current-event-index, max
       break-unless done?
       dummy:&:event <- new event:type
-      return *dummy, 1/found, 1/quit
+      return *dummy, true/found, true/quit
     }
     result <- index *buf, current-event-index
     current-event-index <- add current-event-index, 1
     *console <- put *console, current-event-index:offset, current-event-index
-    return result, 1/found, 0/quit
+    return result, true/found, false/quit
   }
   switch  # real event source is infrequent; avoid polling it too much
   result:event, found?:bool <- check-for-interaction
-  return result, found?, 0/quit
+  return result, found?, false/quit
 ]
 
 # variant of read-event for just keyboard events. Discards everything that
@@ -66,8 +66,8 @@ def read-key console:&:console -> result:char, found?:bool, quit?:bool, console:
   return-if quit?, 0, found?, quit?
   return-unless found?, 0, found?, quit?
   c:char, converted?:bool <- maybe-convert x, text:variant
-  return-unless converted?, 0, 0/found, 0/quit
-  return c, 1/found, 0/quit
+  return-unless converted?, 0, false/found, false/quit
+  return c, true/found, false/quit
 ]
 
 def send-keys-to-channel console:&:console, chan:&:sink:char, screen:&:screen -> console:&:console, chan:&:sink:char, screen:&:screen [
@@ -99,6 +99,6 @@ def wait-for-event console:&:console -> console:&:console [
 def has-more-events? console:&:console -> result:bool [
   local-scope
   load-inputs
-  return-if console, 0/false  # fake events are processed as soon as they arrive
+  return-if console, false  # fake events are processed as soon as they arrive
   result <- interactions-left?
 ]
diff --git a/088file.mu b/088file.mu
index a7a3ba77..d9c3391d 100644
--- a/088file.mu
+++ b/088file.mu
@@ -21,7 +21,7 @@ container resource [
 def start-reading resources:&:resources, filename:text -> contents:&:source:char, error?:bool [
   local-scope
   load-inputs
-  error? <- copy 0/false
+  error? <- copy false
   {
     break-unless resources
     # fake file system
@@ -30,7 +30,7 @@ def start-reading resources:&:resources, filename:text -> contents:&:source:char
   }
   # real file system
   file:num <- $open-file-for-reading filename
-  return-unless file, 0/contents, 1/error?
+  return-unless file, 0/contents, true/error
   contents:&:source:char, sink:&:sink:char <- new-channel 30
   start-running receive-from-file file, sink
 ]
@@ -53,7 +53,7 @@ def slurp resources:&:resources, filename:text -> contents:text, error?:bool [
 def start-reading-from-fake-resource resources:&:resources, resource:text -> contents:&:source:char, error?:bool [
   local-scope
   load-inputs
-  error? <- copy 0/no-error
+  error? <- copy false
   i:num <- copy 0
   data:&:@:resource <- get *resources, data:offset
   len:num <- length *data
@@ -70,7 +70,7 @@ def start-reading-from-fake-resource resources:&:resources, resource:text -> con
     start-running receive-from-text curr-contents, sink
     return
   }
-  return 0/not-found, 1/error
+  return 0/not-found, true/error-found
 ]
 
 def receive-from-file file:num, sink:&:sink:char -> sink:&:sink:char [
@@ -105,7 +105,7 @@ def receive-from-text contents:text, sink:&:sink:char -> sink:&:sink:char [
 def start-writing resources:&:resources, filename:text -> sink:&:sink:char, routine-id:num, error?:bool [
   local-scope
   load-inputs
-  error? <- copy 0/false
+  error? <- copy false
   source:&:source:char, sink:&:sink:char <- new-channel 30
   {
     break-unless resources
@@ -115,7 +115,7 @@ def start-writing resources:&:resources, filename:text -> sink:&:sink:char, rout
   }
   # real file system
   file:num <- $open-file-for-writing filename
-  return-unless file, 0/sink, 0/routine-id, 1/error?
+  return-unless file, 0/sink, 0/routine-id, true/error
   {
     break-if file
     msg:text <- append [no such file: ] filename
@@ -128,7 +128,7 @@ def dump resources:&:resources, filename:text, contents:text -> resources:&:reso
   local-scope
   load-inputs
   # todo: really create an empty file
-  return-unless contents, resources, 0/no-error
+  return-unless contents, resources, false/no-error
   sink-file:&:sink:char, write-routine:num, error?:bool <- start-writing resources, filename
   return-if error?
   i:num <- copy 0
diff --git a/chessboard.mu b/chessboard.mu
index 3797c805..74cda69a 100644
--- a/chessboard.mu
+++ b/chessboard.mu
@@ -259,7 +259,7 @@ def read-move stdin:&:source:char, screen:&:screen -> result:&:move, quit?:bool,
   return-if error?, 0/dummy
   *result <- put *result, from-rank:offset, from-rank
   error? <- expect-from-channel stdin, 45/dash, screen
-  return-if error?, 0/dummy, 0/quit
+  return-if error?, 0/dummy, false/quit
   to-file:num, quit?, error? <- read-file stdin, screen
   return-if quit?, 0/dummy
   return-if error?, 0/dummy
@@ -269,7 +269,7 @@ def read-move stdin:&:source:char, screen:&:screen -> result:&:move, quit?:bool,
   return-if error?, 0/dummy
   *result <- put *result, to-rank:offset, to-rank
   error? <- expect-from-channel stdin, 10/newline, screen
-  return-if error?, 0/dummy, 0/quit
+  return-if error?, 0/dummy, false/quit
 ]
 
 # valid values for file: 0-7
@@ -277,18 +277,18 @@ def read-file stdin:&:source:char, screen:&:screen -> file:num, quit:bool, error
   local-scope
   load-inputs
   c:char, eof?:bool, stdin <- read stdin
-  return-if eof?, 0/dummy, 1/quit, 0/error
+  return-if eof?, 0/dummy, true/quit, false/no-error
   q-pressed?:bool <- equal c, 81/Q
-  return-if q-pressed?, 0/dummy, 1/quit, 0/error
+  return-if q-pressed?, 0/dummy, true/quit, false/no-error
   q-pressed? <- equal c, 113/q
-  return-if q-pressed?, 0/dummy, 1/quit, 0/error
+  return-if q-pressed?, 0/dummy, true/quit, false/no-error
   empty-fake-keyboard?:bool <- equal c, 0/eof
-  return-if empty-fake-keyboard?, 0/dummy, 1/quit, 0/error
+  return-if empty-fake-keyboard?, 0/dummy, true/quit, false/no-error
   {
     newline?:bool <- equal c, 10/newline
     break-unless newline?
     print screen, [that's not enough]
-    return 0/dummy, 0/quit, 1/error
+    return 0/dummy, false/don't-quit, true/error
   }
   file:num <- subtract c, 97/a
   # 'a' <= file <= 'h'
@@ -298,16 +298,16 @@ def read-file stdin:&:source:char, screen:&:screen -> file:num, quit:bool, error
     print screen, [file too low: ]
     print screen, c
     cursor-to-next-line screen
-    return 0/dummy, 0/quit, 1/error
+    return 0/dummy, false/don't-quit, true/error
   }
   {
     below-max:bool <- lesser-than file, 8
     break-if below-max
     print screen, [file too high: ]
     print screen, c
-    return 0/dummy, 0/quit, 1/error
+    return 0/dummy, false/don't-quit, true/error
   }
-  return file, 0/quit, 0/error
+  return file, false/don't-quit, false/no-error
 ]
 
 # valid values for rank: 0-7
@@ -315,18 +315,18 @@ def read-rank stdin:&:source:char, screen:&:screen -> rank:num, quit?:bool, erro
   local-scope
   load-inputs
   c:char, eof?:bool, stdin <- read stdin
-  return-if eof?, 0/dummy, 1/quit, 0/error
+  return-if eof?, 0/dummy, true/quit, false/no-error
   q-pressed?:bool <- equal c, 81/Q
-  return-if q-pressed?, 0/dummy, 1/quit, 0/error
+  return-if q-pressed?, 0/dummy, true/quit, false/no-error
   q-pressed? <- equal c, 113/q
-  return-if q-pressed?, 0/dummy, 1/quit, 0/error
+  return-if q-pressed?, 0/dummy, true/quit, false/no-error
   empty-fake-keyboard?:bool <- equal c, 0/eof
-  return-if empty-fake-keyboard?, 0/dummy, 1/quit, 0/error
+  return-if empty-fake-keyboard?, 0/dummy, true/quit, false/no-error
   {
     newline?:bool <- equal c, 10  # newline
     break-unless newline?
     print screen, [that's not enough]
-    return 0/dummy, 0/quit, 1/error
+    return 0/dummy, false/don't-quite, true/error
   }
   rank:num <- subtract c, 49/'1'
   # assert'1' <= rank <= '8'
@@ -335,16 +335,16 @@ def read-rank stdin:&:source:char, screen:&:screen -> rank:num, quit?:bool, erro
     break-if above-min
     print screen, [rank too low: ]
     print screen, c
-    return 0/dummy, 0/quit, 1/error
+    return 0/dummy, false/don't-quite, true/error
   }
   {
     below-max:bool <- lesser-or-equal rank, 7
     break-if below-max
     print screen, [rank too high: ]
     print screen, c
-    return 0/dummy, 0/quit, 1/error
+    return 0/dummy, false/don't-quite, true/error
   }
-  return rank, 0/quit, 0/error
+  return rank, false/don't-quite, false/no-error
 ]
 
 # read a character from the given channel and check that it's what we expect
@@ -353,7 +353,7 @@ def expect-from-channel stdin:&:source:char, expected:char, screen:&:screen -> r
   local-scope
   load-inputs
   c:char, eof?:bool, stdin <- read stdin
-  return-if eof? 1/true
+  return-if eof? true
   {
     match?:bool <- equal c, expected
     break-if match?
diff --git a/continuation2.mu b/continuation2.mu
index 88870957..b71e9a11 100644
--- a/continuation2.mu
+++ b/continuation2.mu
@@ -31,7 +31,7 @@ def create-yielder l:&:list:num -> n:num, done?:bool [
   load-inputs
   return-continuation-until-mark 100/mark
   done? <- equal l, 0/nil
-  return-if done?, 0/false
+  return-if done?, false
   n <- first l
   l <- rest l
 ]
diff --git a/continuation4.mu b/continuation4.mu
index 34c8de71..d4eb0641 100644
--- a/continuation4.mu
+++ b/continuation4.mu
@@ -43,5 +43,5 @@ def create-yielder l:&:list:num -> n:num, done?:bool [
   # return. Calling functions should stop calling its continuation after this
   # point.
   return-continuation-until-mark 100/mark, -1, done?
-  assert 0/false, [called too many times, ran out of continuations to return]
+  assert false, [called too many times, ran out of continuations to return]
 ]
diff --git a/continuation5.mu b/continuation5.mu
index b2b7e09c..4ae05614 100644
--- a/continuation5.mu
+++ b/continuation5.mu
@@ -45,5 +45,5 @@ def create-yielder l:&:list:num -> n:num, done?:bool [
     loop
   }
   return-continuation-until-mark 100/mark, -1, done?
-  assert 0/false, [called too many times, ran out of continuations to return]
+  assert false, [called too many times, ran out of continuations to return]
 ]
diff --git a/edit/002-typing.mu b/edit/002-typing.mu
index 47885c4f..a67fcf3c 100644
--- a/edit/002-typing.mu
+++ b/edit/002-typing.mu
@@ -50,23 +50,23 @@ def editor-event-loop screen:&:screen, console:&:console, editor:&:editor -> scr
 def move-cursor editor:&:editor, screen:&:screen, t:touch-event -> in-focus?:bool, editor:&:editor [
   local-scope
   load-inputs
-  return-unless editor, 0/false
+  return-unless editor, false
   click-row:num <- get t, row:offset
-  return-unless click-row, 0/false  # ignore clicks on 'menu'
+  return-unless click-row, false  # ignore clicks on 'menu'
   click-column:num <- get t, column:offset
   left:num <- get *editor, left:offset
   too-far-left?:bool <- lesser-than click-column, left
-  return-if too-far-left?, 0/false
+  return-if too-far-left?, false
   right:num <- get *editor, right:offset
   too-far-right?:bool <- greater-than click-column, right
-  return-if too-far-right?, 0/false
+  return-if too-far-right?, false
   # position cursor
   <begin-move-cursor>
   editor <- snap-cursor editor, screen, click-row, click-column
   undo-coalesce-tag:num <- copy 0/never
   <end-move-cursor>
   # gain focus
-  return 1/true
+  return true
 ]
 
 # Variant of 'render' that only moves the cursor (coordinates and
@@ -166,7 +166,7 @@ def snap-cursor editor:&:editor, screen:&:screen, target-row:num, target-column:
 def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render?:bool, screen:&:screen, editor:&:editor [
   local-scope
   load-inputs
-  return-unless editor, 0/don't-render
+  return-unless editor, false/don't-render
   screen-width:num <- screen-width screen
   screen-height:num <- screen-height screen
   left:num <- get *editor, left:offset
@@ -185,7 +185,7 @@ def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render
     <handle-special-character>
     # ignore any other special characters
     regular-character?:bool <- greater-or-equal c, 32/space
-    return-unless regular-character?, 0/don't-render
+    return-unless regular-character?, false/don't-render
     # otherwise type it in
     <begin-insert-character>
     go-render? <- insert-at-cursor editor, c, screen
@@ -197,7 +197,7 @@ def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render
   assert is-keycode?, [event was of unknown type; neither keyboard nor mouse]
   # handlers for each special key will go here
   <handle-special-key>
-  return 1/go-render
+  return true/go-render
 ]
 
 def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool, editor:&:editor, screen:&:screen [
@@ -232,7 +232,7 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
     break-if overflow?
     move-cursor screen, save-row, save-column
     print screen, c
-    return 0/don't-render
+    return false/don't-render
   }
   {
     # not at right margin? print the character and rest of line
@@ -245,7 +245,7 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
     {
       # hit right margin? give up and let caller render
       at-right?:bool <- greater-than curr-column, right
-      return-if at-right?, 1/go-render
+      return-if at-right?, true/go-render
       break-unless curr
       # newline? done.
       currc:char <- get *curr, value:offset
@@ -256,9 +256,9 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
       curr <- next curr
       loop
     }
-    return 0/don't-render
+    return false/don't-render
   }
-  return 1/go-render
+  return true/go-render
 ]
 
 # helper for tests
@@ -708,7 +708,7 @@ after <insert-character-special-case> [
       at-end-of-line? <- equal next-character, 10/newline
     }
     # break unless ((eol? and at-wrap?) or (~eol? and just-before-wrap?))
-    move-cursor-to-next-line?:bool <- copy 0/false
+    move-cursor-to-next-line?:bool <- copy false
     {
       break-if at-end-of-line?
       move-cursor-to-next-line? <- copy just-before-wrap?
@@ -735,7 +735,7 @@ after <insert-character-special-case> [
       break-unless below-screen?
       <scroll-down>
     }
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -829,7 +829,7 @@ container editor [
 ]
 
 after <editor-initialization> [
-  *result <- put *result, indent?:offset, 1/true
+  *result <- put *result, indent?:offset, true
 ]
 
 scenario editor-moves-cursor-down-after-inserting-newline [
@@ -859,7 +859,7 @@ after <handle-special-character> [
     <begin-insert-enter>
     insert-new-line-and-indent editor, screen
     <end-insert-enter>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -885,7 +885,7 @@ def insert-new-line-and-indent editor:&:editor, screen:&:screen -> editor:&:edit
   {
     below-screen?:bool <- greater-or-equal cursor-row, screen-height  # must be equal, never greater
     break-unless below-screen?
-    <scroll-down>
+    <scroll-down2>
     cursor-row <- subtract cursor-row, 1  # bring back into screen range
     *editor <- put *editor, cursor-row:offset, cursor-row
   }
@@ -915,16 +915,16 @@ def at-start-of-wrapped-line? editor:&:editor -> result:bool [
   left:num <- get *editor, left:offset
   cursor-column:num <- get *editor, cursor-column:offset
   cursor-at-left?:bool <- equal cursor-column, left
-  return-unless cursor-at-left?, 0/false
+  return-unless cursor-at-left?, false
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   before-before-cursor:&:duplex-list:char <- prev before-cursor
-  return-unless before-before-cursor, 0/false  # cursor is at start of editor
+  return-unless before-before-cursor, false  # cursor is at start of editor
   char-before-cursor:char <- get *before-cursor, value:offset
   cursor-after-newline?:bool <- equal char-before-cursor, 10/newline
-  return-if cursor-after-newline?, 0/false
+  return-if cursor-after-newline?, false
   # if cursor is at left margin and not at start, but previous character is not a newline,
   # then we're at start of a wrapped line
-  return 1/true
+  return true
 ]
 
 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
@@ -1095,8 +1095,8 @@ after <handle-special-key> [
   {
     paste-start?:bool <- equal k, 65507/paste-start
     break-unless paste-start?
-    *editor <- put *editor, indent?:offset, 0/false
-    return 1/go-render
+    *editor <- put *editor, indent?:offset, false
+    return true/go-render
   }
 ]
 
@@ -1104,8 +1104,8 @@ after <handle-special-key> [
   {
     paste-end?:bool <- equal k, 65506/paste-end
     break-unless paste-end?
-    *editor <- put *editor, indent?:offset, 1/true
-    return 1/go-render
+    *editor <- put *editor, indent?:offset, true
+    return true/go-render
   }
 ]
 
diff --git a/edit/003-shortcuts.mu b/edit/003-shortcuts.mu
index 02ea77d0..b8f49731 100644
--- a/edit/003-shortcuts.mu
+++ b/edit/003-shortcuts.mu
@@ -113,7 +113,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   data:&:duplex-list:char <- get *editor, data:offset
   # if at start of text (before-cursor at § sentinel), return
   prev:&:duplex-list:char <- prev before-cursor
-  return-unless prev, 0/no-more-render, 0/nothing-deleted
+  return-unless prev, false/no-more-render, 0/nothing-deleted
   trace 10, [app], [delete-before-cursor]
   original-row:num <- get *editor, cursor-row:offset
   scroll?:bool <- move-cursor-coordinates-left editor
@@ -121,13 +121,13 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   data <- remove before-cursor, data  # will also neatly trim next/prev pointers in backspaced-cell/before-cursor
   before-cursor <- copy prev
   *editor <- put *editor, before-cursor:offset, before-cursor
-  return-if scroll?, 1/go-render
+  return-if scroll?, true/go-render
   screen-width:num <- screen-width screen
   cursor-row:num <- get *editor, cursor-row:offset
   cursor-column:num <- get *editor, cursor-column:offset
   # did we just backspace over a newline?
   same-row?:bool <- equal cursor-row, original-row
-  return-unless same-row?, 1/go-render
+  return-unless same-row?, true/go-render
   left:num <- get *editor, left:offset
   right:num <- get *editor, right:offset
   curr:&:duplex-list:char <- next before-cursor
@@ -136,7 +136,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   {
     # hit right margin? give up and let caller render
     at-right?:bool <- greater-or-equal curr-column, right
-    return-if at-right?, 1/go-render
+    return-if at-right?, true/go-render
     break-unless curr
     # newline? done.
     currc:char <- get *curr, value:offset
@@ -150,13 +150,13 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   # we're guaranteed not to be at the right margin
   space:char <- copy 32/space
   screen <- print screen, space
-  go-render? <- copy 0/false
+  go-render? <- copy false
 ]
 
 def move-cursor-coordinates-left editor:&:editor -> go-render?:bool, editor:&:editor [
   local-scope
   load-inputs
-  go-render?:bool <- copy 0/false
+  go-render?:bool <- copy false
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   cursor-row:num <- get *editor, cursor-row:offset
   cursor-column:num <- get *editor, cursor-column:offset
@@ -180,7 +180,7 @@ def move-cursor-coordinates-left editor:&:editor -> go-render?:bool, editor:&:ed
   {
     break-unless top-of-screen?
     <scroll-up>
-    go-render? <- copy 1/true
+    go-render? <- copy true
   }
   {
     # case 1: if previous character was newline, figure out how long the previous line is
@@ -376,11 +376,11 @@ def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, delete
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   data:&:duplex-list:char <- get *editor, data:offset
   deleted-cell:&:duplex-list:char <- next before-cursor
-  return-unless deleted-cell, 0/don't-render
+  return-unless deleted-cell, false/don't-render
   currc:char <- get *deleted-cell, value:offset
   data <- remove deleted-cell, data
   deleted-newline?:bool <- equal currc, 10/newline
-  return-if deleted-newline?, 1/go-render
+  return-if deleted-newline?, true/go-render
   # wasn't a newline? render rest of line
   curr:&:duplex-list:char <- next before-cursor  # refresh after remove above
   cursor-row:num <- get *editor, cursor-row:offset
@@ -391,7 +391,7 @@ def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, delete
   {
     # hit right margin? give up and let caller render
     at-right?:bool <- greater-or-equal curr-column, screen-width
-    return-if at-right?, 1/go-render
+    return-if at-right?, true/go-render
     break-unless curr
     currc:char <- get *curr, value:offset
     at-newline?:bool <- equal currc, 10/newline
@@ -404,7 +404,7 @@ def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, delete
   # we're guaranteed not to be at the right margin
   space:char <- copy 32/space
   screen <- print screen, space
-  go-render? <- copy 0/false
+  go-render? <- copy false
 ]
 
 # right arrow
@@ -468,11 +468,11 @@ def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-rende
     cursor-column <- copy left
     *editor <- put *editor, cursor-column:offset, cursor-column
     below-screen?:bool <- greater-or-equal cursor-row, screen-height  # must be equal
-    return-unless below-screen?, 0/don't-render
+    return-unless below-screen?, false/don't-render
     <scroll-down>
     cursor-row <- subtract cursor-row, 1  # bring back into screen range
     *editor <- put *editor, cursor-row:offset, cursor-row
-    return 1/go-render
+    return true/go-render
   }
   # if the line wraps, move cursor to start of next row
   {
@@ -491,16 +491,16 @@ def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-rende
     cursor-column <- copy left
     *editor <- put *editor, cursor-column:offset, cursor-column
     below-screen?:bool <- greater-or-equal cursor-row, screen-height  # must be equal
-    return-unless below-screen?, 0/no-more-render
+    return-unless below-screen?, false/no-more-render
     <scroll-down>
     cursor-row <- subtract cursor-row, 1  # bring back into screen range
     *editor <- put *editor, cursor-row:offset, cursor-row
-    return 1/go-render
+    return true/go-render
   }
   # otherwise move cursor one character right
   cursor-column <- add cursor-column, 1
   *editor <- put *editor, cursor-column:offset, cursor-column
-  go-render? <- copy 0/false
+  go-render? <- copy false
 ]
 
 scenario editor-moves-cursor-to-next-line-with-right-arrow [
@@ -722,7 +722,7 @@ after <handle-special-key> [
     trace 10, [app], [left arrow]
     # if not at start of text (before-cursor at § sentinel)
     prev:&:duplex-list:char <- prev before-cursor
-    return-unless prev, 0/don't-render
+    return-unless prev, false/don't-render
     <begin-move-cursor>
     go-render? <- move-cursor-coordinates-left editor
     before-cursor <- copy prev
@@ -1000,7 +1000,7 @@ after <handle-special-key> [
 def move-to-previous-line editor:&:editor -> go-render?:bool, editor:&:editor [
   local-scope
   load-inputs
-  go-render?:bool <- copy 0/false
+  go-render?:bool <- copy false
   cursor-row:num <- get *editor, cursor-row:offset
   cursor-column:num <- get *editor, cursor-column:offset
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
@@ -1056,7 +1056,7 @@ def move-to-previous-line editor:&:editor -> go-render?:bool, editor:&:editor [
     # if cursor already at top, scroll up
     break-unless already-at-top?
     <scroll-up>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -1411,7 +1411,7 @@ def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, edi
     break-if before-cursor
     {
       break-if at-bottom-of-screen?
-      return 0/don't-render
+      return false/don't-render
     }
     {
       break-unless at-bottom-of-screen?
@@ -1423,7 +1423,7 @@ def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, edi
     break-if next
     {
       break-if at-bottom-of-screen?
-      return 0/don't-render
+      return false/don't-render
     }
     {
       break-unless at-bottom-of-screen?
@@ -1452,7 +1452,7 @@ def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, edi
       break-if next
       {
         break-if at-bottom-of-screen?
-        return 0/don't-render
+        return false/don't-render
       }
       {
         break-unless at-bottom-of-screen?
@@ -1476,11 +1476,11 @@ def move-to-next-line editor:&:editor, screen-height:num -> go-render?:bool, edi
     *editor <- put *editor, before-cursor:offset, before-cursor
     *editor <- put *editor, cursor-column:offset, cursor-column
     *editor <- put *editor, cursor-row:offset, cursor-row
-    return 0/don't-render
+    return false/don't-render
   }
   +try-to-scroll
   <scroll-down>
-  go-render? <- copy 1/true
+  go-render? <- copy true
 ]
 
 scenario editor-adjusts-column-at-next-line [
@@ -1589,7 +1589,7 @@ after <handle-special-character> [
     move-to-start-of-screen-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1601,7 +1601,7 @@ after <handle-special-key> [
     move-to-start-of-screen-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1814,7 +1814,7 @@ after <handle-special-character> [
     move-to-end-of-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1826,7 +1826,7 @@ after <handle-special-key> [
     move-to-end-of-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -2025,7 +2025,7 @@ def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:
   {
     # if we have a wrapped line, give up and render the whole screen
     wrap?:bool <- greater-or-equal i, right
-    return-if wrap?, 1/go-render
+    return-if wrap?, true/go-render
     curr <- next curr
     break-unless curr
     c:char <- get *curr, value:offset
@@ -2041,11 +2041,11 @@ def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:
   left:num <- get *editor, left:offset
   end:num <- subtract right, left
   wrap?:bool <- greater-or-equal old-row-len, end
-  return-if wrap?, 1/go-render
+  return-if wrap?, true/go-render
   curr-line:text <- buffer-to-array buf
   curr-row:num <- get *editor, cursor-row:offset
   render-code screen, curr-line, curr-column, right, curr-row
-  return 0/dont-render
+  return false/dont-render
 ]
 
 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
@@ -2054,7 +2054,7 @@ def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor
   # compute range to delete
   init:&:duplex-list:char <- get *editor, data:offset
   top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
-  update-top-of-screen?:bool <- copy 0/false
+  update-top-of-screen?:bool <- copy false
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   start:&:duplex-list:char <- copy before-cursor
   end:&:duplex-list:char <- next before-cursor
@@ -2595,7 +2595,7 @@ def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:
   local-scope
   load-inputs
   # if we deleted nothing, there's nothing to render
-  return-unless deleted-cells, 0/dont-render
+  return-unless deleted-cells, false/dont-render
   # if the line used to wrap before, give up and render the whole screen
   curr-column:num <- get *editor, cursor-column:offset
   num-deleted-cells:num <- length deleted-cells
@@ -2604,9 +2604,9 @@ def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:
   right:num <- get *editor, right:offset
   end:num <- subtract right, left
   wrap?:bool <- greater-or-equal old-row-len, end
-  return-if wrap?, 1/go-render
+  return-if wrap?, true/go-render
   clear-line-until screen, right
-  return 0/dont-render
+  return false/dont-render
 ]
 
 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
@@ -2839,7 +2839,20 @@ after <scroll-down> [
   top-of-screen <- before-start-of-next-line top-of-screen, max
   *editor <- put *editor, top-of-screen:offset, top-of-screen
   no-movement?:bool <- equal old-top, top-of-screen
-  return-if no-movement?, 0/don't-render
+  return-if no-movement?, false/don't-render
+]
+
+after <scroll-down2> [
+  trace 10, [app], [scroll down]
+  top-of-screen:&:duplex-list:char <- get *editor, top-of-screen:offset
+  left:num <- get *editor, left:offset
+  right:num <- get *editor, right:offset
+  max:num <- subtract right, left
+  old-top:&:duplex-list:char <- copy top-of-screen
+  top-of-screen <- before-start-of-next-line top-of-screen, max
+  *editor <- put *editor, top-of-screen:offset, top-of-screen
+  no-movement?:bool <- equal old-top, top-of-screen
+  return-if no-movement?
 ]
 
 # Takes a pointer into the doubly-linked list, scans ahead at most 'max'
@@ -3210,7 +3223,7 @@ after <scroll-up> [
   top-of-screen <- before-previous-screen-line top-of-screen, editor
   *editor <- put *editor, top-of-screen:offset, top-of-screen
   no-movement?:bool <- equal old-top, top-of-screen
-  return-if no-movement?, 0/don't-render
+  return-if no-movement?, false/don't-render
 ]
 
 scenario editor-scrolls-up-past-wrapped-line-using-arrow-keys [
@@ -4262,7 +4275,7 @@ def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num ->
   curr:&:duplex-list:char <- copy line-start
   {
     render-all?:bool <- greater-or-equal i, end
-    return-if render-all?, 1/go-render
+    return-if render-all?, true/go-render
     break-unless curr
     c:char <- get *curr, value:offset
     newline?:bool <- equal c, 10/newline
@@ -4274,7 +4287,7 @@ def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num ->
     loop
   }
   clear-line-until screen, right
-  return 0/dont-render
+  return false/dont-render
 ]
 
 def before-start-of-screen-line editor:&:editor -> result:&:duplex-list:char [
diff --git a/edit/004-programming-environment.mu b/edit/004-programming-environment.mu
index 669335ff..1065dd64 100644
--- a/edit/004-programming-environment.mu
+++ b/edit/004-programming-environment.mu
@@ -32,7 +32,7 @@ def new-programming-environment resources:&:resources, screen:&:screen, test-san
   current-sandbox:&:editor <- new-editor test-sandbox-editor-contents, sandbox-left, width/right
   *result <- put *result, recipes:offset, recipes
   *result <- put *result, current-sandbox:offset, current-sandbox
-  *result <- put *result, sandbox-in-focus?:offset, 0/false
+  *result <- put *result, sandbox-in-focus?:offset, false
   <programming-environment-initialization>
 ]
 
@@ -45,8 +45,8 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources:
   # if we fall behind we'll stop updating the screen, but then we have to
   # render the entire screen when we catch up.
   # todo: test this
-  render-recipes-on-no-more-events?:bool <- copy 0/false
-  render-sandboxes-on-no-more-events?:bool <- copy 0/false
+  render-recipes-on-no-more-events?:bool <- copy false
+  render-sandboxes-on-no-more-events?:bool <- copy false
   {
     # looping over each (keyboard or touch) event as it occurs
     +next-event
@@ -113,12 +113,12 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources:
         break-if more-events?
         {
           break-unless render-recipes-on-no-more-events?
-          render-recipes-on-no-more-events? <- copy 0/false
+          render-recipes-on-no-more-events? <- copy false
           screen <- render-recipes screen, env, render
         }
         {
           break-unless render-sandboxes-on-no-more-events?
-          render-sandboxes-on-no-more-events? <- copy 0/false
+          render-sandboxes-on-no-more-events? <- copy false
           screen <- render-sandbox-side screen, env, render
         }
       }
diff --git a/edit/005-sandbox.mu b/edit/005-sandbox.mu
index 0cba13b9..ae8561a9 100644
--- a/edit/005-sandbox.mu
+++ b/edit/005-sandbox.mu
@@ -201,7 +201,7 @@ def update-recipes env:&:environment, resources:&:resources, screen:&:screen ->
   in:text <- editor-contents recipes
   resources <- dump resources, [lesson/recipes.mu], in
   reload in
-  errors-found? <- copy 0/false
+  errors-found? <- copy false
 ]
 
 # replaced in a later layer
diff --git a/edit/006-sandbox-copy.mu b/edit/006-sandbox-copy.mu
index 72f320f6..04d22ab5 100644
--- a/edit/006-sandbox-copy.mu
+++ b/edit/006-sandbox-copy.mu
@@ -142,7 +142,7 @@ def should-attempt-copy? click-row:num, click-column:num, env:&:environment -> r
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'copy' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -150,7 +150,7 @@ def should-attempt-copy? click-row:num, click-column:num, env:&:environment -> r
   sandbox-right-margin:num <- get *first-sandbox, right:offset
   _, _, copy-button-left:num, copy-button-right:num <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin
   copy-button-vertical-area?:bool <- within-range? click-column, copy-button-left, copy-button-right
-  return-unless copy-button-vertical-area?, 0/false
+  return-unless copy-button-vertical-area?, false
   # finally, is sandbox editor empty?
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   result <- empty-editor? current-sandbox
@@ -161,15 +161,15 @@ def try-copy-sandbox click-row:num, env:&:environment -> clicked-on-copy-button?
   load-inputs
   # identify the sandbox to copy, if the click was actually on the 'copy' button
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
-  clicked-on-copy-button? <- copy 1/true
+  return-unless sandbox, false
+  clicked-on-copy-button? <- copy true
   text:text <- get *sandbox, data:offset
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   current-sandbox <- insert-text current-sandbox, text
   # reset scroll
   *env <- put *env, render-from:offset, -1
   # position cursor in sandbox editor
-  *env <- put *env, sandbox-in-focus?:offset, 1/true
+  *env <- put *env, sandbox-in-focus?:offset, true
 ]
 
 def find-sandbox env:&:environment, click-row:num -> result:&:sandbox [
@@ -193,9 +193,9 @@ def click-on-sandbox-area? click-row:num, click-column:num, env:&:environment ->
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   sandbox-left-margin:num <- get *current-sandbox, left:offset
   on-sandbox-side?:bool <- greater-or-equal click-column, sandbox-left-margin
-  return-unless on-sandbox-side?, 0/false
+  return-unless on-sandbox-side?, false
   first-sandbox:&:sandbox <- get *env, sandbox:offset
-  return-unless first-sandbox, 0/false
+  return-unless first-sandbox, false
   first-sandbox-begins:num <- get *first-sandbox, starting-row-on-screen:offset
   result <- greater-or-equal click-row, first-sandbox-begins
 ]
@@ -349,7 +349,7 @@ after <global-touch> [
     break-unless copy?
     modified?:bool <- prepend-sandbox-into-recipe-side click-row, env
     break-unless modified?
-    *env <- put *env, sandbox-in-focus?:offset, 0/false
+    *env <- put *env, sandbox-in-focus?:offset, false
     screen <- render-recipes screen, env, render
     screen <- update-cursor screen, recipes, current-sandbox, sandbox-in-focus?, env
     loop +next-event
@@ -362,7 +362,7 @@ def should-copy-to-recipe? click-row:num, click-column:num, env:&:environment ->
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'copy' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -376,7 +376,7 @@ def prepend-sandbox-into-recipe-side click-row:num, env:&:environment -> clicked
   local-scope
   load-inputs
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
+  return-unless sandbox, false
   recipe-editor:&:editor <- get *env, recipes:offset
   recipe-data:&:duplex-list:char <- get *recipe-editor, data:offset
   # make the newly inserted code easy to delineate
@@ -391,5 +391,5 @@ def prepend-sandbox-into-recipe-side click-row:num, env:&:environment -> clicked
   *recipe-editor <- put *recipe-editor, before-cursor:offset, recipe-data
   *recipe-editor <- put *recipe-editor, cursor-row:offset, 1
   *recipe-editor <- put *recipe-editor, cursor-column:offset, 0
-  return 1/true
+  return true
 ]
diff --git a/edit/007-sandbox-delete.mu b/edit/007-sandbox-delete.mu
index 0e599758..5e7989fb 100644
--- a/edit/007-sandbox-delete.mu
+++ b/edit/007-sandbox-delete.mu
@@ -85,7 +85,7 @@ def should-attempt-delete? click-row:num, click-column:num, env:&:environment ->
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'copy' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -100,8 +100,8 @@ def try-delete-sandbox click-row:num, env:&:environment -> clicked-on-delete-but
   load-inputs
   # identify the sandbox to delete, if the click was actually on the 'delete' button
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
-  clicked-on-delete-button? <- copy 1/true
+  return-unless sandbox, false
+  clicked-on-delete-button? <- copy true
   env <- delete-sandbox env, sandbox
 ]
 
diff --git a/edit/008-sandbox-edit.mu b/edit/008-sandbox-edit.mu
index ab4f1f63..57cdbc0d 100644
--- a/edit/008-sandbox-edit.mu
+++ b/edit/008-sandbox-edit.mu
@@ -125,7 +125,7 @@ def should-attempt-edit? click-row:num, click-column:num, env:&:environment -> r
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, click-column, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'edit' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -133,7 +133,7 @@ def should-attempt-edit? click-row:num, click-column:num, env:&:environment -> r
   sandbox-right-margin:num <- get *first-sandbox, right:offset
   edit-button-left:num, edit-button-right:num, _ <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin
   edit-button-vertical-area?:bool <- within-range? click-column, edit-button-left, edit-button-right
-  return-unless edit-button-vertical-area?, 0/false
+  return-unless edit-button-vertical-area?, false
   # finally, is sandbox editor empty?
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   result <- empty-editor? current-sandbox
@@ -144,8 +144,8 @@ def try-edit-sandbox click-row:num, env:&:environment -> clicked-on-edit-button?
   load-inputs
   # identify the sandbox to edit, if the click was actually on the 'edit' button
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
-  clicked-on-edit-button? <- copy 1/true
+  return-unless sandbox, false
+  clicked-on-edit-button? <- copy true
   # 'edit' button = 'copy' button + 'delete' button
   text:text <- get *sandbox, data:offset
   current-sandbox:&:editor <- get *env, current-sandbox:offset
@@ -154,7 +154,7 @@ def try-edit-sandbox click-row:num, env:&:environment -> clicked-on-edit-button?
   # reset scroll
   *env <- put *env, render-from:offset, -1
   # position cursor in sandbox editor
-  *env <- put *env, sandbox-in-focus?:offset, 1/true
+  *env <- put *env, sandbox-in-focus?:offset, true
 ]
 
 scenario sandbox-with-print-can-be-edited [
diff --git a/edit/011-errors.mu b/edit/011-errors.mu
index 43f318d3..373193d6 100644
--- a/edit/011-errors.mu
+++ b/edit/011-errors.mu
@@ -17,10 +17,10 @@ def! update-recipes env:&:environment, resources:&:resources, screen:&:screen ->
   {
     break-unless recipe-errors
     update-status screen, [errors found     ], 1/red
-    errors-found? <- copy 1/true
+    errors-found? <- copy true
     return
   }
-  errors-found? <- copy 0/false
+  errors-found? <- copy false
 ]
 
 after <begin-run-sandboxes-on-F4> [
@@ -73,7 +73,7 @@ before <end-run-sandboxes> [
     error-index:num <- get *env, error-index:offset
     sandboxes-completed-successfully?:bool <- equal error-index, -1
     break-if sandboxes-completed-successfully?
-    errors-found? <- copy 1/true
+    errors-found? <- copy true
   }
 ]
 
diff --git a/edit/012-editor-undo.mu b/edit/012-editor-undo.mu
index 161e6843..42d325bd 100644
--- a/edit/012-editor-undo.mu
+++ b/edit/012-editor-undo.mu
@@ -76,7 +76,7 @@ after <handle-special-character> [
     redo <- push op, redo
     *editor <- put *editor, redo:offset, redo
     <handle-undo>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -94,7 +94,7 @@ after <handle-special-character> [
     undo <- push op, undo
     *editor <- put *editor, undo:offset, undo
     <handle-redo>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
diff --git a/exception1.mu b/exception1.mu
index 88916c57..dd60c744 100644
--- a/exception1.mu
+++ b/exception1.mu
@@ -7,8 +7,8 @@
 
 def main [
   local-scope
-  foo 0/no-exception
-  foo 1/raise-exception
+  foo false/no-exception
+  foo true/raise-exception
 ]
 
 # example showing exception handling
diff --git a/exception2.mu b/exception2.mu
index 48179dc2..f07c135b 100644
--- a/exception2.mu
+++ b/exception2.mu
@@ -13,8 +13,8 @@ exclusive-container error-or:_elem [
 
 def main [
   local-scope
-  foo 0/no-exception
-  foo 1/raise-exception
+  foo false/no-exception
+  foo true/raise-exception
 ]
 
 # example showing exception handling
diff --git a/lambda-to-mu.mu b/lambda-to-mu.mu
index 31edaf34..1d23cd46 100644
--- a/lambda-to-mu.mu
+++ b/lambda-to-mu.mu
@@ -56,14 +56,14 @@ def new-pair a:&:cell, b:&:cell -> result:&:cell [
 def is-atom? x:&:cell -> result:bool [
   local-scope
   load-inputs
-  return-unless x, 0/false
+  return-unless x, false
   _, result <- maybe-convert *x, atom:variant
 ]
 
 def is-pair? x:&:cell -> result:bool [
   local-scope
   load-inputs
-  return-unless x, 0/false
+  return-unless x, false
   _, result <- maybe-convert *x, pair:variant
 ]
 
@@ -97,7 +97,7 @@ def atom-match? x:&:cell, pat:text -> result:bool [
   local-scope
   load-inputs
   s:text, is-atom?:bool <- maybe-convert *x, atom:variant
-  return-unless is-atom?, 0/false
+  return-unless is-atom?, false
   result <- equal pat, s
 ]
 
diff --git a/mu.vim b/mu.vim
index 967136e2..6dfe6318 100644
--- a/mu.vim
+++ b/mu.vim
@@ -54,6 +54,7 @@ syntax match muLiteral %[^ ]\+:label/[^ ,]*\|[^ ]\+:label\>%
 syntax match muLiteral %[^ ]\+:type/[^ ,]*\|[^ ]\+:type\>%
 syntax match muLiteral %[^ ]\+:offset/[^ ,]*\|[^ ]\+:offset\>%
 syntax match muLiteral %[^ ]\+:variant/[^ ,]*\|[^ ]\+:variant\>%
+syntax match muLiteral % true\(\/[^ ]*\)\?\| false\(\/[^ ]*\)\?%  " literals will never be the first word in an instruction
 highlight link muLiteral Constant
 
 " sources of action at a distance
diff --git a/nqueens.mu b/nqueens.mu
index 030ba28b..9e9f4425 100644
--- a/nqueens.mu
+++ b/nqueens.mu
@@ -66,11 +66,11 @@ def conflicting-file? curr:square, queens:&:list:square -> result:bool [
     q:square <- first queens
     qfile:num <- get q, file:offset
     file-match?:bool <- equal curr-file, qfile
-    return-if file-match?, 1/conflict-found
+    return-if file-match?, true/conflict-found
     queens <- rest queens
     loop
   }
-  return 0/no-conflict-found
+  return false/no-conflict-found
 ]
 
 def conflicting-diagonal? curr:square, queens:&:list:square -> result:bool [
@@ -88,11 +88,11 @@ def conflicting-diagonal? curr:square, queens:&:list:square -> result:bool [
     rank-delta <- abs rank-delta
     file-delta <- abs file-delta
     diagonal-match?:bool <- equal rank-delta, file-delta
-    return-if diagonal-match?, 1/conflict-found
+    return-if diagonal-match?, true/conflict-found
     queens <- rest queens
     loop
   }
-  return 0/no-conflict-found
+  return false/no-conflict-found
 ]
 
 def main [
diff --git a/same-fringe.mu b/same-fringe.mu
index a1e619b7..b9235006 100644
--- a/same-fringe.mu
+++ b/same-fringe.mu
@@ -38,7 +38,7 @@ def same-fringe a:&:tree:_elem, b:&:tree:_elem -> result:bool [
     break-if a-done?
     break-if b-done?
     match?:bool <- equal x, y
-    return-unless match?, 0/false
+    return-unless match?, false
     loop
   }
   result <- and a-done?, b-done?
@@ -51,8 +51,8 @@ def process t:&:tree:_elem [
   return-continuation-until-mark 100/mark  # initial
   traverse t
   zero-val:&:_elem <- new _elem:type
-  return-continuation-until-mark 100/mark, *zero-val, 1/done  # final
-  assert 0/false, [continuation called past done]
+  return-continuation-until-mark 100/mark, *zero-val, true/done  # final
+  assert false, [continuation called past done]
 ]
 
 # core traversal
@@ -68,7 +68,7 @@ def traverse t:&:tree:_elem [
   return-if r
   # leaf
   v:_elem <- get *t, val:offset
-  return-continuation-until-mark 100/mark, v, 0/not-done
+  return-continuation-until-mark 100/mark, v, false/not-done
 ]
 
 # details
diff --git a/sandbox/002-typing.mu b/sandbox/002-typing.mu
index 47885c4f..a67fcf3c 100644
--- a/sandbox/002-typing.mu
+++ b/sandbox/002-typing.mu
@@ -50,23 +50,23 @@ def editor-event-loop screen:&:screen, console:&:console, editor:&:editor -> scr
 def move-cursor editor:&:editor, screen:&:screen, t:touch-event -> in-focus?:bool, editor:&:editor [
   local-scope
   load-inputs
-  return-unless editor, 0/false
+  return-unless editor, false
   click-row:num <- get t, row:offset
-  return-unless click-row, 0/false  # ignore clicks on 'menu'
+  return-unless click-row, false  # ignore clicks on 'menu'
   click-column:num <- get t, column:offset
   left:num <- get *editor, left:offset
   too-far-left?:bool <- lesser-than click-column, left
-  return-if too-far-left?, 0/false
+  return-if too-far-left?, false
   right:num <- get *editor, right:offset
   too-far-right?:bool <- greater-than click-column, right
-  return-if too-far-right?, 0/false
+  return-if too-far-right?, false
   # position cursor
   <begin-move-cursor>
   editor <- snap-cursor editor, screen, click-row, click-column
   undo-coalesce-tag:num <- copy 0/never
   <end-move-cursor>
   # gain focus
-  return 1/true
+  return true
 ]
 
 # Variant of 'render' that only moves the cursor (coordinates and
@@ -166,7 +166,7 @@ def snap-cursor editor:&:editor, screen:&:screen, target-row:num, target-column:
 def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render?:bool, screen:&:screen, editor:&:editor [
   local-scope
   load-inputs
-  return-unless editor, 0/don't-render
+  return-unless editor, false/don't-render
   screen-width:num <- screen-width screen
   screen-height:num <- screen-height screen
   left:num <- get *editor, left:offset
@@ -185,7 +185,7 @@ def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render
     <handle-special-character>
     # ignore any other special characters
     regular-character?:bool <- greater-or-equal c, 32/space
-    return-unless regular-character?, 0/don't-render
+    return-unless regular-character?, false/don't-render
     # otherwise type it in
     <begin-insert-character>
     go-render? <- insert-at-cursor editor, c, screen
@@ -197,7 +197,7 @@ def handle-keyboard-event screen:&:screen, editor:&:editor, e:event -> go-render
   assert is-keycode?, [event was of unknown type; neither keyboard nor mouse]
   # handlers for each special key will go here
   <handle-special-key>
-  return 1/go-render
+  return true/go-render
 ]
 
 def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool, editor:&:editor, screen:&:screen [
@@ -232,7 +232,7 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
     break-if overflow?
     move-cursor screen, save-row, save-column
     print screen, c
-    return 0/don't-render
+    return false/don't-render
   }
   {
     # not at right margin? print the character and rest of line
@@ -245,7 +245,7 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
     {
       # hit right margin? give up and let caller render
       at-right?:bool <- greater-than curr-column, right
-      return-if at-right?, 1/go-render
+      return-if at-right?, true/go-render
       break-unless curr
       # newline? done.
       currc:char <- get *curr, value:offset
@@ -256,9 +256,9 @@ def insert-at-cursor editor:&:editor, c:char, screen:&:screen -> go-render?:bool
       curr <- next curr
       loop
     }
-    return 0/don't-render
+    return false/don't-render
   }
-  return 1/go-render
+  return true/go-render
 ]
 
 # helper for tests
@@ -708,7 +708,7 @@ after <insert-character-special-case> [
       at-end-of-line? <- equal next-character, 10/newline
     }
     # break unless ((eol? and at-wrap?) or (~eol? and just-before-wrap?))
-    move-cursor-to-next-line?:bool <- copy 0/false
+    move-cursor-to-next-line?:bool <- copy false
     {
       break-if at-end-of-line?
       move-cursor-to-next-line? <- copy just-before-wrap?
@@ -735,7 +735,7 @@ after <insert-character-special-case> [
       break-unless below-screen?
       <scroll-down>
     }
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -829,7 +829,7 @@ container editor [
 ]
 
 after <editor-initialization> [
-  *result <- put *result, indent?:offset, 1/true
+  *result <- put *result, indent?:offset, true
 ]
 
 scenario editor-moves-cursor-down-after-inserting-newline [
@@ -859,7 +859,7 @@ after <handle-special-character> [
     <begin-insert-enter>
     insert-new-line-and-indent editor, screen
     <end-insert-enter>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -885,7 +885,7 @@ def insert-new-line-and-indent editor:&:editor, screen:&:screen -> editor:&:edit
   {
     below-screen?:bool <- greater-or-equal cursor-row, screen-height  # must be equal, never greater
     break-unless below-screen?
-    <scroll-down>
+    <scroll-down2>
     cursor-row <- subtract cursor-row, 1  # bring back into screen range
     *editor <- put *editor, cursor-row:offset, cursor-row
   }
@@ -915,16 +915,16 @@ def at-start-of-wrapped-line? editor:&:editor -> result:bool [
   left:num <- get *editor, left:offset
   cursor-column:num <- get *editor, cursor-column:offset
   cursor-at-left?:bool <- equal cursor-column, left
-  return-unless cursor-at-left?, 0/false
+  return-unless cursor-at-left?, false
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   before-before-cursor:&:duplex-list:char <- prev before-cursor
-  return-unless before-before-cursor, 0/false  # cursor is at start of editor
+  return-unless before-before-cursor, false  # cursor is at start of editor
   char-before-cursor:char <- get *before-cursor, value:offset
   cursor-after-newline?:bool <- equal char-before-cursor, 10/newline
-  return-if cursor-after-newline?, 0/false
+  return-if cursor-after-newline?, false
   # if cursor is at left margin and not at start, but previous character is not a newline,
   # then we're at start of a wrapped line
-  return 1/true
+  return true
 ]
 
 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts
@@ -1095,8 +1095,8 @@ after <handle-special-key> [
   {
     paste-start?:bool <- equal k, 65507/paste-start
     break-unless paste-start?
-    *editor <- put *editor, indent?:offset, 0/false
-    return 1/go-render
+    *editor <- put *editor, indent?:offset, false
+    return true/go-render
   }
 ]
 
@@ -1104,8 +1104,8 @@ after <handle-special-key> [
   {
     paste-end?:bool <- equal k, 65506/paste-end
     break-unless paste-end?
-    *editor <- put *editor, indent?:offset, 1/true
-    return 1/go-render
+    *editor <- put *editor, indent?:offset, true
+    return true/go-render
   }
 ]
 
diff --git a/sandbox/003-shortcuts.mu b/sandbox/003-shortcuts.mu
index c12429f0..db19443d 100644
--- a/sandbox/003-shortcuts.mu
+++ b/sandbox/003-shortcuts.mu
@@ -113,7 +113,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   data:&:duplex-list:char <- get *editor, data:offset
   # if at start of text (before-cursor at § sentinel), return
   prev:&:duplex-list:char <- prev before-cursor
-  return-unless prev, 0/no-more-render, 0/nothing-deleted
+  return-unless prev, false/no-more-render, 0/nothing-deleted
   trace 10, [app], [delete-before-cursor]
   original-row:num <- get *editor, cursor-row:offset
   move-cursor-coordinates-left editor
@@ -126,7 +126,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   cursor-column:num <- get *editor, cursor-column:offset
   # did we just backspace over a newline?
   same-row?:bool <- equal cursor-row, original-row
-  return-unless same-row?, 1/go-render
+  return-unless same-row?, true/go-render
   left:num <- get *editor, left:offset
   right:num <- get *editor, right:offset
   curr:&:duplex-list:char <- next before-cursor
@@ -135,7 +135,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   {
     # hit right margin? give up and let caller render
     at-right?:bool <- greater-or-equal curr-column, right
-    return-if at-right?, 1/go-render
+    return-if at-right?, true/go-render
     break-unless curr
     # newline? done.
     currc:char <- get *curr, value:offset
@@ -149,7 +149,7 @@ def delete-before-cursor editor:&:editor, screen:&:screen -> go-render?:bool, ba
   # we're guaranteed not to be at the right margin
   space:char <- copy 32/space
   screen <- print screen, space
-  go-render? <- copy 0/false
+  go-render? <- copy false
 ]
 
 def move-cursor-coordinates-left editor:&:editor -> editor:&:editor [
@@ -373,11 +373,11 @@ def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, delete
   before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset
   data:&:duplex-list:char <- get *editor, data:offset
   deleted-cell:&:duplex-list:char <- next before-cursor
-  return-unless deleted-cell, 0/don't-render
+  return-unless deleted-cell, false/don't-render
   currc:char <- get *deleted-cell, value:offset
   data <- remove deleted-cell, data
   deleted-newline?:bool <- equal currc, 10/newline
-  return-if deleted-newline?, 1/go-render
+  return-if deleted-newline?, true/go-render
   # wasn't a newline? render rest of line
   curr:&:duplex-list:char <- next before-cursor  # refresh after remove above
   cursor-row:num <- get *editor, cursor-row:offset
@@ -388,7 +388,7 @@ def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, delete
   {
     # hit right margin? give up and let caller render
     at-right?:bool <- greater-or-equal curr-column, screen-width
-    return-if at-right?, 1/go-render
+    return-if at-right?, true/go-render
     break-unless curr
     currc:char <- get *curr, value:offset
     at-newline?:bool <- equal currc, 10/newline
@@ -401,7 +401,7 @@ def delete-at-cursor editor:&:editor, screen:&:screen -> go-render?:bool, delete
   # we're guaranteed not to be at the right margin
   space:char <- copy 32/space
   screen <- print screen, space
-  go-render? <- copy 0/false
+  go-render? <- copy false
 ]
 
 # right arrow
@@ -465,10 +465,10 @@ def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-rende
     cursor-column <- copy left
     *editor <- put *editor, cursor-column:offset, cursor-column
     below-screen?:bool <- greater-or-equal cursor-row, screen-height  # must be equal
-    return-unless below-screen?, 0/don't-render
+    return-unless below-screen?, false/don't-render
     cursor-row <- subtract cursor-row, 1  # bring back into screen range
     *editor <- put *editor, cursor-row:offset, cursor-row
-    return 1/go-render
+    return true/go-render
   }
   # if the line wraps, move cursor to start of next row
   {
@@ -487,15 +487,15 @@ def move-cursor-coordinates-right editor:&:editor, screen-height:num -> go-rende
     cursor-column <- copy left
     *editor <- put *editor, cursor-column:offset, cursor-column
     below-screen?:bool <- greater-or-equal cursor-row, screen-height  # must be equal
-    return-unless below-screen?, 0/no-more-render
+    return-unless below-screen?, false/no-more-render
     cursor-row <- subtract cursor-row, 1  # bring back into screen range
     *editor <- put *editor, cursor-row:offset, cursor-row
-    return 1/go-render
+    return true/go-render
   }
   # otherwise move cursor one character right
   cursor-column <- add cursor-column, 1
   *editor <- put *editor, cursor-column:offset, cursor-column
-  go-render? <- copy 0/false
+  go-render? <- copy false
 ]
 
 scenario editor-moves-cursor-to-next-line-with-right-arrow [
@@ -717,7 +717,7 @@ after <handle-special-key> [
     trace 10, [app], [left arrow]
     # if not at start of text (before-cursor at § sentinel)
     prev:&:duplex-list:char <- prev before-cursor
-    return-unless prev, 0/don't-render
+    return-unless prev, false/don't-render
     <begin-move-cursor>
     move-cursor-coordinates-left editor
     before-cursor <- copy prev
@@ -1511,7 +1511,7 @@ after <handle-special-character> [
     move-to-start-of-screen-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1523,7 +1523,7 @@ after <handle-special-key> [
     move-to-start-of-screen-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1736,7 +1736,7 @@ after <handle-special-character> [
     move-to-end-of-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1748,7 +1748,7 @@ after <handle-special-key> [
     move-to-end-of-line editor
     undo-coalesce-tag:num <- copy 0/never
     <end-move-cursor>
-    return 0/don't-render
+    return false/don't-render
   }
 ]
 
@@ -1947,7 +1947,7 @@ def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:
   {
     # if we have a wrapped line, give up and render the whole screen
     wrap?:bool <- greater-or-equal i, right
-    return-if wrap?, 1/go-render
+    return-if wrap?, true/go-render
     curr <- next curr
     break-unless curr
     c:char <- get *curr, value:offset
@@ -1963,11 +1963,11 @@ def minimal-render-for-ctrl-u screen:&:screen, editor:&:editor, deleted-cells:&:
   left:num <- get *editor, left:offset
   end:num <- subtract right, left
   wrap?:bool <- greater-or-equal old-row-len, end
-  return-if wrap?, 1/go-render
+  return-if wrap?, true/go-render
   curr-line:text <- buffer-to-array buf
   curr-row:num <- get *editor, cursor-row:offset
   render-code screen, curr-line, curr-column, right, curr-row
-  return 0/dont-render
+  return false/dont-render
 ]
 
 def delete-to-start-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
@@ -2332,7 +2332,7 @@ def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:
   local-scope
   load-inputs
   # if we deleted nothing, there's nothing to render
-  return-unless deleted-cells, 0/dont-render
+  return-unless deleted-cells, false/dont-render
   # if the line used to wrap before, give up and render the whole screen
   curr-column:num <- get *editor, cursor-column:offset
   num-deleted-cells:num <- length deleted-cells
@@ -2341,9 +2341,9 @@ def minimal-render-for-ctrl-k screen:&:screen, editor:&:editor, deleted-cells:&:
   right:num <- get *editor, right:offset
   end:num <- subtract right, left
   wrap?:bool <- greater-or-equal old-row-len, end
-  return-if wrap?, 1/go-render
+  return-if wrap?, true/go-render
   clear-line-until screen, right
-  return 0/dont-render
+  return false/dont-render
 ]
 
 def delete-to-end-of-line editor:&:editor -> result:&:duplex-list:char, editor:&:editor [
@@ -2613,7 +2613,7 @@ def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num ->
   curr:&:duplex-list:char <- copy line-start
   {
     render-all?:bool <- greater-or-equal i, end
-    return-if render-all?, 1/go-render
+    return-if render-all?, true/go-render
     break-unless curr
     c:char <- get *curr, value:offset
     newline?:bool <- equal c, 10/newline
@@ -2625,7 +2625,7 @@ def render-line-from-start screen:&:screen, editor:&:editor, right-margin:num ->
     loop
   }
   clear-line-until screen, right
-  return 0/dont-render
+  return false/dont-render
 ]
 
 def before-start-of-screen-line editor:&:editor -> result:&:duplex-list:char [
diff --git a/sandbox/004-programming-environment.mu b/sandbox/004-programming-environment.mu
index dccd7c9a..1208d0e8 100644
--- a/sandbox/004-programming-environment.mu
+++ b/sandbox/004-programming-environment.mu
@@ -31,7 +31,7 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources:
   # if we fall behind we'll stop updating the screen, but then we have to
   # render the entire screen when we catch up.
   # todo: test this
-  render-all-on-no-more-events?:bool <- copy 0/false
+  render-all-on-no-more-events?:bool <- copy false
   {
     # looping over each (keyboard or touch) event as it occurs
     +next-event
@@ -86,7 +86,7 @@ def event-loop screen:&:screen, console:&:console, env:&:environment, resources:
       {
         break-if more-events?
         break-unless render-all-on-no-more-events?
-        render-all-on-no-more-events? <- copy 0/false
+        render-all-on-no-more-events? <- copy false
         screen <- render-all screen, env, render
       }
       screen <- update-cursor screen, current-sandbox, env
diff --git a/sandbox/005-sandbox.mu b/sandbox/005-sandbox.mu
index 4b56ad27..ae4372a1 100644
--- a/sandbox/005-sandbox.mu
+++ b/sandbox/005-sandbox.mu
@@ -188,7 +188,7 @@ def update-recipes env:&:environment, resources:&:resources, screen:&:screen ->
   load-inputs
   in:text <- slurp resources, [lesson/recipes.mu]
   reload in
-  errors-found? <- copy 0/false
+  errors-found? <- copy false
 ]
 
 # replaced in a later layer
diff --git a/sandbox/006-sandbox-copy.mu b/sandbox/006-sandbox-copy.mu
index 541618e6..4b7222f3 100644
--- a/sandbox/006-sandbox-copy.mu
+++ b/sandbox/006-sandbox-copy.mu
@@ -154,7 +154,7 @@ def should-attempt-copy? click-row:num, click-column:num, env:&:environment -> r
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'copy' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -162,7 +162,7 @@ def should-attempt-copy? click-row:num, click-column:num, env:&:environment -> r
   sandbox-right-margin:num <- get *first-sandbox, right:offset
   _, _, copy-button-left:num, copy-button-right:num, _ <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin
   copy-button-vertical-area?:bool <- within-range? click-column, copy-button-left, copy-button-right
-  return-unless copy-button-vertical-area?, 0/false
+  return-unless copy-button-vertical-area?, false
   # finally, is sandbox editor empty?
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   result <- empty-editor? current-sandbox
@@ -173,8 +173,8 @@ def try-copy-sandbox click-row:num, env:&:environment -> clicked-on-copy-button?
   load-inputs
   # identify the sandbox to copy, if the click was actually on the 'copy' button
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
-  clicked-on-copy-button? <- copy 1/true
+  return-unless sandbox, false
+  clicked-on-copy-button? <- copy true
   text:text <- get *sandbox, data:offset
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   current-sandbox <- insert-text current-sandbox, text
@@ -201,7 +201,7 @@ def click-on-sandbox-area? click-row:num, env:&:environment -> result:bool [
   local-scope
   load-inputs
   first-sandbox:&:sandbox <- get *env, sandbox:offset
-  return-unless first-sandbox, 0/false
+  return-unless first-sandbox, false
   first-sandbox-begins:num <- get *first-sandbox, starting-row-on-screen:offset
   result <- greater-or-equal click-row, first-sandbox-begins
 ]
diff --git a/sandbox/007-sandbox-delete.mu b/sandbox/007-sandbox-delete.mu
index 2e8ab759..01f01f42 100644
--- a/sandbox/007-sandbox-delete.mu
+++ b/sandbox/007-sandbox-delete.mu
@@ -82,7 +82,7 @@ def should-attempt-delete? click-row:num, click-column:num, env:&:environment ->
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'copy' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -97,8 +97,8 @@ def try-delete-sandbox click-row:num, env:&:environment -> clicked-on-delete-but
   load-inputs
   # identify the sandbox to delete, if the click was actually on the 'delete' button
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
-  clicked-on-delete-button? <- copy 1/true
+  return-unless sandbox, false
+  clicked-on-delete-button? <- copy true
   env <- delete-sandbox env, sandbox
 ]
 
diff --git a/sandbox/008-sandbox-edit.mu b/sandbox/008-sandbox-edit.mu
index 3cef65ce..fb3981bf 100644
--- a/sandbox/008-sandbox-edit.mu
+++ b/sandbox/008-sandbox-edit.mu
@@ -125,7 +125,7 @@ def should-attempt-edit? click-row:num, click-column:num, env:&:environment -> r
   load-inputs
   # are we below the sandbox editor?
   click-sandbox-area?:bool <- click-on-sandbox-area? click-row, env
-  return-unless click-sandbox-area?, 0/false
+  return-unless click-sandbox-area?, false
   # narrower, is the click in the columns spanning the 'edit' button?
   first-sandbox:&:editor <- get *env, current-sandbox:offset
   assert first-sandbox, [!!]
@@ -133,7 +133,7 @@ def should-attempt-edit? click-row:num, click-column:num, env:&:environment -> r
   sandbox-right-margin:num <- get *first-sandbox, right:offset
   edit-button-left:num, edit-button-right:num, _ <- sandbox-menu-columns sandbox-left-margin, sandbox-right-margin
   edit-button-vertical-area?:bool <- within-range? click-column, edit-button-left, edit-button-right
-  return-unless edit-button-vertical-area?, 0/false
+  return-unless edit-button-vertical-area?, false
   # finally, is sandbox editor empty?
   current-sandbox:&:editor <- get *env, current-sandbox:offset
   result <- empty-editor? current-sandbox
@@ -144,8 +144,8 @@ def try-edit-sandbox click-row:num, env:&:environment -> clicked-on-edit-button?
   load-inputs
   # identify the sandbox to edit, if the click was actually on the 'edit' button
   sandbox:&:sandbox <- find-sandbox env, click-row
-  return-unless sandbox, 0/false
-  clicked-on-edit-button? <- copy 1/true
+  return-unless sandbox, false
+  clicked-on-edit-button? <- copy true
   # 'edit' button = 'copy' button + 'delete' button
   text:text <- get *sandbox, data:offset
   current-sandbox:&:editor <- get *env, current-sandbox:offset
diff --git a/sandbox/011-errors.mu b/sandbox/011-errors.mu
index 893515bf..8678989f 100644
--- a/sandbox/011-errors.mu
+++ b/sandbox/011-errors.mu
@@ -15,10 +15,10 @@ def! update-recipes env:&:environment, resources:&:resources, screen:&:screen ->
   {
     break-unless recipe-errors
     update-status screen, [errors found     ], 1/red
-    errors-found? <- copy 1/true
+    errors-found? <- copy true
     return
   }
-  errors-found? <- copy 0/false
+  errors-found? <- copy false
 ]
 
 before <end-render-components> [
@@ -47,7 +47,7 @@ before <end-run-sandboxes> [
     error-index:num <- get *env, error-index:offset
     sandboxes-completed-successfully?:bool <- equal error-index, -1
     break-if sandboxes-completed-successfully?
-    errors-found? <- copy 1/true
+    errors-found? <- copy true
   }
 ]
 
diff --git a/sandbox/012-editor-undo.mu b/sandbox/012-editor-undo.mu
index e5782f0c..23448ea2 100644
--- a/sandbox/012-editor-undo.mu
+++ b/sandbox/012-editor-undo.mu
@@ -74,7 +74,7 @@ after <handle-special-character> [
     redo <- push op, redo
     *editor <- put *editor, redo:offset, redo
     <handle-undo>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
@@ -92,7 +92,7 @@ after <handle-special-character> [
     undo <- push op, undo
     *editor <- put *editor, undo:offset, undo
     <handle-redo>
-    return 1/go-render
+    return true/go-render
   }
 ]
 
diff --git a/vimrc.vim b/vimrc.vim
index 972754f9..218da388 100644
--- a/vimrc.vim
+++ b/vimrc.vim
@@ -31,6 +31,7 @@ function! HighlightTangledFile()
   syntax match muLiteral %[^ ]\+:type/[^ ,]*\|[^ ]\+:type\>%
   syntax match muLiteral %[^ ]\+:offset/[^ ,]*\|[^ ]\+:offset\>%
   syntax match muLiteral %[^ ]\+:variant/[^ ,]*\|[^ ]\+:variant\>%
+  syntax keyword muLiteral true false null
   highlight link muLiteral Constant
   syntax match muAssign " <- \|\<raw\>" | highlight link muAssign SpecialChar
   " common keywords