From 1fa530589eee7b668d936e77c1c430f18907a481 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Wed, 28 Oct 2015 13:08:26 -0700 Subject: 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). --- 021check_instruction.cc | 17 +++++++++++++++++ 034call.cc | 9 ++++++++- 035call_ingredient.cc | 17 ++++++++++++++++- 036call_reply.cc | 6 +++--- 038scheduler.cc | 11 ++++++++--- 071print.mu | 12 ++++++------ 072scenario_screen.cc | 18 +++++++++--------- 073scenario_screen_test.mu | 8 ++++---- 074console.mu | 10 +++++----- 075scenario_console.cc | 20 ++++++++++---------- 076scenario_console_test.mu | 8 ++++---- chessboard.mu | 36 ++++++++++++++++++------------------ 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& 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_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 -- cgit 1.4.1-2-gfad0