about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--020run.cc1
-rw-r--r--037call_reply.cc3
-rw-r--r--038scheduler.cc17
-rw-r--r--039wait.cc11
-rw-r--r--chessboard.mu176
5 files changed, 206 insertions, 2 deletions
diff --git a/020run.cc b/020run.cc
index 0f196b82..c2a44019 100644
--- a/020run.cc
+++ b/020run.cc
@@ -96,6 +96,7 @@ void run_current_routine()
 //?     cout << "DDD: " << current_instruction().to_string() << '\n'; //? 1
     current_step_index() = instruction_counter+1;
   }
+  stop_running_current_routine:;
 }
 
 //: Some helpers.
diff --git a/037call_reply.cc b/037call_reply.cc
index a13c88e5..81f9c7c2 100644
--- a/037call_reply.cc
+++ b/037call_reply.cc
@@ -21,7 +21,8 @@ Recipe_number["reply"] = REPLY;
 case REPLY: {
   const instruction& reply_inst = current_instruction();  // save pointer into recipe before pop
   Current_routine->calls.pop();
-  assert(!Current_routine->calls.empty());
+  // just in case 'main' returns a value, drop it for now
+  if (Current_routine->calls.empty()) goto stop_running_current_routine;
   const instruction& caller_instruction = current_instruction();
   // make reply results available to caller
   copy(ingredients.begin(), ingredients.end(), inserter(products, products.begin()));
diff --git a/038scheduler.cc b/038scheduler.cc
index b8c51e40..012a1761 100644
--- a/038scheduler.cc
+++ b/038scheduler.cc
@@ -240,3 +240,20 @@ case ROUTINE_STATE: {
   products.at(0).push_back(result);
   break;
 }
+
+:(before "End Primitive Recipe Declarations")
+RESTART,
+:(before "End Primitive Recipe Numbers")
+Recipe_number["restart"] = RESTART;
+:(before "End Primitive Recipe Implementations")
+case RESTART: {
+  assert(ingredients.at(0).size() == 1);  // routine id must be scalar
+  index_t id = ingredients.at(0).at(0);
+  for (index_t i = 0; i < Routines.size(); ++i) {
+    if (Routines.at(i)->id == id) {
+      Routines.at(i)->state = RUNNING;
+      break;
+    }
+  }
+  break;
+}
diff --git a/039wait.cc b/039wait.cc
index 8d9086d6..89871022 100644
--- a/039wait.cc
+++ b/039wait.cc
@@ -41,6 +41,7 @@ case WAIT_FOR_LOCATION: {
   Current_routine->waiting_on_location = loc.value;
   Current_routine->old_value_of_wating_location = Memory[loc.value];
   trace("run") << "waiting for location " << loc.value << " to change from " << Memory[loc.value];
+//?   trace("schedule") << Current_routine->id << ": waiting for location " << loc.value << " to change from " << Memory[loc.value]; //? 1
   break;
 }
 
@@ -48,8 +49,13 @@ case WAIT_FOR_LOCATION: {
 
 :(before "End Scheduler State Transitions")
 for (index_t i = 0; i < Routines.size(); ++i) {
+//?   trace("schedule") << "wake up loop 1: routine " << Routines.at(i)->id << " has state " << Routines.at(i)->state; //? 1
   if (Routines.at(i)->state != WAITING) continue;
-  if (Memory[Routines.at(i)->waiting_on_location] &&
+//?   trace("schedule") << "waiting on location: " << Routines.at(i)->waiting_on_location; //? 1
+//?   if (Routines.at(i)->waiting_on_location) //? 1
+//?     trace("schedule") << "checking routine " << Routines.at(i)->id << " waiting on location " //? 1
+//?       << Routines.at(i)->waiting_on_location << ": " << Memory[Routines.at(i)->waiting_on_location] << " vs " << Routines[i]->old_value_of_wating_location; //? 1
+  if (Routines.at(i)->waiting_on_location &&
       Memory[Routines.at(i)->waiting_on_location] != Routines.at(i)->old_value_of_wating_location) {
     trace("schedule") << "waking up routine\n";
     Routines.at(i)->state = RUNNING;
@@ -93,6 +99,9 @@ case WAIT_FOR_ROUTINE: {
 }
 
 :(before "End Scheduler State Transitions")
+// Wake up any routines waiting for other routines to go to sleep.
+// Important: this must come after the scheduler loop above giving routines
+// waiting for locations to change a chance to wake up.
 for (index_t i = 0; i < Routines.size(); ++i) {
   if (Routines.at(i)->state != WAITING) continue;
   if (!Routines.at(i)->waiting_on_routine) continue;
diff --git a/chessboard.mu b/chessboard.mu
index d4b00b6f..d9ed4618 100644
--- a/chessboard.mu
+++ b/chessboard.mu
@@ -1,3 +1,7 @@
+# chessboard program: takes moves in algebraic notation and displays the
+# position after each
+
+## a board is an array of files, a file is an array of characters (squares)
 recipe init-board [
   default-space:address:array:location <- new location:type, 30:literal
   initial-position:address:array:integer <- next-ingredient
@@ -140,3 +144,175 @@ scenario printing-the-board [
     .                              .
   ]
 ]
+
+## data structure: move
+container move [
+  # valid range: 0-7
+  from-file:integer
+  from-rank:integer
+  to-file:integer
+  to-rank:integer
+]
+
+recipe read-move [
+  default-space:address:array:location <- new location:type, 30:literal
+  stdin:address:channel <- next-ingredient
+  from-file:integer <- read-file stdin:address:channel
+  {
+    q-pressed?:boolean <- lesser-than from-file:integer, 0:literal
+    break-unless q-pressed?:boolean
+    reply 0:literal
+  }
+  # construct the move object
+  result:address:move <- new move:literal
+  x:address:integer <- get-address result:address:move/deref, from-file:offset
+  x:address:integer/deref <- copy from-file:integer
+  x:address:integer <- get-address result:address:move/deref, from-rank:offset
+  x:address:integer/deref <- read-rank stdin:address:channel
+  expect-from-channel stdin:address:channel, 45:literal  # '-'
+  x:address:integer <- get-address result:address:move/deref, to-file:offset
+  x:address:integer/deref <- read-file stdin:address:channel
+  x:address:integer <- get-address result:address:move/deref, to-rank:offset
+  x:address:integer/deref <- read-rank stdin:address:channel
+  expect-from-channel stdin:address:channel, 10:literal  # newline
+  reply result:address:move
+]
+
+recipe read-file [
+  default-space:address:array:location <- new location:type, 30:literal
+  stdin:address:channel <- next-ingredient
+  c:character, stdin:address:channel <- read stdin:address:channel
+  {
+    q-pressed?:boolean <- equal c:character, 81:literal  # 'q'
+    break-unless q-pressed?:boolean
+    reply -1:literal
+  }
+  file:integer <- subtract c:character, 97:literal  # 'a'
+  # 'a' <= file <= 'h'
+  above-min:boolean <- greater-or-equal file:integer, 0:literal
+  assert above-min:boolean [file too low]
+  below-max:boolean <- lesser-than file:integer, 8:literal
+  assert below-max:boolean [file too high]
+  reply file:integer
+]
+
+recipe read-rank [
+  default-space:address:array:location <- new location:type, 30:literal
+  stdin:address:channel <- next-ingredient
+  c:character, stdin:address:channel <- read stdin:address:channel
+  {
+    q-pressed?:boolean <- equal c:character, 81:literal  # 'q'
+    break-unless q-pressed?:boolean
+    reply -1:literal
+  }
+  rank:integer <- subtract c:character, 49:literal  # '1'
+  # assert'1' <= rank <= '8'
+  above-min:boolean <- greater-or-equal rank:integer 0:literal
+  assert above-min:boolean [rank too low]
+  below-max:boolean <- lesser-or-equal rank:integer 7:literal
+  assert below-max:boolean [rank too high]
+  reply rank:integer
+]
+
+# read a character from the given channel and check that it's what we expect
+recipe expect-from-channel [
+  default-space:address:array:location <- new location:type, 30:literal
+  stdin:address:channel <- next-ingredient
+  expected:character <- next-ingredient
+  c:character, stdin:address:channel <- read stdin:address:channel
+  match?:boolean <- equal c:character, expected:character
+  assert match?:boolean [expected character not found]
+]
+
+scenario read-move-blocking [
+  run [
+#?     $start-tracing #? 1
+    1:address:channel <- init-channel 2:literal
+#?     $print [aaa channel address: ], 1:address:channel, [ #? 1
+#? ] #? 1
+    2:integer/routine <- start-running read-move:recipe, 1:address:channel
+    # 'read-move' is waiting for input
+    wait-for-routine 2:integer
+#?     $print [bbb channel address: ], 1:address:channel, [ #? 1
+#? ] #? 1
+    3:integer <- routine-state 2:integer/id
+#?     $print [I: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/waiting? <- equal 3:integer/routine-state, 2:literal/waiting
+    assert 4:boolean/waiting?, [
+F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)]
+    # press 'a'
+#?     $print [ccc channel address: ], 1:address:channel, [ #? 1
+#? ] #? 1
+#?     $exit #? 1
+    1:address:channel <- write 1:address:channel, 97:literal  # 'a'
+    restart 2:integer/routine
+    # 'read-move' still waiting for input
+    wait-for-routine 2:integer
+    3:integer <- routine-state 2:integer/id
+#?     $print [II: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/waiting? <- equal 3:integer/routine-state, 2:literal/waiting
+    assert 4:boolean/waiting?, [
+F read-move-blocking: routine failed to pause after rank 'a']
+    # press '2'
+    1:address:channel <- write 1:address:channel, 50:literal  # '2'
+    restart 2:integer/routine
+    # 'read-move' still waiting for input
+    wait-for-routine 2:integer
+    3:integer <- routine-state 2:integer/id
+#?     $print [III: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/waiting? <- equal 3:integer/routine-state, 2:literal/waiting
+    assert 4:boolean/waiting?, [
+F read-move-blocking: routine failed to pause after file 'a2']
+    # press '-'
+    1:address:channel <- write 1:address:channel, 45:literal  # '-'
+    restart 2:integer/routine
+    # 'read-move' still waiting for input
+    wait-for-routine 2:integer
+    3:integer <- routine-state 2:integer
+#?     $print [IV: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/waiting? <- equal 3:integer/routine-state, 2:literal/waiting
+    assert 4:boolean/waiting?/routine-state, [
+F read-move-blocking: routine failed to pause after hyphen 'a2-']
+    # press 'a'
+    1:address:channel <- write 1:address:channel, 97:literal  # 'a'
+    restart 2:integer/routine
+    # 'read-move' still waiting for input
+    wait-for-routine 2:integer
+    3:integer <- routine-state 2:integer
+#?     $print [V: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/waiting? <- equal 3:integer/routine-state, 2:literal/waiting
+    assert 4:boolean/waiting?/routine-state, [
+F read-move-blocking: routine failed to pause after rank 'a2-a']
+    # press '4'
+    1:address:channel <- write 1:address:channel, 52:literal  # '4'
+    restart 2:integer/routine
+    # 'read-move' still waiting for input
+    wait-for-routine 2:integer
+    3:integer <- routine-state 2:integer
+#?     $print [VI: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/waiting? <- equal 3:integer/routine-state, 2:literal/waiting
+    assert 4:boolean/waiting?, [
+F read-move-blocking: routine failed to pause after file 'a2-a4']
+    # press 'newline'
+    1:address:channel <- write 1:address:channel, 10:literal  # newline
+    restart 2:integer/routine
+    # 'read-move' now completes
+    wait-for-routine 2:integer
+    3:integer <- routine-state 2:integer
+#?     $print [VII: routine ], 2:integer, [ state ], 3:integer [ #? 1
+#? ] #? 1
+    4:boolean/completed? <- equal 3:integer/routine-state, 1:literal/completed
+    assert 4:boolean/completed?, [
+F read-move-blocking: routine failed to terminate on newline]
+    trace [test], [reached end]
+  ]
+  trace-should-contain [
+    test: reached end
+  ]
+]