about summary refs log tree commit diff stats
path: root/047check_type_by_name.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-10-22 12:08:10 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-10-22 12:08:10 -0700
commitada5eb55cb185edf30dcac48b25cc485d44677ef (patch)
treee147838f053a582e33146ac4fc4ab30ac8434e0e /047check_type_by_name.cc
parenta6deb48067f8049922f16ed3489896f7749fd39f (diff)
downloadmu-ada5eb55cb185edf30dcac48b25cc485d44677ef.tar.gz
3552
Stop requiring jump instructions to explicitly provide a ':label' type
for jump targets.

This has been a source of repeated confusion for my students:
  a) They'd add the ':label' to the label definition rather than the
  jump target (label use)
  b) They'd spend time thinking about whether the initial '+' prefix was
  part of the label name.

In the process I cleaned up a couple of things:

  - the space of names is more cleanly partitioned into labels and
    non-labels (clarifying that '_' and '-' are non-label prefixes)
  - you can't use label names as regular variables anymore
  - you can infer the type of a label just from its name
Diffstat (limited to '047check_type_by_name.cc')
-rw-r--r--047check_type_by_name.cc24
1 files changed, 24 insertions, 0 deletions
diff --git a/047check_type_by_name.cc b/047check_type_by_name.cc
index 62a6107c..96a703ce 100644
--- a/047check_type_by_name.cc
+++ b/047check_type_by_name.cc
@@ -37,6 +37,10 @@ void check_or_set_types_by_name(const recipe_ordinal r) {
 
 void deduce_missing_type(set<reagent>& known, reagent& x) {
   if (x.type) return;
+  if (is_jump_target(x.name)) {
+    x.type = new type_tree("label");
+    return;
+  }
   if (known.find(x) == known.end()) return;
   x.type = new type_tree(*known.find(x)->type);
   trace(9992, "transform") << x.name << " <= " << names_to_string(x.type) << end();
@@ -46,6 +50,11 @@ void check_type(set<reagent>& known, const reagent& x, const recipe& caller) {
   if (is_literal(x)) return;
   if (is_integer(x.name)) return;  // if you use raw locations you're probably doing something unsafe
   if (!x.type) return;  // might get filled in by other logic later
+  if (is_jump_target(x.name)) {
+    if (!x.type->atom || x.type->name != "label")
+      raise << maybe(caller.name) << "non-label '" << x.name << "' must begin with a letter\n" << end();
+    return;
+  }
   if (known.find(x) == known.end()) {
     trace(9992, "transform") << x.name << " => " << names_to_string(x.type) << end();
     known.insert(x);
@@ -90,6 +99,14 @@ def main [
 # x is in location 1
 +mem: storing 2 in location 1
 
+:(scenario transform_fills_in_missing_label_type)
+def main [
+  jump +target
+  1:num <- copy 0
+  +target
+]
+-mem: storing 0 in location 1
+
 :(scenario transform_fails_on_missing_types_in_first_mention)
 % Hide_errors = true;
 def main [
@@ -98,6 +115,13 @@ def main [
 ]
 +error: main: missing type for 'x' in 'x <- copy 1'
 
+:(scenario transform_fails_on_wrong_type_for_label)
+% Hide_errors = true;
+def main [
+  +foo:num <- copy 34
+]
++error: main: non-label '+foo' must begin with a letter
+
 :(scenario typo_in_address_type_fails)
 % Hide_errors = true;
 def main [