about summary refs log tree commit diff stats
path: root/053recipe_header.cc
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2016-10-22 16:04:47 -0700
committerKartik K. Agaram <vc@akkartik.com>2016-10-22 16:04:47 -0700
commit3b107f1863930433e771a630dfbba095fa1fd6b0 (patch)
tree6f579d003f3cb4d392d68d8aeac059195b639581 /053recipe_header.cc
parente939023612da044098e649e1e77cacceb73c564d (diff)
downloadmu-3b107f1863930433e771a630dfbba095fa1fd6b0.tar.gz
3554 - flag unexpected header for recipe 'main'
As long as Mu operates atop Unix, we need to make these assumptions.

Thanks Ella Couch for finding this loophole.
Diffstat (limited to '053recipe_header.cc')
-rw-r--r--053recipe_header.cc43
1 files changed, 43 insertions, 0 deletions
diff --git a/053recipe_header.cc b/053recipe_header.cc
index a98b4c54..9845b3fa 100644
--- a/053recipe_header.cc
+++ b/053recipe_header.cc
@@ -521,6 +521,49 @@ def add2 x:num, y:num -> x:num [
 ]
 +error: main: '3:num <- add2 1:num, 2:num' should write to '1:num' rather than '3:num'
 
+//: One special-case is recipe 'main'. Make sure it's only ever taking in text
+//: ingredients, and returning a single number.
+
+:(scenario recipe_header_ingredients_constrained_for_main)
+% Hide_errors = true;
+def main x:num [
+]
++error: ingredients of recipe 'main' must all be text (address:array:character)
+
+:(scenario recipe_header_products_constrained_for_main)
+% Hide_errors = true;
+def main -> x:text [
+]
++error: recipe 'main' must return at most a single product, a number
+
+:(scenario recipe_header_products_constrained_for_main_2)
+% Hide_errors = true;
+def main -> x:num, y:num [
+]
++error: recipe 'main' must return at most a single product, a number
+
+:(after "Transform.push_back(expand_type_abbreviations)")
+Transform.push_back(check_recipe_header_constraints);
+:(code)
+void check_recipe_header_constraints(const recipe_ordinal r) {
+  const recipe& caller = get(Recipe, r);
+  if (caller.name != "main") return;
+  if (!caller.has_header) return;
+  reagent/*local*/ expected_ingredient("x:address:array:character");
+  for (int i = 0; i < SIZE(caller.ingredients); ++i) {
+    if (!types_strictly_match(expected_ingredient, caller.ingredients.at(i))) {
+      raise << "ingredients of recipe 'main' must all be text (address:array:character)\n" << end();
+      break;
+    }
+  }
+  int nprod = SIZE(caller.products);
+  reagent/*local*/ expected_product("x:number");
+  if (nprod > 1
+      || (nprod == 1 && !types_strictly_match(expected_product, caller.products.at(0)))) {
+    raise << "recipe 'main' must return at most a single product, a number\n" << end();
+  }
+}
+
 :(before "End Includes")
 using std::min;
 using std::max;