about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--071recipe.cc34
-rw-r--r--072scheduler.cc15
2 files changed, 39 insertions, 10 deletions
diff --git a/071recipe.cc b/071recipe.cc
index 9135feda..2acfa840 100644
--- a/071recipe.cc
+++ b/071recipe.cc
@@ -160,24 +160,38 @@ void check_indirect_calls_against_header(const recipe_ordinal r) {
   const recipe& caller = get(Recipe, r);
   for (int i = 0;  i < SIZE(caller.steps);  ++i) {
     const instruction& inst = caller.steps.at(i);
-    if (inst.operation != CALL) continue;
-    if (inst.ingredients.empty()) continue;  // error raised above
+    if (inst.ingredients.empty()) continue;  // if indirect call, error raised above
     const reagent& callee = inst.ingredients.at(0);
-    if (!is_mu_recipe(callee)) continue;  // error raised above
+    if (!is_mu_recipe(callee)) continue;  // if indirect call, error raised above
     const recipe callee_header = is_literal(callee) ? get(Recipe, callee.value) : from_reagent(inst.ingredients.at(0));
     if (!callee_header.has_header) continue;
-    for (long int i = /*skip callee*/1;  i < min(SIZE(inst.ingredients), SIZE(callee_header.ingredients)+/*skip callee*/1);  ++i) {
-      if (!types_coercible(callee_header.ingredients.at(i-/*skip callee*/1), inst.ingredients.at(i)))
-        raise << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << inst.original_string << "'\n" << end();
+    if (is_indirect_call_with_ingredients(inst.operation)) {
+      for (long int i = /*skip callee*/1;  i < min(SIZE(inst.ingredients), SIZE(callee_header.ingredients)+/*skip callee*/1);  ++i) {
+        if (!types_coercible(callee_header.ingredients.at(i-/*skip callee*/1), inst.ingredients.at(i)))
+          raise << maybe(caller.name) << "ingredient " << i-/*skip callee*/1 << " has the wrong type at '" << inst.original_string << "'\n" << end();
+      }
     }
-    for (long int i = 0;  i < min(SIZE(inst.products), SIZE(callee_header.products));  ++i) {
-      if (is_dummy(inst.products.at(i))) continue;
-      if (!types_coercible(callee_header.products.at(i), inst.products.at(i)))
-        raise << maybe(caller.name) << "product " << i << " has the wrong type at '" << inst.original_string << "'\n" << end();
+    if (is_indirect_call_with_products(inst.operation)) {
+      for (long int i = 0;  i < min(SIZE(inst.products), SIZE(callee_header.products));  ++i) {
+        if (is_dummy(inst.products.at(i))) continue;
+        if (!types_coercible(callee_header.products.at(i), inst.products.at(i)))
+          raise << maybe(caller.name) << "product " << i << " has the wrong type at '" << inst.original_string << "'\n" << end();
+      }
     }
   }
 }
 
+bool is_indirect_call_with_ingredients(const recipe_ordinal r) {
+  if (r == CALL) return true;
+  // End is_indirect_call_with_ingredients Special-cases
+  return false;
+}
+bool is_indirect_call_with_products(const recipe_ordinal r) {
+  if (r == CALL) return true;
+  // End is_indirect_call_with_products Special-cases
+  return false;
+}
+
 recipe from_reagent(const reagent& r) {
   assert(r.type);
   recipe result_header;  // will contain only ingredients and products, nothing else
diff --git a/072scheduler.cc b/072scheduler.cc
index e027b9dc..c5cd616a 100644
--- a/072scheduler.cc
+++ b/072scheduler.cc
@@ -239,6 +239,21 @@ def f2 [
 ]
 +mem: storing 4 in location 2
 
+//: type-checking for 'start-running'
+
+:(scenario start_running_checks_types)
+% Hide_errors = true;
+def f1 [
+  start-running f2, 3
+]
+def f2 n:&:num [
+]
++error: f1: ingredient 0 has the wrong type at 'start-running f2, 3'
+
+// 'start-running' only uses the ingredients of the callee, not its products
+:(before "End is_indirect_call_with_ingredients Special-cases")
+if (r == START_RUNNING) return true;
+
 //: more complex: refcounting management when starting up new routines
 
 :(scenario start_running_immediately_updates_refcounts_of_ingredients)
} /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
//: You guessed right: the '000' prefix means you should start reading here.
//:
//: This project is set up to load all files with a numeric prefix. Just
//: create a new file and start hacking.
//:
//: The first few files (00*) are independent of what this program does, an
//: experimental skeleton that will hopefully make it both easier for others to
//: understand and more malleable, easier to rewrite and remould into radically
//: different shapes without breaking in subtle corner cases. The premise is
//: that understandability and rewrite-friendliness are related in a virtuous
//: cycle. Doing one well makes it easier to do the other.
//:
//: Lower down, this file contains a legal, bare-bones C++ program. It doesn't
//: do anything yet; subsequent files will contain :(...) directives to insert
//: lines into it. For example:
//:   :(after "more events")
//: This directive means: insert the following lines after a line in the
//: program containing the words "more events".
//:
//: A simple tool is included to 'tangle' all the files together in sequence
//: according to their directives into a single source file containing all the
//: code for the project, and then feed the source file to the compiler.
//: (It'll drop these comments starting with a '//:' prefix that only make
//: sense before tangling.)
//:
//: Directives free up the programmer to order code for others to read rather
//: than as forced by the computer or compiler. Each individual feature can be
//: organized in a self-contained 'layer' that adds code to many different data
//: structures and functions all over the program. The right decomposition into
//: layers will let each layer make sense in isolation.
//:
//:   "If I look at any small part of it, I can see what is going on -- I don't
//:   need to refer to other parts to understand what something is doing.
//:
//:   If I look at any large part in overview, I can see what is going on -- I
//:   don't need to know all the details to get it.
//:
//:   Every level of detail is as locally coherent and as well thought-out as
//:   any other level."
//:
//:       -- Richard Gabriel, "The Quality Without A Name"
//:          (http://dreamsongs.com/Files/PatternsOfSoftware.pdf, page 42)
//:
//: Directives are powerful; they permit inserting or modifying any point in
//: the program. Using them tastefully requires mapping out specific lines as
//: waypoints for future layers to hook into. Often such waypoints will be in
//: comments, capitalized to hint that other layers rely on their presence.
//:
//: A single waypoint might have many different code fragments hooking into
//: it from all over the codebase. Use 'before' directives to insert
//: code at a location in order, top to bottom, and 'after' directives to
//: insert code in reverse order. By convention waypoints intended for insertion
//: before begin with 'End'. Notice below how the layers line up above the "End
//: Foo" waypoint.
//:
//:   File 001          File 002                File 003
//:   ============      ===================     ===================
//:   // Foo
//:   ------------
//:              <----  :(before "End Foo")
//:                     ....
//:                     ...
//:   ------------
//:              <----------------------------  :(before "End Foo")
//:                                             ....
//:                                             ...
//:   // End Foo
//:   ============
//:
//: Here's part of a layer in color: http://i.imgur.com/0eONnyX.png. Directives
//: are shaded dark.
//:
//: Layers do more than just shuffle code around. In a well-organized codebase
//: it should be possible to stop loading after any file/layer, build and run
//: the program, and pass all tests for loaded features. (Relevant is
//: http://youtube.com/watch?v=c8N72t7aScY, a scene from "2001: A Space
//: Odyssey".) Get into the habit of running the included script called
//: 'test_layers' before you commit any changes.
//:
//: This 'subsetting guarantee' ensures that this directory contains a
//: cleaned-up narrative of the evolution of this codebase. Organizing
//: autobiographically allows newcomers to rapidly orient themselves, reading
//: the first few files to understand a simple gestalt of a program's core
//: purpose and features, and later gradually working their way through other
//: features as the need arises.
//:
//: Programmers shouldn't need to understand everything about a program to
//: hack on it. But they shouldn't be prevented from a thorough understanding
//: of each aspect either. The goal of layers is to reward curiosity.

// Includes
// End Includes

// Types
// End Types

// Function prototypes are auto-generated in the 'build' script; define your
// functions in any order. Just be sure to declare each function header all on
// one line, ending with the '{'. Our auto-generation scripts are too minimal
// and simple-minded to handle anything else.
#include "function_list"  // by convention, files ending with '_list' are auto-generated

// Globals
//
// All statements in this section should always define a single variable on a
// single line. The 'build' script will simple-mindedly auto-generate extern
// declarations for them. Remember to define (not just declare) constants with
// extern linkage in this section, since C++ global constants have internal
// linkage by default.
//
// End Globals

int main(int argc, char* argv[]) {
  atexit(reset);
  // we require a 32-bit little-endian system
  assert(sizeof(int) == 4);
  assert(sizeof(float) == 4);
  assert_little_endian();

  // End One-time Setup

  // Commandline Parsing
  // End Commandline Parsing

  // End Main

  return 0;
}

// Unit Tests
// End Unit Tests

//: our first directive; insert the following headers at the start of the program
:(before "End Includes")
#include <assert.h>
#include <stdlib.h>

//: Without directives or with the :(code) directive, lines get added at the
//: end.
//:
//: Regardless of where functions are defined, we can call them anywhere we
//: like as long as we format the function header in a specific way: put it
//: all on a single line without indent, end the line with ') {' and no
//: trailing whitespace. As long as functions uniformly start this way, our
//: 'build' script contains a little command to automatically generate
//: declarations for them.
:(code)
void reset() {
  // End Reset
}

void assert_little_endian() {
  const int x = 1;
  const char* y = reinterpret_cast<const char*>(&x);
  if (*y != 1) {
    cerr << "SubX requires a little-endian processor. Do you have Intel (or AMD or Atom) inside?\n";
    exit(1);
  }
}
:(before "End Includes")
#include<iostream>
using std::cerr;