about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-10-28 13:08:26 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-10-28 13:19:41 -0700
commit1fa530589eee7b668d936e77c1c430f18907a481 (patch)
tree95a506363d74231d1e85b402549b0ca6a466391e
parent48086e1044a8c000eb7977621cde0813f7bb70cf (diff)
downloadmu-1fa530589eee7b668d936e77c1c430f18907a481.tar.gz
2299 - check types of ingredients in calls
Still very incomplete:

a) we perform the check at runtime

b) tests for edit and sandbox apps no longer work; we can't fix them
until we get type parameters in both containers and recipes (because
list and list operations need to become generic).
-rw-r--r--021check_instruction.cc17
-rw-r--r--034call.cc9
-rw-r--r--035call_ingredient.cc17
-rw-r--r--036call_reply.cc6
-rw-r--r--038scheduler.cc11
-rw-r--r--071print.mu12
-rw-r--r--072scenario_screen.cc18
-rw-r--r--073scenario_screen_test.mu8
-rw-r--r--074console.mu10
-rw-r--r--075scenario_console.cc20
-rw-r--r--076scenario_console_test.mu8
-rw-r--r--chessboard.mu36
12 files changed, 108 insertions, 64 deletions
diff --git a/021check_instruction.cc b/021check_instruction.cc
index 2fdaad60..f3dd89d8 100644
--- a/021check_instruction.cc
+++ b/021check_instruction.cc
@@ -88,10 +88,27 @@ bool types_match(reagent lhs, reagent rhs) {
 // (trees perform the same check recursively on each subtree)
 bool types_match(type_tree* lhs, type_tree* rhs) {
   if (!lhs) return true;
+  if (!rhs || rhs->value == 0) {
+    if (lhs->value == Type_ordinal["array"]) return false;
+    if (lhs->value == Type_ordinal["address"]) return false;
+    return size_of(rhs) == size_of(lhs);
+  }
   if (lhs->value != rhs->value) return false;
   return types_match(lhs->left, rhs->left) && types_match(lhs->right, rhs->right);
 }
 
+// hacky version that allows 0 addresses
+bool types_match(const reagent lhs, const type_tree* rhs, const vector<double>& data) {
+  if (is_dummy(lhs)) return true;
+  if (!rhs || rhs->value == 0) {
+    if (lhs.type->value == Type_ordinal["array"]) return false;
+    if (lhs.type->value == Type_ordinal["address"]) return scalar(data) && data.at(0) == 0;
+    return size_of(rhs) == size_of(lhs);
+  }
+  if (lhs.type->value != rhs->value) return false;
+  return types_match(lhs.type->left, rhs->left) && types_match(lhs.type->right, rhs->right);
+}
+
 bool is_raw(const reagent& r) {
   return has_property(r, "raw");
 }
diff --git a/034call.cc b/034call.cc
index f33e6053..df358e6e 100644
--- a/034call.cc
+++ b/034call.cc
@@ -42,6 +42,9 @@ struct call {
     running_step_index = 0;
     // End call Constructor
   }
+  ~call() {
+    // End call Destructor
+  }
 };
 typedef list<call> call_stack;
 
@@ -84,7 +87,11 @@ inline const string& current_recipe_name() {
 :(replace{} "inline const instruction& current_instruction()")
 inline const instruction& current_instruction() {
   assert(!Current_routine->calls.empty());
-  return Recipe[current_call().running_recipe].steps.at(current_call().running_step_index);
+  return to_instruction(current_call());
+}
+:(code)
+inline const instruction& to_instruction(const call& call) {
+  return Recipe[call.running_recipe].steps.at(call.running_step_index);
 }
 
 :(after "Defined Recipe Checks")
diff --git a/035call_ingredient.cc b/035call_ingredient.cc
index 41e7811b..eb899899 100644
--- a/035call_ingredient.cc
+++ b/035call_ingredient.cc
@@ -30,7 +30,14 @@ next_ingredient_to_process = 0;
 :(before "End Call Housekeeping")
 for (long long int i = 0; i < SIZE(ingredients); ++i) {
   current_call().ingredient_atoms.push_back(ingredients.at(i));
-  current_call().ingredient_types.push_back(call_instruction.ingredients.at(i).type);
+  reagent ingredient = call_instruction.ingredients.at(i);
+  canonize_type(ingredient);
+  current_call().ingredient_types.push_back(ingredient.type);
+  ingredient.type = NULL;  // release long-lived pointer
+}
+:(before "End call Destructor")
+for (long long int i = 0; i < SIZE(ingredient_types); ++i) {
+  delete ingredient_types.at(i);
 }
 
 :(before "End Primitive Recipe Declarations")
@@ -49,6 +56,14 @@ case NEXT_INGREDIENT: {
 case NEXT_INGREDIENT: {
   assert(!Current_routine->calls.empty());
   if (current_call().next_ingredient_to_process < SIZE(current_call().ingredient_atoms)) {
+    reagent product = current_instruction().products.at(0);
+    canonize_type(product);
+    if (!types_match(product,
+                     current_call().ingredient_types.at(current_call().next_ingredient_to_process),
+                     current_call().ingredient_atoms.at(current_call().next_ingredient_to_process)
+                     )) {
+      raise_error << maybe(current_recipe_name()) << "wrong type for ingredient " << current_instruction().products.at(0).original_string << '\n' << end();
+    }
     products.push_back(
         current_call().ingredient_atoms.at(current_call().next_ingredient_to_process));
     assert(SIZE(products) == 1);  products.resize(2);  // push a new vector
diff --git a/036call_reply.cc b/036call_reply.cc
index 98a1eb33..8a4653ca 100644
--- a/036call_reply.cc
+++ b/036call_reply.cc
@@ -115,14 +115,14 @@ recipe test1 [
 +error: main: 'same-as-ingredient' product from call to test1 must be 1:number rather than 2:number
 
 :(scenario reply_same_as_ingredient_dummy)
-% Hide_errors = true;
+# % Hide_errors = true;
 recipe main [
   1:number <- copy 0
   _ <- test1 1:number  # call with different ingredient and product
 ]
 recipe test1 [
-  10:address:number <- next-ingredient
-  reply 10:address:number/same-as-ingredient:0
+  10:number <- next-ingredient
+  reply 10:number/same-as-ingredient:0
 ]
 $error: 0
 
diff --git a/038scheduler.cc b/038scheduler.cc
index 66bd2d8b..d02aa43e 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -94,8 +94,8 @@ void skip_to_next_routine() {
 
 string current_routine_label() {
   ostringstream result;
-  call_stack calls = Current_routine->calls;
-  for (call_stack::iterator p = calls.begin(); p != calls.end(); ++p) {
+  const call_stack& calls = Current_routine->calls;
+  for (call_stack::const_iterator p = calls.begin(); p != calls.end(); ++p) {
     if (p != calls.begin()) result << '/';
     result << Recipe[p->running_recipe].name;
   }
@@ -161,8 +161,13 @@ case START_RUNNING: {
   routine* new_routine = new routine(ingredients.at(0).at(0));
   new_routine->parent_index = Current_routine_index;
   // populate ingredients
-  for (long long int i = 1; i < SIZE(current_instruction().ingredients); ++i)
+  for (long long int i = 1; i < SIZE(current_instruction().ingredients); ++i) {
     new_routine->calls.front().ingredient_atoms.push_back(ingredients.at(i));
+    reagent ingredient = current_instruction().ingredients.at(i);
+    canonize_type(ingredient);
+    new_routine->calls.front().ingredient_types.push_back(ingredient.type);
+    ingredient.type = NULL;  // release long-lived pointer
+  }
   Routines.push_back(new_routine);
   products.resize(1);
   products.at(0).push_back(new_routine->id);
diff --git a/071print.mu b/071print.mu
index d1cea5cb..c3d08180 100644
--- a/071print.mu
+++ b/071print.mu
@@ -524,7 +524,7 @@ recipe cursor-to-start-of-line [
 
 recipe cursor-to-next-line [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   screen <- cursor-down screen
   screen <- cursor-to-start-of-line screen
   reply screen/same-as-ingredient:0
@@ -560,7 +560,7 @@ recipe screen-height [
 
 recipe hide-cursor [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   # if x exists (not real display), do nothing
   {
     break-unless screen
@@ -573,7 +573,7 @@ recipe hide-cursor [
 
 recipe show-cursor [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   # if x exists (not real display), do nothing
   {
     break-unless screen
@@ -586,7 +586,7 @@ recipe show-cursor [
 
 recipe hide-screen [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   # if x exists (not real display), do nothing
   # todo: help test this
   {
@@ -600,7 +600,7 @@ recipe hide-screen [
 
 recipe show-screen [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   # if x exists (not real display), do nothing
   # todo: help test this
   {
@@ -663,7 +663,7 @@ scenario print-string-stops-at-right-margin [
 
 recipe print-integer [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   n:number <- next-ingredient
   color:number, color-found?:boolean <- next-ingredient
   {
diff --git a/072scenario_screen.cc b/072scenario_screen.cc
index ed2ddad3..f9536bc5 100644
--- a/072scenario_screen.cc
+++ b/072scenario_screen.cc
@@ -9,7 +9,7 @@
 scenario screen-in-scenario [
   assume-screen 5/width, 3/height
   run [
-    screen:address <- print-character screen:address, 97  # 'a'
+    screen:address:screen <- print-character screen:address:screen, 97  # 'a'
   ]
   screen-should-contain [
   #  01234
@@ -23,8 +23,8 @@ scenario screen-in-scenario [
 scenario screen-in-scenario-unicode-color [
   assume-screen 5/width, 3/height
   run [
-    screen:address <- print-character screen:address, 955/greek-small-lambda, 1/red
-    screen:address <- print-character screen:address, 97/a
+    screen:address:screen <- print-character screen:address:screen, 955/greek-small-lambda, 1/red
+    screen:address:screen <- print-character screen:address:screen, 97/a
   ]
   screen-should-contain [
   #  01234
@@ -39,8 +39,8 @@ scenario screen-in-scenario-unicode-color [
 scenario screen-in-scenario-color [
   assume-screen 5/width, 3/height
   run [
-    screen:address <- print-character screen:address, 955/greek-small-lambda, 1/red
-    screen:address <- print-character screen:address, 97/a, 7/white
+    screen:address:screen <- print-character screen:address:screen, 955/greek-small-lambda, 1/red
+    screen:address:screen <- print-character screen:address:screen, 97/a, 7/white
   ]
   # screen-should-contain shows everything
   screen-should-contain [
@@ -72,7 +72,7 @@ scenario screen-in-scenario-color [
 scenario screen-in-scenario-error [
   assume-screen 5/width, 3/height
   run [
-    screen:address <- print-character screen:address, 97  # 'a'
+    screen:address:screen <- print-character screen:address:screen, 97  # 'a'
   ]
   screen-should-contain [
   #  01234
@@ -90,7 +90,7 @@ scenario screen-in-scenario-error [
 scenario screen-in-scenario-color [
   assume-screen 5/width, 3/height
   run [
-    screen:address <- print-character screen:address, 97/a, 1/red
+    screen:address:screen <- print-character screen:address:screen, 97/a, 1/red
   ]
   screen-should-contain-in-color 2/green, [
   #  01234
@@ -139,13 +139,13 @@ Name[r]["screen"] = SCREEN;
 
 :(before "End Rewrite Instruction(curr)")
 // rewrite `assume-screen width, height` to
-// `screen:address <- new-fake-screen width, height`
+// `screen:address:screen <- new-fake-screen width, height`
 if (curr.name == "assume-screen") {
   curr.operation = Recipe_ordinal["new-fake-screen"];
   curr.name = "new-fake-screen";
   assert(curr.operation);
   assert(curr.products.empty());
-  curr.products.push_back(reagent("screen:address"));
+  curr.products.push_back(reagent("screen:address:screen"));
   curr.products.at(0).set_value(SCREEN);
 }
 
diff --git a/073scenario_screen_test.mu b/073scenario_screen_test.mu
index b3fc6b04..1eb2c351 100644
--- a/073scenario_screen_test.mu
+++ b/073scenario_screen_test.mu
@@ -3,7 +3,7 @@
 scenario print-character-at-top-left-2 [
   assume-screen 3/width, 2/height
   run [
-    screen:address <- print-character screen:address, 97/a
+    screen:address:screen <- print-character screen:address:screen, 97/a
   ]
   screen-should-contain [
     .a  .
@@ -15,11 +15,11 @@ scenario clear-line-erases-printed-characters-2 [
   assume-screen 5/width, 3/height
   run [
     # print a character
-    screen:address <- print-character screen:address, 97/a
+    screen:address:screen <- print-character screen:address:screen, 97/a
     # move cursor to start of line
-    screen:address <- move-cursor screen:address, 0/row, 0/column
+    screen:address:screen <- move-cursor screen:address:screen, 0/row, 0/column
     # clear line
-    screen:address <- clear-line screen:address
+    screen:address:screen <- clear-line screen:address:screen
   ]
   screen-should-contain [
     .     .
diff --git a/074console.mu b/074console.mu
index e346f990..e713462b 100644
--- a/074console.mu
+++ b/074console.mu
@@ -63,7 +63,7 @@ recipe read-event [
 # newlines, tabs, ctrl-d..
 recipe read-key [
   local-scope
-  console:address <- next-ingredient
+  console:address:console <- next-ingredient
   x:event, console, found?:boolean, quit?:boolean <- read-event console
   reply-if quit?, 0, console/same-as-ingredient:0, found?, quit?
   reply-unless found?, 0, console/same-as-ingredient:0, found?, quit?
@@ -74,9 +74,9 @@ recipe read-key [
 
 recipe send-keys-to-channel [
   local-scope
-  console:address <- next-ingredient
+  console:address:console <- next-ingredient
   chan:address:channel <- next-ingredient
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   {
     c:character, console, found?:boolean, quit?:boolean <- read-key console
     loop-unless found?
@@ -91,7 +91,7 @@ recipe send-keys-to-channel [
 
 recipe wait-for-event [
   local-scope
-  console:address <- next-ingredient
+  console:address:console <- next-ingredient
   {
     _, console, found?:boolean <- read-event console
     loop-unless found?
@@ -102,7 +102,7 @@ recipe wait-for-event [
 # use this helper to skip rendering if there's lots of other events queued up
 recipe has-more-events? [
   local-scope
-  console:address <- next-ingredient
+  console:address:console <- next-ingredient
   {
     break-unless console
     # fake consoles should be plenty fast; never skip
diff --git a/075scenario_console.cc b/075scenario_console.cc
index 11438bf4..f8e3e1a1 100644
--- a/075scenario_console.cc
+++ b/075scenario_console.cc
@@ -11,10 +11,10 @@ scenario keyboard-in-scenario [
     type [abc]
   ]
   run [
-    1:character, console:address, 2:boolean <- read-key console:address
-    3:character, console:address, 4:boolean <- read-key console:address
-    5:character, console:address, 6:boolean <- read-key console:address
-    7:character, console:address, 8:boolean, 9:boolean <- read-key console:address
+    1:character, console:address:console, 2:boolean <- read-key console:address:console
+    3:character, console:address:console, 4:boolean <- read-key console:address:console
+    5:character, console:address:console, 6:boolean <- read-key console:address:console
+    7:character, console:address:console, 8:boolean, 9:boolean <- read-key console:address:console
   ]
   memory-should-contain [
     1 <- 97  # 'a'
@@ -182,15 +182,15 @@ scenario events-in-scenario [
   ]
   run [
     # 3 keyboard events; each event occupies 4 locations
-    1:event <- read-event console:address
-    5:event <- read-event console:address
-    9:event <- read-event console:address
+    1:event <- read-event console:address:console
+    5:event <- read-event console:address:console
+    9:event <- read-event console:address:console
     # mouse click
-    13:event <- read-event console:address
+    13:event <- read-event console:address:console
     # non-character keycode
-    17:event <- read-event console:address
+    17:event <- read-event console:address:console
     # final keyboard event
-    21:event <- read-event console:address
+    21:event <- read-event console:address:console
   ]
   memory-should-contain [
     1 <- 0  # 'text'
diff --git a/076scenario_console_test.mu b/076scenario_console_test.mu
index bfa72861..754f1166 100644
--- a/076scenario_console_test.mu
+++ b/076scenario_console_test.mu
@@ -7,10 +7,10 @@ scenario read-key-in-mu [
     type [abc]
   ]
   run [
-    1:character, console:address, 2:boolean <- read-key console:address
-    3:character, console:address, 4:boolean <- read-key console:address
-    5:character, console:address, 6:boolean <- read-key console:address
-    7:character, console:address, 8:boolean <- read-key console:address
+    1:character, console:address:console, 2:boolean <- read-key console:address:console
+    3:character, console:address:console, 4:boolean <- read-key console:address:console
+    5:character, console:address:console, 6:boolean <- read-key console:address:console
+    7:character, console:address:console, 8:boolean <- read-key console:address:console
   ]
   memory-should-contain [
     1 <- 97  # 'a'
diff --git a/chessboard.mu b/chessboard.mu
index 359ac9d3..669e096f 100644
--- a/chessboard.mu
+++ b/chessboard.mu
@@ -34,7 +34,7 @@ scenario print-board-and-read-move [
 ]
   ]
   run [
-    screen:address, console:address <- chessboard screen:address, console:address
+    screen:address:screen, console:address:console <- chessboard screen:address:screen, console:address:console
     # icon for the cursor
     screen <- print-character screen, 9251/␣
   ]
@@ -68,8 +68,8 @@ scenario print-board-and-read-move [
 
 recipe chessboard [
   local-scope
-  screen:address <- next-ingredient
-  console:address <- next-ingredient
+  screen:address:screen <- next-ingredient
+  console:address:console <- next-ingredient
   board:address:array:address:array:character <- initial-position
   # hook up stdin
   stdin:address:channel <- new-channel 10/capacity
@@ -151,7 +151,7 @@ recipe new-file [
 
 recipe print-board [
   local-scope
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   board:address:array:address:array:character <- next-ingredient
   row:number <- copy 7  # start printing from the top of the board
   # print each row
@@ -217,7 +217,7 @@ scenario printing-the-board [
   assume-screen 30/width, 12/height
   run [
     1:address:array:address:array:character/board <- initial-position
-    screen:address <- print-board screen:address, 1:address:array:address:array:character/board
+    screen:address:screen <- print-board screen:address:screen, 1:address:array:address:array:character/board
   ]
   screen-should-contain [
   #  012345678901234567890123456789
@@ -246,12 +246,12 @@ container move [
   to-rank:number
 ]
 
-# result:address:move, quit?:boolean, error?:boolean <- read-move stdin:address:channel, screen:address
+# result:address:move, quit?:boolean, error?:boolean <- read-move stdin:address:channel, screen:address:screen
 # prints only error messages to screen
 recipe read-move [
   local-scope
   stdin:address:channel <- next-ingredient
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   from-file:number, quit?:boolean, error?:boolean <- read-file stdin, screen
   reply-if quit?, 0/dummy, quit?, error?
   reply-if error?, 0/dummy, quit?, error?
@@ -278,12 +278,12 @@ recipe read-move [
   reply result, quit?, error?
 ]
 
-# file:number, quit:boolean, error:boolean <- read-file stdin:address:channel, screen:address
+# file:number, quit:boolean, error:boolean <- read-file stdin:address:channel, screen:address:screen
 # valid values for file: 0-7
 recipe read-file [
   local-scope
   stdin:address:channel <- next-ingredient
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   c:character, stdin <- read stdin
   {
     q-pressed?:boolean <- equal c, 81/Q
@@ -329,12 +329,12 @@ recipe read-file [
   reply file, 0/quit, 0/error
 ]
 
-# rank:number <- read-rank stdin:address:channel, screen:address
+# rank:number <- read-rank stdin:address:channel, screen:address:screen
 # valid values: 0-7, -1 (quit), -2 (error)
 recipe read-rank [
   local-scope
   stdin:address:channel <- next-ingredient
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   c:character, stdin <- read stdin
   {
     q-pressed?:boolean <- equal c, 8/Q
@@ -380,7 +380,7 @@ recipe expect-from-channel [
   local-scope
   stdin:address:channel <- next-ingredient
   expected:character <- next-ingredient
-  screen:address <- next-ingredient
+  screen:address:screen <- next-ingredient
   c:character, stdin <- read stdin
   {
     match?:boolean <- equal c, expected
@@ -396,7 +396,7 @@ scenario read-move-blocking [
   assume-screen 20/width, 2/height
   run [
     1:address:channel <- new-channel 2
-    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address
+    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address:screen
     # 'read-move' is waiting for input
     wait-for-routine 2:number
     3:number <- routine-state 2:number/id
@@ -468,7 +468,7 @@ scenario read-move-quit [
   assume-screen 20/width, 2/height
   run [
     1:address:channel <- new-channel 2
-    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address
+    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address:screen
     # 'read-move' is waiting for input
     wait-for-routine 2:number
     3:number <- routine-state 2:number/id
@@ -495,7 +495,7 @@ scenario read-move-illegal-file [
   assume-screen 20/width, 2/height
   run [
     1:address:channel <- new-channel 2
-    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address
+    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address:screen
     # 'read-move' is waiting for input
     wait-for-routine 2:number
     3:number <- routine-state 2:number/id
@@ -516,7 +516,7 @@ scenario read-move-illegal-rank [
   assume-screen 20/width, 2/height
   run [
     1:address:channel <- new-channel 2
-    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address
+    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address:screen
     # 'read-move' is waiting for input
     wait-for-routine 2:number
     3:number <- routine-state 2:number/id
@@ -538,7 +538,7 @@ scenario read-move-empty [
   assume-screen 20/width, 2/height
   run [
     1:address:channel <- new-channel 2
-    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address
+    2:number/routine <- start-running read-move:recipe, 1:address:channel, screen:address:screen
     # 'read-move' is waiting for input
     wait-for-routine 2:number
     3:number <- routine-state 2:number/id
@@ -587,7 +587,7 @@ scenario making-a-move [
     7:address:number <- get-address *3:address:move, to-rank:offset
     *7:address:number <- copy 3/'4'
     2:address:array:address:array:character/board <- make-move 2:address:array:address:array:character/board, 3:address:move
-    screen:address <- print-board screen:address, 2:address:array:address:array:character/board
+    screen:address:screen <- print-board screen:address:screen, 2:address:array:address:array:character/board
   ]
   screen-should-contain [
   #  012345678901234567890123456789