From c495d2ac7ca0d7f1c1a9bbb7d1ad5072a7eface5 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Fri, 17 Apr 2015 11:00:56 -0700 Subject: 1075 --- cpp/.traces/array_length | 2 +- cpp/.traces/brace_conversion | 2 +- cpp/.traces/break_cascading | 4 +- cpp/.traces/break_cascading2 | 4 +- cpp/.traces/break_empty_block | 2 +- cpp/.traces/break_if | 4 +- cpp/.traces/break_label | 2 +- cpp/.traces/break_nested | 2 +- cpp/.traces/break_nested_degenerate | 2 +- cpp/.traces/break_nested_degenerate2 | 2 +- cpp/.traces/break_unless | 2 +- cpp/.traces/closure | 12 +- .../convert_names_transforms_container_elements | 4 +- cpp/.traces/factorial | 4 +- cpp/.traces/get | 2 +- cpp/.traces/get_address | 2 +- cpp/.traces/get_address_indirect | 2 +- cpp/.traces/get_handles_nested_container_elements | 2 +- cpp/.traces/get_indirect | 2 +- cpp/.traces/include_nonderef_properties | 2 +- cpp/.traces/index | 2 +- cpp/.traces/index_address | 2 +- cpp/.traces/index_direct_offset | 2 +- cpp/.traces/index_indirect | 2 +- cpp/.traces/loop | 2 +- cpp/.traces/loop_nested | 2 +- cpp/.traces/loop_unless | 2 +- cpp/.traces/new | 4 +- cpp/.traces/new_array | 4 +- cpp/.traces/new_string | 14 +- cpp/.traces/next_ingredient | 2 +- cpp/.traces/reply | 4 +- cpp/.traces/reply_container | 4 +- .../string-equal-common-lengths-but-distinct | 38 +- cpp/.traces/string-equal-distinct-lengths | 14 +- cpp/.traces/string-equal-identical | 38 +- cpp/.traces/string-equal-reflexive | 34 +- cpp/.traces/string-equal-with-empty | 14 +- cpp/.traces/string_literal | 9 +- cpp/.traces/string_literal_nested | 9 +- cpp/.traces/string_literal_with_colons | 9 +- cpp/.traces/trace | 2 +- cpp/.traces/trace_in_mu | 2 +- cpp/013literal_string | 63 ++++ cpp/013run | 187 ---------- cpp/014arithmetic | 225 ------------ cpp/015boolean | 93 ----- cpp/016jump | 114 ------ cpp/017compare | 261 -------------- cpp/020container | 167 --------- cpp/020run | 187 ++++++++++ cpp/021address | 117 ------- cpp/021arithmetic | 225 ++++++++++++ cpp/022array | 152 -------- cpp/022boolean | 93 +++++ cpp/023jump | 114 ++++++ cpp/023length | 30 -- cpp/024compare | 261 ++++++++++++++ cpp/025call | 77 ---- cpp/025trace | 19 + cpp/026call_ingredient | 42 --- cpp/027call_reply | 70 ---- cpp/030brace | 387 --------------------- cpp/030container | 167 +++++++++ cpp/031address | 117 +++++++ cpp/031name | 172 --------- cpp/032array | 152 ++++++++ cpp/032new | 76 ---- cpp/033length | 30 ++ cpp/033space | 90 ----- cpp/034space_surround | 50 --- cpp/035call | 77 ++++ cpp/035literal_string | 91 ----- cpp/036call_ingredient | 42 +++ cpp/037call_reply | 70 ++++ cpp/040brace | 387 +++++++++++++++++++++ cpp/040scenario | 132 ------- cpp/041name | 172 +++++++++ cpp/041scenario_test.mu | 9 - cpp/042new | 102 ++++++ cpp/042trace | 19 - cpp/043scenario_trace | 101 ------ cpp/043space | 90 +++++ cpp/044scenario_trace_test.mu | 27 -- cpp/044space_surround | 50 +++ cpp/045closure_name | 142 -------- cpp/050scenario | 132 +++++++ cpp/050string.mu | 96 ----- cpp/051scenario_test.mu | 9 + cpp/052scenario_trace | 101 ++++++ cpp/053scenario_trace_test.mu | 27 ++ cpp/054closure_name | 142 ++++++++ cpp/060string.mu | 96 +++++ 93 files changed, 3055 insertions(+), 3072 deletions(-) create mode 100644 cpp/013literal_string delete mode 100644 cpp/013run delete mode 100644 cpp/014arithmetic delete mode 100644 cpp/015boolean delete mode 100644 cpp/016jump delete mode 100644 cpp/017compare delete mode 100644 cpp/020container create mode 100644 cpp/020run delete mode 100644 cpp/021address create mode 100644 cpp/021arithmetic delete mode 100644 cpp/022array create mode 100644 cpp/022boolean create mode 100644 cpp/023jump delete mode 100644 cpp/023length create mode 100644 cpp/024compare delete mode 100644 cpp/025call create mode 100644 cpp/025trace delete mode 100644 cpp/026call_ingredient delete mode 100644 cpp/027call_reply delete mode 100644 cpp/030brace create mode 100644 cpp/030container create mode 100644 cpp/031address delete mode 100644 cpp/031name create mode 100644 cpp/032array delete mode 100644 cpp/032new create mode 100644 cpp/033length delete mode 100644 cpp/033space delete mode 100644 cpp/034space_surround create mode 100644 cpp/035call delete mode 100644 cpp/035literal_string create mode 100644 cpp/036call_ingredient create mode 100644 cpp/037call_reply create mode 100644 cpp/040brace delete mode 100644 cpp/040scenario create mode 100644 cpp/041name delete mode 100644 cpp/041scenario_test.mu create mode 100644 cpp/042new delete mode 100644 cpp/042trace delete mode 100644 cpp/043scenario_trace create mode 100644 cpp/043space delete mode 100644 cpp/044scenario_trace_test.mu create mode 100644 cpp/044space_surround delete mode 100644 cpp/045closure_name create mode 100644 cpp/050scenario delete mode 100644 cpp/050string.mu create mode 100644 cpp/051scenario_test.mu create mode 100644 cpp/052scenario_trace create mode 100644 cpp/053scenario_trace_test.mu create mode 100644 cpp/054closure_name create mode 100644 cpp/060string.mu diff --git a/cpp/.traces/array_length b/cpp/.traces/array_length index 65ae6484..5484570d 100644 --- a/cpp/.traces/array_length +++ b/cpp/.traces/array_length @@ -10,7 +10,7 @@ parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "16", value: 0, type: 0, properties: ["16": "literal"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} -parse/0: instruction: 22 +parse/0: instruction: 23 parse/0: ingredient: {name: "1", value: 0, type: 5-1, properties: ["1": "array":"integer"]} parse/0: product: {name: "5", value: 0, type: 1, properties: ["5": "integer"]} after-brace/0: recipe main diff --git a/cpp/.traces/brace_conversion b/cpp/.traces/brace_conversion index c9444a7c..6920866e 100644 --- a/cpp/.traces/brace_conversion +++ b/cpp/.traces/brace_conversion @@ -1,5 +1,5 @@ parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} diff --git a/cpp/.traces/break_cascading b/cpp/.traces/break_cascading index 06127e3d..1a516b99 100644 --- a/cpp/.traces/break_cascading +++ b/cpp/.traces/break_cascading @@ -2,10 +2,10 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: } parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: } brace/0: 1000: push (open, 1) brace/0: push (close, 3) diff --git a/cpp/.traces/break_cascading2 b/cpp/.traces/break_cascading2 index 2cd8aea6..327e3ec3 100644 --- a/cpp/.traces/break_cascading2 +++ b/cpp/.traces/break_cascading2 @@ -5,13 +5,13 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: label: } parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: } brace/0: 1000: push (open, 2) brace/0: push (close, 5) diff --git a/cpp/.traces/break_empty_block b/cpp/.traces/break_empty_block index 3605ac83..2771f904 100644 --- a/cpp/.traces/break_empty_block +++ b/cpp/.traces/break_empty_block @@ -2,7 +2,7 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: } brace/0: 1000: push (open, 1) brace/0: push (close, 3) diff --git a/cpp/.traces/break_if b/cpp/.traces/break_if index d5f5d0e9..3ea882a3 100644 --- a/cpp/.traces/break_if +++ b/cpp/.traces/break_if @@ -5,14 +5,14 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: label: { -parse/0: instruction: 26 +parse/0: instruction: 27 parse/0: ingredient: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: label: } parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: } brace/0: 1000: push (open, 2) brace/0: push (close, 5) diff --git a/cpp/.traces/break_label b/cpp/.traces/break_label index fe03e6c2..c73d8678 100644 --- a/cpp/.traces/break_label +++ b/cpp/.traces/break_label @@ -2,7 +2,7 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} parse/0: label: { -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: ingredient: {name: "+foo", value: 0, type: 0, properties: ["+foo": "offset"]} parse/0: label: } brace/0: 1000: push (open, 1) diff --git a/cpp/.traces/break_nested b/cpp/.traces/break_nested index ac8c5a30..ef268b47 100644 --- a/cpp/.traces/break_nested +++ b/cpp/.traces/break_nested @@ -5,7 +5,7 @@ parse/0: label: { parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: { parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} diff --git a/cpp/.traces/break_nested_degenerate b/cpp/.traces/break_nested_degenerate index c2c5d1a2..6540bc51 100644 --- a/cpp/.traces/break_nested_degenerate +++ b/cpp/.traces/break_nested_degenerate @@ -5,7 +5,7 @@ parse/0: label: { parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: { parse/0: label: } parse/0: instruction: 1 diff --git a/cpp/.traces/break_nested_degenerate2 b/cpp/.traces/break_nested_degenerate2 index dcbe62ad..a1ee2035 100644 --- a/cpp/.traces/break_nested_degenerate2 +++ b/cpp/.traces/break_nested_degenerate2 @@ -5,7 +5,7 @@ parse/0: label: { parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} -parse/0: instruction: 25 +parse/0: instruction: 26 parse/0: label: { parse/0: label: } parse/0: label: } diff --git a/cpp/.traces/break_unless b/cpp/.traces/break_unless index 03fd8a90..7d61dded 100644 --- a/cpp/.traces/break_unless +++ b/cpp/.traces/break_unless @@ -5,7 +5,7 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: label: { -parse/0: instruction: 27 +parse/0: instruction: 28 parse/0: ingredient: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} diff --git a/cpp/.traces/closure b/cpp/.traces/closure index f5a41ee9..0f5d2161 100644 --- a/cpp/.traces/closure +++ b/cpp/.traces/closure @@ -1,4 +1,4 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} @@ -10,7 +10,7 @@ parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer", parse/0: instruction: 1002 parse/0: ingredient: {name: "1", value: 0, type: 2-0, properties: ["1": "address":"space", "names": "init-counter"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer", "raw": ]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} @@ -20,13 +20,13 @@ parse/0: product: {name: "x", value: 0, type: 1, properties: ["x": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "3", value: 0, type: 0, properties: ["3": "literal"]} parse/0: product: {name: "y", value: 0, type: 1, properties: ["y": "integer"]} -parse/0: instruction: 24 +parse/0: instruction: 25 parse/0: ingredient: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "space", value: 0, type: 0, properties: ["space": "literal"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 23 +parse/0: instruction: 24 parse/0: product: {name: "0", value: 0, type: 2-0, properties: ["0": "address":"space", "names": "init-counter"]} parse/0: instruction: 2 parse/0: ingredient: {name: "y", value: 0, type: 1, properties: ["y": "integer", "space": "1"]} @@ -35,7 +35,7 @@ parse/0: product: {name: "y", value: 0, type: 1, properties: ["y": "integer", parse/0: instruction: 1 parse/0: ingredient: {name: "234", value: 0, type: 0, properties: ["234": "literal"]} parse/0: product: {name: "y", value: 0, type: 1, properties: ["y": "integer"]} -parse/0: instruction: 24 +parse/0: instruction: 25 parse/0: ingredient: {name: "y", value: 0, type: 1, properties: ["y": "integer", "space": "1"]} name/0: recipe increment-counter is surrounded by init-counter new/0: location -> 1 diff --git a/cpp/.traces/convert_names_transforms_container_elements b/cpp/.traces/convert_names_transforms_container_elements index 0dd4f7e8..c86b6d2d 100644 --- a/cpp/.traces/convert_names_transforms_container_elements +++ b/cpp/.traces/convert_names_transforms_container_elements @@ -1,8 +1,8 @@ -parse/0: instruction: 18 +parse/0: instruction: 19 parse/0: ingredient: {name: "0", value: 0, type: 6, properties: ["0": "point"]} parse/0: ingredient: {name: "y", value: 0, type: 0, properties: ["y": "offset"]} parse/0: product: {name: "a", value: 0, type: 1, properties: ["a": "integer"]} -parse/0: instruction: 18 +parse/0: instruction: 19 parse/0: ingredient: {name: "0", value: 0, type: 6, properties: ["0": "point"]} parse/0: ingredient: {name: "x", value: 0, type: 0, properties: ["x": "offset"]} parse/0: product: {name: "b", value: 0, type: 1, properties: ["b": "integer"]} diff --git a/cpp/.traces/factorial b/cpp/.traces/factorial index 9a7f261e..d4ea095b 100644 --- a/cpp/.traces/factorial +++ b/cpp/.traces/factorial @@ -9,7 +9,7 @@ parse/0: instruction: 13 parse/0: ingredient: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]} parse/0: product: {name: "3", value: 0, type: 3, properties: ["3": "boolean"]} -parse/0: instruction: 26 +parse/0: instruction: 27 parse/0: ingredient: {name: "3", value: 0, type: 3, properties: ["3": "boolean"]} parse/0: instruction: 4 parse/0: ingredient: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} @@ -19,7 +19,7 @@ parse/0: instruction: 3 parse/0: ingredient: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]} parse/0: product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]} -parse/0: instruction: 28 +parse/0: instruction: 29 parse/0: label: } parse/0: instruction: 1 parse/0: ingredient: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} diff --git a/cpp/.traces/get b/cpp/.traces/get index 39778dbf..60d738da 100644 --- a/cpp/.traces/get +++ b/cpp/.traces/get @@ -4,7 +4,7 @@ parse/0: product: {name: "12", value: 0, type: 1, properties: ["12": "integer" parse/0: instruction: 1 parse/0: ingredient: {name: "35", value: 0, type: 0, properties: ["35": "literal"]} parse/0: product: {name: "13", value: 0, type: 1, properties: ["13": "integer"]} -parse/0: instruction: 18 +parse/0: instruction: 19 parse/0: ingredient: {name: "12", value: 0, type: 6, properties: ["12": "point"]} parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "offset"]} parse/0: product: {name: "15", value: 0, type: 1, properties: ["15": "integer"]} diff --git a/cpp/.traces/get_address b/cpp/.traces/get_address index 1a37c192..f36d4b05 100644 --- a/cpp/.traces/get_address +++ b/cpp/.traces/get_address @@ -4,7 +4,7 @@ parse/0: product: {name: "12", value: 0, type: 1, properties: ["12": "integer" parse/0: instruction: 1 parse/0: ingredient: {name: "35", value: 0, type: 0, properties: ["35": "literal"]} parse/0: product: {name: "13", value: 0, type: 1, properties: ["13": "integer"]} -parse/0: instruction: 19 +parse/0: instruction: 20 parse/0: ingredient: {name: "12", value: 0, type: 6, properties: ["12": "point"]} parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "offset"]} parse/0: product: {name: "15", value: 0, type: 2-1, properties: ["15": "address":"integer"]} diff --git a/cpp/.traces/get_address_indirect b/cpp/.traces/get_address_indirect index 2f2af58b..bb74ab61 100644 --- a/cpp/.traces/get_address_indirect +++ b/cpp/.traces/get_address_indirect @@ -7,7 +7,7 @@ parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "35", value: 0, type: 0, properties: ["35": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} -parse/0: instruction: 19 +parse/0: instruction: 20 parse/0: ingredient: {name: "1", value: 0, type: 2-6, properties: ["1": "address":"point", "deref": ]} parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "offset"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} diff --git a/cpp/.traces/get_handles_nested_container_elements b/cpp/.traces/get_handles_nested_container_elements index 4334fc26..5997b167 100644 --- a/cpp/.traces/get_handles_nested_container_elements +++ b/cpp/.traces/get_handles_nested_container_elements @@ -7,7 +7,7 @@ parse/0: product: {name: "13", value: 0, type: 1, properties: ["13": "integer" parse/0: instruction: 1 parse/0: ingredient: {name: "36", value: 0, type: 0, properties: ["36": "literal"]} parse/0: product: {name: "14", value: 0, type: 1, properties: ["14": "integer"]} -parse/0: instruction: 18 +parse/0: instruction: 19 parse/0: ingredient: {name: "12", value: 0, type: 7, properties: ["12": "point-integer"]} parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "offset"]} parse/0: product: {name: "15", value: 0, type: 1, properties: ["15": "integer"]} diff --git a/cpp/.traces/get_indirect b/cpp/.traces/get_indirect index 98e9d9c6..b9328f71 100644 --- a/cpp/.traces/get_indirect +++ b/cpp/.traces/get_indirect @@ -7,7 +7,7 @@ parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "35", value: 0, type: 0, properties: ["35": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} -parse/0: instruction: 18 +parse/0: instruction: 19 parse/0: ingredient: {name: "1", value: 0, type: 2-6, properties: ["1": "address":"point", "deref": ]} parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "offset"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} diff --git a/cpp/.traces/include_nonderef_properties b/cpp/.traces/include_nonderef_properties index 835c973a..b7f103fc 100644 --- a/cpp/.traces/include_nonderef_properties +++ b/cpp/.traces/include_nonderef_properties @@ -7,7 +7,7 @@ parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "35", value: 0, type: 0, properties: ["35": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} -parse/0: instruction: 18 +parse/0: instruction: 19 parse/0: ingredient: {name: "1", value: 0, type: 2-6, properties: ["1": "address":"point", "deref": , "foo": ]} parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "offset"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} diff --git a/cpp/.traces/index b/cpp/.traces/index index e9f3dd08..c5114af2 100644 --- a/cpp/.traces/index +++ b/cpp/.traces/index @@ -10,7 +10,7 @@ parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "16", value: 0, type: 0, properties: ["16": "literal"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} -parse/0: instruction: 20 +parse/0: instruction: 21 parse/0: ingredient: {name: "1", value: 0, type: 5-1, properties: ["1": "array":"integer"]} parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "5", value: 0, type: 1, properties: ["5": "integer"]} diff --git a/cpp/.traces/index_address b/cpp/.traces/index_address index ca503f99..464a4565 100644 --- a/cpp/.traces/index_address +++ b/cpp/.traces/index_address @@ -10,7 +10,7 @@ parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "16", value: 0, type: 0, properties: ["16": "literal"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} -parse/0: instruction: 21 +parse/0: instruction: 22 parse/0: ingredient: {name: "1", value: 0, type: 5-1, properties: ["1": "array":"integer"]} parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "5", value: 0, type: 1, properties: ["5": "integer"]} diff --git a/cpp/.traces/index_direct_offset b/cpp/.traces/index_direct_offset index 67bbbde6..021f8452 100644 --- a/cpp/.traces/index_direct_offset +++ b/cpp/.traces/index_direct_offset @@ -13,7 +13,7 @@ parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "5", value: 0, type: 1, properties: ["5": "integer"]} -parse/0: instruction: 20 +parse/0: instruction: 21 parse/0: ingredient: {name: "1", value: 0, type: 5-1, properties: ["1": "array":"integer"]} parse/0: ingredient: {name: "5", value: 0, type: 1, properties: ["5": "integer"]} parse/0: product: {name: "6", value: 0, type: 1, properties: ["6": "integer"]} diff --git a/cpp/.traces/index_indirect b/cpp/.traces/index_indirect index 0b3bb283..e1f6c191 100644 --- a/cpp/.traces/index_indirect +++ b/cpp/.traces/index_indirect @@ -13,7 +13,7 @@ parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]} parse/0: product: {name: "5", value: 0, type: 2-5-1, properties: ["5": "address":"array":"integer"]} -parse/0: instruction: 20 +parse/0: instruction: 21 parse/0: ingredient: {name: "5", value: 0, type: 2-5-1, properties: ["5": "address":"array":"integer", "deref": ]} parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]} parse/0: product: {name: "6", value: 0, type: 1, properties: ["6": "integer"]} diff --git a/cpp/.traces/loop b/cpp/.traces/loop index cf494543..ba71abf6 100644 --- a/cpp/.traces/loop +++ b/cpp/.traces/loop @@ -8,7 +8,7 @@ parse/0: label: { parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} -parse/0: instruction: 28 +parse/0: instruction: 29 parse/0: label: } brace/0: 1000: push (open, 2) brace/0: push (close, 5) diff --git a/cpp/.traces/loop_nested b/cpp/.traces/loop_nested index d6d78346..3b9fb46f 100644 --- a/cpp/.traces/loop_nested +++ b/cpp/.traces/loop_nested @@ -10,7 +10,7 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: label: } -parse/0: instruction: 29 +parse/0: instruction: 30 parse/0: ingredient: {name: "4", value: 0, type: 3, properties: ["4": "boolean"]} parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} diff --git a/cpp/.traces/loop_unless b/cpp/.traces/loop_unless index 9d5f5892..b26ad4c5 100644 --- a/cpp/.traces/loop_unless +++ b/cpp/.traces/loop_unless @@ -5,7 +5,7 @@ parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} parse/0: product: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: label: { -parse/0: instruction: 30 +parse/0: instruction: 31 parse/0: ingredient: {name: "2", value: 0, type: 1, properties: ["2": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "0", value: 0, type: 0, properties: ["0": "literal"]} diff --git a/cpp/.traces/new b/cpp/.traces/new index 5e148caf..965d0333 100644 --- a/cpp/.traces/new +++ b/cpp/.traces/new @@ -1,7 +1,7 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "integer", value: 0, type: 0, properties: ["integer": "type"]} parse/0: product: {name: "1", value: 0, type: 2-1, properties: ["1": "address":"integer", "raw": ]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "integer", value: 0, type: 0, properties: ["integer": "type"]} parse/0: product: {name: "2", value: 0, type: 2-1, properties: ["2": "address":"integer", "raw": ]} parse/0: instruction: 13 diff --git a/cpp/.traces/new_array b/cpp/.traces/new_array index a480b46d..d41cc26b 100644 --- a/cpp/.traces/new_array +++ b/cpp/.traces/new_array @@ -1,8 +1,8 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "integer", value: 0, type: 0, properties: ["integer": "type"]} parse/0: ingredient: {name: "5", value: 0, type: 0, properties: ["5": "literal"]} parse/0: product: {name: "1", value: 0, type: 2-5-1, properties: ["1": "address":"array":"integer", "raw": ]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "integer", value: 0, type: 0, properties: ["integer": "type"]} parse/0: product: {name: "2", value: 0, type: 2-1, properties: ["2": "address":"integer", "raw": ]} parse/0: instruction: 3 diff --git a/cpp/.traces/new_string b/cpp/.traces/new_string index fe4fe3e8..525602e3 100644 --- a/cpp/.traces/new_string +++ b/cpp/.traces/new_string @@ -1,10 +1,10 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc def", value: 0, type: 0, properties: ["abc def": "literal-string"]} -parse/0: product: {name: "1", value: 0, type: 2-5-8, properties: ["1": "address":"array":"character"]} -parse/0: instruction: 20 -parse/0: ingredient: {name: "1", value: 0, type: 2-5-8, properties: ["1": "address":"array":"character", "deref": ]} +parse/0: product: {name: "1", value: 0, type: 2-5-4, properties: ["1": "address":"array":"character"]} +parse/0: instruction: 21 +parse/0: ingredient: {name: "1", value: 0, type: 2-5-4, properties: ["1": "address":"array":"character", "deref": ]} parse/0: ingredient: {name: "5", value: 0, type: 0, properties: ["5": "literal"]} -parse/0: product: {name: "2", value: 0, type: 8, properties: ["2": "character"]} +parse/0: product: {name: "2", value: 0, type: 4, properties: ["2": "character"]} new/0: abc def -> 0 after-brace/0: recipe main after-brace/0: new ... @@ -12,11 +12,11 @@ after-brace/0: index ... run/0: instruction main/0 mem/0: storing 1000 in location 1 run/0: instruction main/1 -run/0: ingredient 0 is {name: "1", value: 1, type: 2-5-8, properties: ["1": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "1", value: 1, type: 2-5-4, properties: ["1": "address":"array":"character", "deref": ]} mem/0: location 1 is 1000 run/0: ingredient 1 is {name: "5", value: 5, type: 0, properties: ["5": "literal"]} run/0: address to copy is 1006 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1006 is 101 run/0: product 0 is 101 mem/0: storing 101 in location 2 diff --git a/cpp/.traces/next_ingredient b/cpp/.traces/next_ingredient index a296bd69..6f9da074 100644 --- a/cpp/.traces/next_ingredient +++ b/cpp/.traces/next_ingredient @@ -1,6 +1,6 @@ parse/0: instruction: 1001 parse/0: ingredient: {name: "2", value: 0, type: 0, properties: ["2": "literal"]} -parse/0: instruction: 23 +parse/0: instruction: 24 parse/0: product: {name: "12", value: 0, type: 1, properties: ["12": "integer"]} parse/0: instruction: 2 parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]} diff --git a/cpp/.traces/reply b/cpp/.traces/reply index 1dde3540..b83e094f 100644 --- a/cpp/.traces/reply +++ b/cpp/.traces/reply @@ -2,13 +2,13 @@ parse/0: instruction: 1001 parse/0: ingredient: {name: "2", value: 0, type: 0, properties: ["2": "literal"]} parse/0: product: {name: "3", value: 0, type: 1, properties: ["3": "integer"]} parse/0: product: {name: "4", value: 0, type: 1, properties: ["4": "integer"]} -parse/0: instruction: 23 +parse/0: instruction: 24 parse/0: product: {name: "12", value: 0, type: 1, properties: ["12": "integer"]} parse/0: instruction: 2 parse/0: ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]} parse/0: ingredient: {name: "12", value: 0, type: 1, properties: ["12": "integer"]} parse/0: product: {name: "13", value: 0, type: 1, properties: ["13": "integer"]} -parse/0: instruction: 24 +parse/0: instruction: 25 parse/0: ingredient: {name: "12", value: 0, type: 1, properties: ["12": "integer"]} parse/0: ingredient: {name: "13", value: 0, type: 1, properties: ["13": "integer"]} after-brace/0: recipe f diff --git a/cpp/.traces/reply_container b/cpp/.traces/reply_container index 1b491677..144b9b07 100644 --- a/cpp/.traces/reply_container +++ b/cpp/.traces/reply_container @@ -1,12 +1,12 @@ parse/0: instruction: 1001 parse/0: ingredient: {name: "2", value: 0, type: 0, properties: ["2": "literal"]} parse/0: product: {name: "3", value: 0, type: 6, properties: ["3": "point"]} -parse/0: instruction: 23 +parse/0: instruction: 24 parse/0: product: {name: "12", value: 0, type: 1, properties: ["12": "integer"]} parse/0: instruction: 1 parse/0: ingredient: {name: "35", value: 0, type: 0, properties: ["35": "literal"]} parse/0: product: {name: "13", value: 0, type: 1, properties: ["13": "integer"]} -parse/0: instruction: 24 +parse/0: instruction: 25 parse/0: ingredient: {name: "12", value: 0, type: 6, properties: ["12": "point"]} after-brace/0: recipe f after-brace/0: next-ingredient ... diff --git a/cpp/.traces/string-equal-common-lengths-but-distinct b/cpp/.traces/string-equal-common-lengths-but-distinct index 22b9eed7..ee87a24a 100644 --- a/cpp/.traces/string-equal-common-lengths-but-distinct +++ b/cpp/.traces/string-equal-common-lengths-but-distinct @@ -1,16 +1,16 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]} -parse/0: product: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: instruction: 31 +parse/0: product: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: instruction: 32 parse/0: ingredient: {name: "abd", value: 0, type: 0, properties: ["abd": "literal-string"]} -parse/0: product: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: product: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: instruction: 100 -parse/0: ingredient: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: ingredient: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: ingredient: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: ingredient: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: product: {name: "3", value: 0, type: 3, properties: ["3": "boolean", "raw": ]} new/0: location -> 1 new/0: abc -> 0 @@ -78,22 +78,22 @@ mem/0: location 1046 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1040 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 0 run/0: address to copy is 1031 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1031 is 97 run/0: product 0 is 97 mem/0: storing 97 in location 1047 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1042 is 1034 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 0 run/0: address to copy is 1035 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1035 is 97 run/0: product 0 is 97 mem/0: storing 97 in location 1048 @@ -130,22 +130,22 @@ mem/0: location 1046 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1040 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 1 run/0: address to copy is 1032 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1032 is 98 run/0: product 0 is 98 mem/0: storing 98 in location 1047 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1042 is 1034 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 1 run/0: address to copy is 1036 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1036 is 98 run/0: product 0 is 98 mem/0: storing 98 in location 1048 @@ -182,22 +182,22 @@ mem/0: location 1046 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1040 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 2 run/0: address to copy is 1033 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1033 is 99 run/0: product 0 is 99 mem/0: storing 99 in location 1047 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1042 is 1034 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 2 run/0: address to copy is 1037 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1037 is 100 run/0: product 0 is 100 mem/0: storing 100 in location 1048 diff --git a/cpp/.traces/string-equal-distinct-lengths b/cpp/.traces/string-equal-distinct-lengths index 0c69eb1a..834292fe 100644 --- a/cpp/.traces/string-equal-distinct-lengths +++ b/cpp/.traces/string-equal-distinct-lengths @@ -1,16 +1,16 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]} -parse/0: product: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: instruction: 31 +parse/0: product: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: instruction: 32 parse/0: ingredient: {name: "abcd", value: 0, type: 0, properties: ["abcd": "literal-string"]} -parse/0: product: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: product: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: instruction: 100 -parse/0: ingredient: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: ingredient: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: ingredient: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: ingredient: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: product: {name: "3", value: 0, type: 3, properties: ["3": "boolean", "raw": ]} new/0: location -> 1 new/0: abc -> 0 diff --git a/cpp/.traces/string-equal-identical b/cpp/.traces/string-equal-identical index 164582af..3e16bee4 100644 --- a/cpp/.traces/string-equal-identical +++ b/cpp/.traces/string-equal-identical @@ -1,16 +1,16 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]} -parse/0: product: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: instruction: 31 +parse/0: product: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: instruction: 32 parse/0: ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]} -parse/0: product: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: product: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: instruction: 100 -parse/0: ingredient: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: ingredient: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: ingredient: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: ingredient: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: product: {name: "3", value: 0, type: 3, properties: ["3": "boolean", "raw": ]} new/0: location -> 1 new/0: abc -> 0 @@ -78,22 +78,22 @@ mem/0: location 1046 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1040 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 0 run/0: address to copy is 1031 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1031 is 97 run/0: product 0 is 97 mem/0: storing 97 in location 1047 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1042 is 1034 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 0 run/0: address to copy is 1035 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1035 is 97 run/0: product 0 is 97 mem/0: storing 97 in location 1048 @@ -130,22 +130,22 @@ mem/0: location 1046 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1040 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 1 run/0: address to copy is 1032 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1032 is 98 run/0: product 0 is 98 mem/0: storing 98 in location 1047 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1042 is 1034 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 1 run/0: address to copy is 1036 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1036 is 98 run/0: product 0 is 98 mem/0: storing 98 in location 1048 @@ -182,22 +182,22 @@ mem/0: location 1046 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1040 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 2 run/0: address to copy is 1033 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1033 is 99 run/0: product 0 is 99 mem/0: storing 99 in location 1047 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1042 is 1034 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1045 is 2 run/0: address to copy is 1037 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1037 is 99 run/0: product 0 is 99 mem/0: storing 99 in location 1048 diff --git a/cpp/.traces/string-equal-reflexive b/cpp/.traces/string-equal-reflexive index 2a629bbb..3b478725 100644 --- a/cpp/.traces/string-equal-reflexive +++ b/cpp/.traces/string-equal-reflexive @@ -1,13 +1,13 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]} -parse/0: product: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} +parse/0: product: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} parse/0: instruction: 100 -parse/0: ingredient: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: ingredient: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} +parse/0: ingredient: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: ingredient: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} parse/0: product: {name: "3", value: 0, type: 3, properties: ["3": "boolean", "raw": ]} new/0: location -> 1 new/0: abc -> 0 @@ -70,22 +70,22 @@ mem/0: location 1042 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1036 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1041 is 0 run/0: address to copy is 1031 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1031 is 97 run/0: product 0 is 97 mem/0: storing 97 in location 1043 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1038 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1041 is 0 run/0: address to copy is 1031 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1031 is 97 run/0: product 0 is 97 mem/0: storing 97 in location 1044 @@ -122,22 +122,22 @@ mem/0: location 1042 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1036 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1041 is 1 run/0: address to copy is 1032 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1032 is 98 run/0: product 0 is 98 mem/0: storing 98 in location 1043 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1038 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1041 is 1 run/0: address to copy is 1032 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1032 is 98 run/0: product 0 is 98 mem/0: storing 98 in location 1044 @@ -174,22 +174,22 @@ mem/0: location 1042 is 0 run/0: ingredient 0 is 0 run/0: jump-if fell through run/0: instruction string-equal/16 -run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-8, properties: ["a": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "a", value: 1, type: 2-5-4, properties: ["a": "address":"array":"character", "deref": ]} mem/0: location 1036 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1041 is 2 run/0: address to copy is 1033 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1033 is 99 run/0: product 0 is 99 mem/0: storing 99 in location 1043 run/0: instruction string-equal/17 -run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-8, properties: ["b": "address":"array":"character", "deref": ]} +run/0: ingredient 0 is {name: "b", value: 3, type: 2-5-4, properties: ["b": "address":"array":"character", "deref": ]} mem/0: location 1038 is 1030 run/0: ingredient 1 is {name: "i", value: 6, type: 1, properties: ["i": "integer"]} mem/0: location 1041 is 2 run/0: address to copy is 1033 -run/0: its type is 8 +run/0: its type is 4 mem/0: location 1033 is 99 run/0: product 0 is 99 mem/0: storing 99 in location 1044 diff --git a/cpp/.traces/string-equal-with-empty b/cpp/.traces/string-equal-with-empty index 803e017b..2d10802e 100644 --- a/cpp/.traces/string-equal-with-empty +++ b/cpp/.traces/string-equal-with-empty @@ -1,16 +1,16 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]} parse/0: ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]} parse/0: product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]} -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "", value: 0, type: 0, properties: ["": "literal-string"]} -parse/0: product: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: instruction: 31 +parse/0: product: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: instruction: 32 parse/0: ingredient: {name: "abcd", value: 0, type: 0, properties: ["abcd": "literal-string"]} -parse/0: product: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: product: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: instruction: 100 -parse/0: ingredient: {name: "x", value: 0, type: 2-5-8, properties: ["x": "address":"array":"character"]} -parse/0: ingredient: {name: "y", value: 0, type: 2-5-8, properties: ["y": "address":"array":"character"]} +parse/0: ingredient: {name: "x", value: 0, type: 2-5-4, properties: ["x": "address":"array":"character"]} +parse/0: ingredient: {name: "y", value: 0, type: 2-5-4, properties: ["y": "address":"array":"character"]} parse/0: product: {name: "3", value: 0, type: 3, properties: ["3": "boolean", "raw": ]} new/0: location -> 1 new/0: -> 0 diff --git a/cpp/.traces/string_literal b/cpp/.traces/string_literal index 0562305b..bca008a9 100644 --- a/cpp/.traces/string_literal +++ b/cpp/.traces/string_literal @@ -1,8 +1,3 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc def", value: 0, type: 0, properties: ["abc def": "literal-string"]} -parse/0: product: {name: "1", value: 0, type: 2-5-8, properties: ["1": "address":"array":"character"]} -new/0: abc def -> 0 -after-brace/0: recipe main -after-brace/0: new ... -run/0: instruction main/0 -mem/0: storing 1000 in location 1 +parse/0: product: {name: "1", value: 0, type: 2-5-4, properties: ["1": "address":"array":"character"]} diff --git a/cpp/.traces/string_literal_nested b/cpp/.traces/string_literal_nested index d91739ec..aad3dc98 100644 --- a/cpp/.traces/string_literal_nested +++ b/cpp/.traces/string_literal_nested @@ -1,8 +1,3 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc [def]", value: 0, type: 0, properties: ["abc [def]": "literal-string"]} -parse/0: product: {name: "1", value: 0, type: 2-5-8, properties: ["1": "address":"array":"character"]} -new/0: abc [def] -> 0 -after-brace/0: recipe main -after-brace/0: new ... -run/0: instruction main/0 -mem/0: storing 1000 in location 1 +parse/0: product: {name: "1", value: 0, type: 2-5-4, properties: ["1": "address":"array":"character"]} diff --git a/cpp/.traces/string_literal_with_colons b/cpp/.traces/string_literal_with_colons index cf30be82..65a458fe 100644 --- a/cpp/.traces/string_literal_with_colons +++ b/cpp/.traces/string_literal_with_colons @@ -1,8 +1,3 @@ -parse/0: instruction: 31 +parse/0: instruction: 32 parse/0: ingredient: {name: "abc:def/ghi", value: 0, type: 0, properties: ["abc:def/ghi": "literal-string"]} -parse/0: product: {name: "1", value: 0, type: 2-5-8, properties: ["1": "address":"array":"character"]} -new/0: abc:def/ghi -> 0 -after-brace/0: recipe main -after-brace/0: new ... -run/0: instruction main/0 -mem/0: storing 1000 in location 1 +parse/0: product: {name: "1", value: 0, type: 2-5-4, properties: ["1": "address":"array":"character"]} diff --git a/cpp/.traces/trace b/cpp/.traces/trace index fb4fd081..2ef6ce77 100644 --- a/cpp/.traces/trace +++ b/cpp/.traces/trace @@ -1,4 +1,4 @@ -parse/0: instruction: 32 +parse/0: instruction: 18 parse/0: ingredient: {name: "foo", value: 0, type: 0, properties: ["foo": "literal-string"]} parse/0: ingredient: {name: "this is a trace in mu", value: 0, type: 0, properties: ["this is a trace in mu": "literal-string"]} after-brace/0: recipe main diff --git a/cpp/.traces/trace_in_mu b/cpp/.traces/trace_in_mu index dc7d8d8a..1d0be2b2 100644 --- a/cpp/.traces/trace_in_mu +++ b/cpp/.traces/trace_in_mu @@ -1,4 +1,4 @@ -parse/0: instruction: 32 +parse/0: instruction: 18 parse/0: ingredient: {name: "foo", value: 0, type: 0, properties: ["foo": "literal-string"]} parse/0: ingredient: {name: "aaa", value: 0, type: 0, properties: ["aaa": "literal-string"]} after-brace/0: recipe test-trace_in_mu diff --git a/cpp/013literal_string b/cpp/013literal_string new file mode 100644 index 00000000..f56cb928 --- /dev/null +++ b/cpp/013literal_string @@ -0,0 +1,63 @@ +//: Some instructions can take string literals for convenience. +//: +//: Instead of quotes, we'll use [] to delimit strings. That'll reduce the +//: need for escaping since we can support nested brackets. And we can also +//: imagine that 'recipe' might one day itself be defined in mu, doing its own +//: parsing. + +//: First extend the mu parser to support string literals. +:(scenario "string_literal") +recipe main [ + 1:address:array:character <- new [abc def] +] ++parse: ingredient: {name: "abc def", value: 0, type: 0, properties: ["abc def": "literal-string"]} + +:(scenario "string_literal_with_colons") +recipe main [ + 1:address:array:character <- new [abc:def/ghi] +] ++parse: ingredient: {name: "abc:def/ghi", value: 0, type: 0, properties: ["abc:def/ghi": "literal-string"]} + +:(before "End Mu Types Initialization") +Type_number["literal-string"] = 0; + +:(after "string next_word(istream& in)") +if (in.peek() == '[') return slurp_quoted(in); + +:(code) +string slurp_quoted(istream& in) { + assert(!in.eof()); + assert(in.peek() == '['); + ostringstream out; + int size = 0; + while (!in.eof()) { + char c = in.get(); +//? cout << c << '\n'; //? 1 + out << c; +//? cout << out.str() << "$\n"; //? 1 + if (c == '[') ++size; + if (c == ']') --size; + if (size == 0) break; + } + return out.str(); +} + +:(after "reagent::reagent(string s)") +//? cout << s[0] << '\n'; //? 1 + if (s[0] == '[') { + assert(s[s.size()-1] == ']'); + // delete [] delimiters + s.erase(0, 1); + s.erase(s.size()-1, s.size()); + name = s; + types.push_back(0); + properties.push_back(pair >(name, vector())); + properties.back().second.push_back("literal-string"); + return; + } + +:(scenario "string_literal_nested") +recipe main [ + 1:address:array:character <- new [abc [def]] +] ++parse: ingredient: {name: "abc [def]", value: 0, type: 0, properties: ["abc [def]": "literal-string"]} diff --git a/cpp/013run b/cpp/013run deleted file mode 100644 index 91e242a7..00000000 --- a/cpp/013run +++ /dev/null @@ -1,187 +0,0 @@ -:(scenarios run) -:(scenario copy_literal) -recipe main [ - 1:integer <- copy 23:literal -] -+run: instruction main/0 -+run: ingredient 0 is 23 -+mem: storing 23 in location 1 - -:(scenario copy) -recipe main [ - 1:integer <- copy 23:literal - 2:integer <- copy 1:integer -] -+run: instruction main/1 -+run: ingredient 0 is 1 -+mem: location 1 is 23 -+mem: storing 23 in location 2 - -:(before "End Types") -// Book-keeping while running a recipe. -//: Later layers will change this. -struct routine { - recipe_number running_recipe; - size_t running_at; - routine(recipe_number r) :running_recipe(r), running_at(0) {} -}; - -:(before "End Globals") -routine* Current_routine = NULL; - -:(code) -void run(recipe_number r) { - run(routine(r)); -} - -void run(routine rr) { - Current_routine = &rr; - while (!done(rr)) { - vector& instructions = steps(rr); - size_t& pc = running_at(rr); - // Running one instruction. - if (instructions[pc].is_label) { ++pc; continue; } -//? cout << "AAA " << Trace_stream << " ^" << Trace_stream->dump_layer << "$\n"; //? 1 - trace("run") << "instruction " << recipe_name(rr) << '/' << pc; -//? cout << "operation " << instructions[pc].operation << '\n'; //? 3 -//? if (!instructions[pc].products.empty()) trace("foo") << "AAA product 0 is " << instructions[pc].products[0].to_string(); //? 1 - switch (instructions[pc].operation) { - // Primitive Recipe Implementations - case COPY: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector data = read_memory(instructions[pc].ingredients[0]); - write_memory(instructions[pc].products[0], data); - break; - } - // End Primitive Recipe Implementations - default: { - cout << "not a primitive op: " << instructions[pc].operation << '\n'; - } - } - ++pc; - } - Current_routine = NULL; -} - -//: Some helpers. -//: We'll need to override these later as we change the definition of routine. -//: Important that they return referrences into the routine. -inline size_t& running_at(routine& rr) { - return rr.running_at; -} - -inline string recipe_name(routine& rr) { - return Recipe[rr.running_recipe].name; -} - -inline vector& steps(routine& rr) { - return Recipe[rr.running_recipe].steps; -} - -inline bool done(routine& rr) { - return running_at(rr) >= steps(rr).size(); -} - -:(before "End Main") -if (argc > 1) { - setup(); - for (int i = 1; i < argc; ++i) { - load(argv[i]); - } - - Trace_stream = new trace_stream; -//? Trace_stream->dump_layer = "all"; //? 2 - transform_all(); - recipe_number r = Recipe_number[string("main")]; - if (r) run(r); - dump_memory(); -} - -:(code) -void load(string filename) { - ifstream fin(filename.c_str()); - if (!fin) { - raise << "no such file " << filename << '\n'; - return; - } - fin >> std::noskipws; - add_recipes(fin); - transform_all(); - fin.close(); -} - -//: On startup, load everything in core.mu -:(before "End Load Recipes") -load("core.mu"); -recently_added_recipes.clear(); // freeze everything so it doesn't get cleared by tests - -//: helper for tests - -:(code) -void run(string form) { - vector tmp = add_recipes(form); - transform_all(); - run(tmp.front()); -} - -:(code) -vector read_memory(reagent x) { -//? cout << "read_memory: " << x.to_string() << '\n'; //? 1 - vector result; - if (isa_literal(x)) { - result.push_back(x.value); - return result; - } - int base = x.value; - size_t size = size_of(x); - for (size_t offset = 0; offset < size; ++offset) { - int val = Memory[base+offset]; - trace("mem") << "location " << base+offset << " is " << val; - result.push_back(val); - } - return result; -} - -void write_memory(reagent x, vector data) { - if (is_dummy(x)) return; - int base = x.value; - if (size_of(x) != data.size()) - raise << "size mismatch in storing to " << x.to_string() << '\n'; - for (size_t offset = 0; offset < data.size(); ++offset) { - trace("mem") << "storing " << data[offset] << " in location " << base+offset; - Memory[base+offset] = data[offset]; - } -} - -:(code) -size_t size_of(const reagent& r) { - return size_of(r.types); -} -size_t size_of(const vector& types) { - // End size_of(types) Cases - return 1; -} - -bool is_dummy(const reagent& x) { - return x.name == "_"; -} - -bool isa_literal(const reagent& r) { - return r.types.size() == 1 && r.types[0] == 0; -} - -:(scenario run_label) -recipe main [ - +foo - 1:integer <- copy 23:literal - 2:integer <- copy 1:integer -] -+run: instruction main/1 -+run: instruction main/2 --run: instruction main/0 - -:(scenario run_dummy) -recipe main [ - _ <- copy 0:literal -] -+run: instruction main/0 diff --git a/cpp/014arithmetic b/cpp/014arithmetic deleted file mode 100644 index 08647cbc..00000000 --- a/cpp/014arithmetic +++ /dev/null @@ -1,225 +0,0 @@ -:(before "End Primitive Recipe Declarations") -// Arithmetic ops. -ADD, -:(before "End Primitive Recipe Numbers") -Recipe_number["add"] = ADD; -:(before "End Primitive Recipe Implementations") -case ADD: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] + arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "add_literal") -recipe main [ - 1:integer <- add 23:literal, 34:literal -] -+run: instruction main/0 -+run: ingredient 0 is 23 -+run: ingredient 1 is 34 -+run: product 0 is 57 -+mem: storing 57 in location 1 - -:(scenario "add") -recipe main [ - 1:integer <- copy 23:literal - 2:integer <- copy 34:literal - 3:integer <- add 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 23 -+run: ingredient 1 is 2 -+mem: location 2 is 34 -+run: product 0 is 57 -+mem: storing 57 in location 3 - -:(before "End Primitive Recipe Declarations") -SUBTRACT, -:(before "End Primitive Recipe Numbers") -Recipe_number["subtract"] = SUBTRACT; -:(before "End Primitive Recipe Implementations") -case SUBTRACT: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] - arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "subtract_literal") -recipe main [ - 1:integer <- subtract 5:literal, 2:literal -] -+run: instruction main/0 -+run: ingredient 0 is 5 -+run: ingredient 1 is 2 -+run: product 0 is 3 -+mem: storing 3 in location 1 - -:(scenario "subtract") -recipe main [ - 1:integer <- copy 23:literal - 2:integer <- copy 34:literal - 3:integer <- subtract 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 23 -+run: ingredient 1 is 2 -+mem: location 2 is 34 -+run: product 0 is -11 -+mem: storing -11 in location 3 - -:(before "End Primitive Recipe Declarations") -MULTIPLY, -:(before "End Primitive Recipe Numbers") -Recipe_number["multiply"] = MULTIPLY; -:(before "End Primitive Recipe Implementations") -case MULTIPLY: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - trace("run") << "ingredient 1 is " << arg1[0]; - vector result; - result.push_back(arg0[0] * arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "multiply_literal") -recipe main [ - 1:integer <- multiply 2:literal, 3:literal -] -+run: instruction main/0 -+run: ingredient 0 is 2 -+run: ingredient 1 is 3 -+run: product 0 is 6 -+mem: storing 6 in location 1 - -:(scenario "multiply") -recipe main [ - 1:integer <- copy 4:literal - 2:integer <- copy 6:literal - 3:integer <- multiply 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 4 -+run: ingredient 1 is 2 -+mem: location 2 is 6 -+run: product 0 is 24 -+mem: storing 24 in location 3 - -:(before "End Primitive Recipe Declarations") -DIVIDE, -:(before "End Primitive Recipe Numbers") -Recipe_number["divide"] = DIVIDE; -:(before "End Primitive Recipe Implementations") -case DIVIDE: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - trace("run") << "ingredient 1 is " << arg1[0]; - vector result; - result.push_back(arg0[0] / arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "divide_literal") -recipe main [ - 1:integer <- divide 8:literal, 2:literal -] -+run: instruction main/0 -+run: ingredient 0 is 8 -+run: ingredient 1 is 2 -+run: product 0 is 4 -+mem: storing 4 in location 1 - -:(scenario "divide") -recipe main [ - 1:integer <- copy 27:literal - 2:integer <- copy 3:literal - 3:integer <- divide 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 27 -+run: ingredient 1 is 2 -+mem: location 2 is 3 -+run: product 0 is 9 -+mem: storing 9 in location 3 - -:(before "End Primitive Recipe Declarations") -DIVIDE_WITH_REMAINDER, -:(before "End Primitive Recipe Numbers") -Recipe_number["divide_with_remainder"] = DIVIDE_WITH_REMAINDER; -:(before "End Primitive Recipe Implementations") -case DIVIDE_WITH_REMAINDER: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result0; - result0.push_back(arg0[0] / arg1[0]); - trace("run") << "product 0 is " << result0[0]; - write_memory(instructions[pc].products[0], result0); - vector result1; - result1.push_back(arg0[0] % arg1[0]); - trace("run") << "product 1 is " << result1[0]; - write_memory(instructions[pc].products[1], result1); - break; -} - -:(scenario "divide_with_remainder_literal") -recipe main [ - 1:integer, 2:integer <- divide_with_remainder 9:literal, 2:literal -] -+run: instruction main/0 -+run: ingredient 0 is 9 -+run: ingredient 1 is 2 -+run: product 0 is 4 -+mem: storing 4 in location 1 -+run: product 1 is 1 -+mem: storing 1 in location 2 - -:(scenario "divide_with_remainder") -recipe main [ - 1:integer <- copy 27:literal - 2:integer <- copy 11:literal - 3:integer, 4:integer <- divide_with_remainder 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 27 -+run: ingredient 1 is 2 -+mem: location 2 is 11 -+run: product 0 is 2 -+mem: storing 2 in location 3 -+run: product 1 is 5 -+mem: storing 5 in location 4 diff --git a/cpp/015boolean b/cpp/015boolean deleted file mode 100644 index 6c677f7e..00000000 --- a/cpp/015boolean +++ /dev/null @@ -1,93 +0,0 @@ -:(before "End Primitive Recipe Declarations") -// Boolean ops. -AND, -:(before "End Primitive Recipe Numbers") -Recipe_number["and"] = AND; -:(before "End Primitive Recipe Implementations") -case AND: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] && arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "and") -recipe main [ - 1:integer <- copy 1:literal - 2:integer <- copy 0:literal - 3:integer <- and 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 1 -+run: ingredient 1 is 2 -+mem: location 2 is 0 -+run: product 0 is 0 -+mem: storing 0 in location 3 - -:(before "End Primitive Recipe Declarations") -OR, -:(before "End Primitive Recipe Numbers") -Recipe_number["or"] = OR; -:(before "End Primitive Recipe Implementations") -case OR: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] || arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "or") -recipe main [ - 1:integer <- copy 1:literal - 2:integer <- copy 0:literal - 3:integer <- or 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 1 -+run: ingredient 1 is 2 -+mem: location 2 is 0 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(before "End Primitive Recipe Declarations") -NOT, -:(before "End Primitive Recipe Numbers") -Recipe_number["not"] = NOT; -:(before "End Primitive Recipe Implementations") -case NOT: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - vector result; - result.push_back(!arg0[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "not") -recipe main [ - 1:integer <- copy 1:literal - 2:integer <- not 1:integer -] -+run: instruction main/1 -+run: ingredient 0 is 1 -+mem: location 1 is 1 -+run: product 0 is 0 -+mem: storing 0 in location 2 diff --git a/cpp/016jump b/cpp/016jump deleted file mode 100644 index 669c7258..00000000 --- a/cpp/016jump +++ /dev/null @@ -1,114 +0,0 @@ -:(before "End Primitive Recipe Declarations") -// Jump ops. -JUMP, -:(before "End Primitive Recipe Numbers") -Recipe_number["jump"] = JUMP; -:(before "End Primitive Recipe Implementations") -case JUMP: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].value; - pc += instructions[pc].ingredients[0].value; - trace("run") << "pc now " << pc; - break; -} - -:(scenario "jump_can_skip_instructions") -recipe main [ - jump 1:offset - 1:integer <- copy 1:literal -] -+run: instruction main/0 -+run: ingredient 0 is 1 --run: instruction main/1 --mem: storing 1 in location 1 - -:(scenario "jump_backward") -recipe main [ - jump 1:offset # 0 -+ - jump 1:offset # | +-+ 1 - # \/ /\ | - jump -2:offset # 2 +-->+ | -] # \/ 3 -+run: instruction main/0 -+run: instruction main/2 -+run: instruction main/1 - -:(before "End Primitive Recipe Declarations") -JUMP_IF, -:(before "End Primitive Recipe Numbers") -Recipe_number["jump-if"] = JUMP_IF; -:(before "End Primitive Recipe Implementations") -case JUMP_IF: { - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 0 is " << arg0[0]; - if (!arg0[0]) { - trace("run") << "jump-if fell through"; - break; - } - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - pc += instructions[pc].ingredients[1].value; - trace("run") << "jumping to instruction " << pc+1; - break; -} - -:(scenario "jump_if") -recipe main [ - jump-if 999:literal 1:offset - 1:integer <- copy 1:literal -] -+run: instruction main/0 -+run: ingredient 1 is 1 -+run: jumping to instruction 2 --run: instruction main/1 --mem: storing 1 in location 1 - -:(scenario "jump_if_fallthrough") -recipe main [ - jump-if 0:literal 1:offset - 123:integer <- copy 1:literal -] -+run: instruction main/0 -+run: jump-if fell through -+run: instruction main/1 -+mem: storing 1 in location 123 - -:(before "End Primitive Recipe Declarations") -JUMP_UNLESS, -:(before "End Primitive Recipe Numbers") -Recipe_number["jump-unless"] = JUMP_UNLESS; -:(before "End Primitive Recipe Implementations") -case JUMP_UNLESS: { - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 0 is " << arg0[0]; - if (arg0[0]) { - trace("run") << "jump-unless fell through"; - break; - } - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - pc += instructions[pc].ingredients[1].value; - trace("run") << "jumping to instruction " << pc+1; - break; -} - -:(scenario "jump_unless") -recipe main [ - jump-unless 0:literal 1:offset - 1:integer <- copy 1:literal -] -+run: instruction main/0 -+run: ingredient 1 is 1 -+run: jumping to instruction 2 --run: instruction main/1 --mem: storing 1 in location 1 - -:(scenario "jump_unless_fallthrough") -recipe main [ - jump-unless 999:literal 1:offset - 123:integer <- copy 1:literal -] -+run: instruction main/0 -+run: ingredient 0 is 999 -+run: jump-unless fell through -+run: instruction main/1 -+mem: storing 1 in location 123 diff --git a/cpp/017compare b/cpp/017compare deleted file mode 100644 index 145feaa2..00000000 --- a/cpp/017compare +++ /dev/null @@ -1,261 +0,0 @@ -:(before "End Primitive Recipe Declarations") -// Comparison ops. -EQUAL, -:(before "End Primitive Recipe Numbers") -Recipe_number["equal"] = EQUAL; -:(before "End Primitive Recipe Implementations") -case EQUAL: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - vector result; - result.push_back(equal(arg0.begin(), arg0.end(), arg1.begin())); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "equal") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 33:literal - 3:integer <- equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 0 -+mem: storing 0 in location 3 - -:(scenario "equal2") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 34:literal - 3:integer <- equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 34 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(before "End Primitive Recipe Declarations") -GREATER_THAN, -:(before "End Primitive Recipe Numbers") -Recipe_number["greater-than"] = GREATER_THAN; -:(before "End Primitive Recipe Implementations") -case GREATER_THAN: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] > arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "greater_than") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 33:literal - 3:integer <- greater-than 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(scenario "greater_than2") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 34:literal - 3:integer <- greater-than 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 34 -+run: product 0 is 0 -+mem: storing 0 in location 3 - -:(before "End Primitive Recipe Declarations") -LESSER_THAN, -:(before "End Primitive Recipe Numbers") -Recipe_number["lesser-than"] = LESSER_THAN; -:(before "End Primitive Recipe Implementations") -case LESSER_THAN: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] < arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "lesser_than") -recipe main [ - 1:integer <- copy 32:literal - 2:integer <- copy 33:literal - 3:integer <- lesser-than 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 32 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(scenario "lesser_than2") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 33:literal - 3:integer <- lesser-than 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 0 -+mem: storing 0 in location 3 - -:(before "End Primitive Recipe Declarations") -GREATER_OR_EQUAL, -:(before "End Primitive Recipe Numbers") -Recipe_number["greater-or-equal"] = GREATER_OR_EQUAL; -:(before "End Primitive Recipe Implementations") -case GREATER_OR_EQUAL: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] >= arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "greater_or_equal") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 33:literal - 3:integer <- greater-or-equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(scenario "greater_or_equal2") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 34:literal - 3:integer <- greater-or-equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 34 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(scenario "greater_or_equal3") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 35:literal - 3:integer <- greater-or-equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 35 -+run: product 0 is 0 -+mem: storing 0 in location 3 - -:(before "End Primitive Recipe Declarations") -LESSER_OR_EQUAL, -:(before "End Primitive Recipe Numbers") -Recipe_number["lesser-or-equal"] = LESSER_OR_EQUAL; -:(before "End Primitive Recipe Implementations") -case LESSER_OR_EQUAL: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - vector arg0 = read_memory(instructions[pc].ingredients[0]); - assert(arg0.size() == 1); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - vector arg1 = read_memory(instructions[pc].ingredients[1]); - assert(arg1.size() == 1); - vector result; - result.push_back(arg0[0] <= arg1[0]); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -:(scenario "lesser_or_equal") -recipe main [ - 1:integer <- copy 32:literal - 2:integer <- copy 33:literal - 3:integer <- lesser-or-equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 32 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(scenario "lesser_or_equal2") -recipe main [ - 1:integer <- copy 33:literal - 2:integer <- copy 33:literal - 3:integer <- lesser-or-equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 33 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 1 -+mem: storing 1 in location 3 - -:(scenario "lesser_or_equal3") -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 33:literal - 3:integer <- lesser-or-equal 1:integer, 2:integer -] -+run: instruction main/2 -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+run: ingredient 1 is 2 -+mem: location 2 is 33 -+run: product 0 is 0 -+mem: storing 0 in location 3 diff --git a/cpp/020container b/cpp/020container deleted file mode 100644 index fcdd82f9..00000000 --- a/cpp/020container +++ /dev/null @@ -1,167 +0,0 @@ -//: Containers contain a fixed number of elements of different types. -:(before "End Mu Types Initialization") -//: We'll use this container as a running example, with two integer elements. -int point = Type_number["point"] = Next_type_number++; -Type[point].size = 2; -Type[point].kind = container; -Type[point].name = "point"; -vector i; -i.push_back(integer); -Type[point].elements.push_back(i); -Type[point].elements.push_back(i); - -:(scenario copy_multiple_locations) -# Containers can be copied around with a single instruction just like integers, -# no matter how large they are. -recipe main [ - 1:integer <- copy 34:literal - 2:integer <- copy 35:literal - 3:point <- copy 1:point -] -+run: ingredient 0 is 1 -+mem: location 1 is 34 -+mem: location 2 is 35 -+mem: storing 34 in location 3 -+mem: storing 35 in location 4 - -:(before "End Mu Types Initialization") -// A more complex container, containing another container as one of its -// elements. -int point_integer = Type_number["point-integer"] = Next_type_number++; -Type[point_integer].size = 2; -Type[point_integer].kind = container; -Type[point_integer].name = "point-integer"; -vector p2; -p2.push_back(point); -Type[point_integer].elements.push_back(p2); -vector i2; -i2.push_back(integer); -Type[point_integer].elements.push_back(i2); - -:(scenario "copy_handles_nested_container_elements") -recipe main [ - 12:integer <- copy 34:literal - 13:integer <- copy 35:literal - 14:integer <- copy 36:literal - 15:point-integer <- copy 12:point-integer -] -+mem: storing 36 in location 17 - -:(before "End size_of(types) Cases") -type_info t = Type[types[0]]; -if (t.kind == container) { - size_t result = 0; - for (size_t i = 0; i < t.elements.size(); ++i) { - result += size_of(t.elements[i]); - } - return result; -} - -//: To access elements of a container, use 'get' -:(scenario "get") -recipe main [ - 12:integer <- copy 34:literal - 13:integer <- copy 35:literal - 15:integer <- get 12:point, 1:offset -] -+run: instruction main/2 -+run: ingredient 0 is 12 -+run: ingredient 1 is 1 -+run: address to copy is 13 -+run: its type is 1 -+mem: location 13 is 35 -+run: product 0 is 35 -+mem: storing 35 in location 15 - -:(before "End Primitive Recipe Declarations") -GET, -:(before "End Primitive Recipe Numbers") -Recipe_number["get"] = GET; -:(before "End Primitive Recipe Implementations") -case GET: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - reagent base = instructions[pc].ingredients[0]; - int base_address = base.value; - int base_type = base.types[0]; - assert(Type[base_type].kind == container); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - assert(isa_literal(instructions[pc].ingredients[1])); - size_t offset = instructions[pc].ingredients[1].value; - int src = base_address; - for (size_t i = 0; i < offset; ++i) { - src += size_of(Type[base_type].elements[i]); - } - trace("run") << "address to copy is " << src; - assert(Type[base_type].kind == container); - assert(Type[base_type].elements.size() > offset); - int src_type = Type[base_type].elements[offset][0]; - trace("run") << "its type is " << src_type; - reagent tmp; - tmp.set_value(src); - tmp.types.push_back(src_type); - vector result(read_memory(tmp)); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} - -//: 'get' requires a literal in ingredient 1. We'll use a synonym called -//: 'offset' -:(before "End Mu Types Initialization") -Type_number["offset"] = 0; - -:(scenario "get_handles_nested_container_elements") -recipe main [ - 12:integer <- copy 34:literal - 13:integer <- copy 35:literal - 14:integer <- copy 36:literal - 15:integer <- get 12:point-integer, 1:offset -] -+run: instruction main/2 -+run: ingredient 0 is 12 -+run: ingredient 1 is 1 -+run: address to copy is 14 -+run: its type is 1 -+mem: location 14 is 36 -+run: product 0 is 36 -+mem: storing 36 in location 15 - -//: To write to elements of containers, you need their address. - -:(scenario "get_address") -recipe main [ - 12:integer <- copy 34:literal - 13:integer <- copy 35:literal - 15:address:integer <- get-address 12:point, 1:offset -] -+run: instruction main/2 -+run: ingredient 0 is 12 -+run: ingredient 1 is 1 -+run: address to copy is 13 -+mem: storing 13 in location 15 - -:(before "End Primitive Recipe Declarations") -GET_ADDRESS, -:(before "End Primitive Recipe Numbers") -Recipe_number["get-address"] = GET_ADDRESS; -:(before "End Primitive Recipe Implementations") -case GET_ADDRESS: { - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - reagent base = instructions[pc].ingredients[0]; - int base_address = base.value; - int base_type = base.types[0]; - assert(Type[base_type].kind == container); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; - assert(isa_literal(instructions[pc].ingredients[1])); - size_t offset = instructions[pc].ingredients[1].value; - int src = base_address; - for (size_t i = 0; i < offset; ++i) { - src += size_of(Type[base_type].elements[i]); - } - trace("run") << "address to copy is " << src; - vector result; - result.push_back(src); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} diff --git a/cpp/020run b/cpp/020run new file mode 100644 index 00000000..91e242a7 --- /dev/null +++ b/cpp/020run @@ -0,0 +1,187 @@ +:(scenarios run) +:(scenario copy_literal) +recipe main [ + 1:integer <- copy 23:literal +] ++run: instruction main/0 ++run: ingredient 0 is 23 ++mem: storing 23 in location 1 + +:(scenario copy) +recipe main [ + 1:integer <- copy 23:literal + 2:integer <- copy 1:integer +] ++run: instruction main/1 ++run: ingredient 0 is 1 ++mem: location 1 is 23 ++mem: storing 23 in location 2 + +:(before "End Types") +// Book-keeping while running a recipe. +//: Later layers will change this. +struct routine { + recipe_number running_recipe; + size_t running_at; + routine(recipe_number r) :running_recipe(r), running_at(0) {} +}; + +:(before "End Globals") +routine* Current_routine = NULL; + +:(code) +void run(recipe_number r) { + run(routine(r)); +} + +void run(routine rr) { + Current_routine = &rr; + while (!done(rr)) { + vector& instructions = steps(rr); + size_t& pc = running_at(rr); + // Running one instruction. + if (instructions[pc].is_label) { ++pc; continue; } +//? cout << "AAA " << Trace_stream << " ^" << Trace_stream->dump_layer << "$\n"; //? 1 + trace("run") << "instruction " << recipe_name(rr) << '/' << pc; +//? cout << "operation " << instructions[pc].operation << '\n'; //? 3 +//? if (!instructions[pc].products.empty()) trace("foo") << "AAA product 0 is " << instructions[pc].products[0].to_string(); //? 1 + switch (instructions[pc].operation) { + // Primitive Recipe Implementations + case COPY: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector data = read_memory(instructions[pc].ingredients[0]); + write_memory(instructions[pc].products[0], data); + break; + } + // End Primitive Recipe Implementations + default: { + cout << "not a primitive op: " << instructions[pc].operation << '\n'; + } + } + ++pc; + } + Current_routine = NULL; +} + +//: Some helpers. +//: We'll need to override these later as we change the definition of routine. +//: Important that they return referrences into the routine. +inline size_t& running_at(routine& rr) { + return rr.running_at; +} + +inline string recipe_name(routine& rr) { + return Recipe[rr.running_recipe].name; +} + +inline vector& steps(routine& rr) { + return Recipe[rr.running_recipe].steps; +} + +inline bool done(routine& rr) { + return running_at(rr) >= steps(rr).size(); +} + +:(before "End Main") +if (argc > 1) { + setup(); + for (int i = 1; i < argc; ++i) { + load(argv[i]); + } + + Trace_stream = new trace_stream; +//? Trace_stream->dump_layer = "all"; //? 2 + transform_all(); + recipe_number r = Recipe_number[string("main")]; + if (r) run(r); + dump_memory(); +} + +:(code) +void load(string filename) { + ifstream fin(filename.c_str()); + if (!fin) { + raise << "no such file " << filename << '\n'; + return; + } + fin >> std::noskipws; + add_recipes(fin); + transform_all(); + fin.close(); +} + +//: On startup, load everything in core.mu +:(before "End Load Recipes") +load("core.mu"); +recently_added_recipes.clear(); // freeze everything so it doesn't get cleared by tests + +//: helper for tests + +:(code) +void run(string form) { + vector tmp = add_recipes(form); + transform_all(); + run(tmp.front()); +} + +:(code) +vector read_memory(reagent x) { +//? cout << "read_memory: " << x.to_string() << '\n'; //? 1 + vector result; + if (isa_literal(x)) { + result.push_back(x.value); + return result; + } + int base = x.value; + size_t size = size_of(x); + for (size_t offset = 0; offset < size; ++offset) { + int val = Memory[base+offset]; + trace("mem") << "location " << base+offset << " is " << val; + result.push_back(val); + } + return result; +} + +void write_memory(reagent x, vector data) { + if (is_dummy(x)) return; + int base = x.value; + if (size_of(x) != data.size()) + raise << "size mismatch in storing to " << x.to_string() << '\n'; + for (size_t offset = 0; offset < data.size(); ++offset) { + trace("mem") << "storing " << data[offset] << " in location " << base+offset; + Memory[base+offset] = data[offset]; + } +} + +:(code) +size_t size_of(const reagent& r) { + return size_of(r.types); +} +size_t size_of(const vector& types) { + // End size_of(types) Cases + return 1; +} + +bool is_dummy(const reagent& x) { + return x.name == "_"; +} + +bool isa_literal(const reagent& r) { + return r.types.size() == 1 && r.types[0] == 0; +} + +:(scenario run_label) +recipe main [ + +foo + 1:integer <- copy 23:literal + 2:integer <- copy 1:integer +] ++run: instruction main/1 ++run: instruction main/2 +-run: instruction main/0 + +:(scenario run_dummy) +recipe main [ + _ <- copy 0:literal +] ++run: instruction main/0 diff --git a/cpp/021address b/cpp/021address deleted file mode 100644 index 22355fc6..00000000 --- a/cpp/021address +++ /dev/null @@ -1,117 +0,0 @@ -//: Instructions can read from addresses pointing at other locations using the -//: 'deref' property. -:(scenario "copy_indirect") -recipe main [ - 1:address:integer <- copy 2:literal - 2:integer <- copy 34:literal - # This loads location 1 as an address and looks up *that* location. - 3:integer <- copy 1:address:integer/deref -] -+run: instruction main/2 -+mem: location 1 is 2 -+mem: location 2 is 34 -+mem: storing 34 in location 3 - -:(before "int base = x.value" following "vector read_memory(reagent x)") -x = canonize(x); - -//: similarly, write to addresses pointing at other locations using the -//: 'deref' property -:(scenario "store_indirect") -recipe main [ - 1:address:integer <- copy 2:literal - 1:address:integer/deref <- copy 34:literal -] -+run: instruction main/1 -+mem: location 1 is 2 -+mem: storing 34 in location 2 - -:(before "int base = x.value" following "void write_memory(reagent x, vector data)") -x = canonize(x); - -:(code) -reagent canonize(reagent x) { -//? cout << "canonize\n"; //? 1 - reagent r = x; -//? cout << x.to_string() << " => " << r.to_string() << '\n'; //? 1 - while (has_property(r, "deref")) - r = deref(r); - return r; -} - -bool has_property(reagent x, string name) { - for (size_t i = 0; i < x.properties.size(); ++i) { - if (x.properties[i].first == name) return true; - } - return false; -} - -reagent deref(reagent x) { -//? cout << "deref: " << x.to_string() << "\n"; //? 2 - static const int ADDRESS = Type_number["address"]; - reagent result; - assert(x.types[0] == ADDRESS); - - // compute value - result.set_value(Memory[x.value]); - trace("mem") << "location " << x.value << " is " << result.value; - - // populate types - copy(++x.types.begin(), x.types.end(), inserter(result.types, result.types.begin())); - - // drop-one 'deref' - int i = 0; - int len = x.properties.size(); - for (i = 0; i < len; ++i) { - if (x.properties[i].first == "deref") break; - result.properties.push_back(x.properties[i]); - } - ++i; // skip first deref - for (; i < len; ++i) { - result.properties.push_back(x.properties[i]); - } - return result; -} - -//: 'get' can read from container address -:(scenario "get_indirect") -recipe main [ - 1:integer <- copy 2:literal - 2:integer <- copy 34:literal - 3:integer <- copy 35:literal - 4:integer <- get 1:address:point/deref, 0:offset -] -+run: instruction main/3 -+run: address to copy is 2 -+run: product 0 is 34 -+mem: storing 34 in location 4 - -:(scenario "include_nonderef_properties") -recipe main [ - 1:integer <- copy 2:literal - 2:integer <- copy 34:literal - 3:integer <- copy 35:literal - 4:integer <- get 1:address:point/deref/foo, 0:offset -] -+run: instruction main/3 -+run: address to copy is 2 -+run: product 0 is 34 -+mem: storing 34 in location 4 - -:(after "reagent base = " following "case GET:") -base = canonize(base); - -:(scenario "get_address_indirect") -# 'get' can read from container address -recipe main [ - 1:integer <- copy 2:literal - 2:integer <- copy 34:literal - 3:integer <- copy 35:literal - 4:integer <- get-address 1:address:point/deref, 0:offset -] -+run: instruction main/3 -+run: address to copy is 2 -+run: product 0 is 2 - -:(after "reagent base = " following "case GET_ADDRESS:") -base = canonize(base); diff --git a/cpp/021arithmetic b/cpp/021arithmetic new file mode 100644 index 00000000..08647cbc --- /dev/null +++ b/cpp/021arithmetic @@ -0,0 +1,225 @@ +:(before "End Primitive Recipe Declarations") +// Arithmetic ops. +ADD, +:(before "End Primitive Recipe Numbers") +Recipe_number["add"] = ADD; +:(before "End Primitive Recipe Implementations") +case ADD: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] + arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "add_literal") +recipe main [ + 1:integer <- add 23:literal, 34:literal +] ++run: instruction main/0 ++run: ingredient 0 is 23 ++run: ingredient 1 is 34 ++run: product 0 is 57 ++mem: storing 57 in location 1 + +:(scenario "add") +recipe main [ + 1:integer <- copy 23:literal + 2:integer <- copy 34:literal + 3:integer <- add 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 23 ++run: ingredient 1 is 2 ++mem: location 2 is 34 ++run: product 0 is 57 ++mem: storing 57 in location 3 + +:(before "End Primitive Recipe Declarations") +SUBTRACT, +:(before "End Primitive Recipe Numbers") +Recipe_number["subtract"] = SUBTRACT; +:(before "End Primitive Recipe Implementations") +case SUBTRACT: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] - arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "subtract_literal") +recipe main [ + 1:integer <- subtract 5:literal, 2:literal +] ++run: instruction main/0 ++run: ingredient 0 is 5 ++run: ingredient 1 is 2 ++run: product 0 is 3 ++mem: storing 3 in location 1 + +:(scenario "subtract") +recipe main [ + 1:integer <- copy 23:literal + 2:integer <- copy 34:literal + 3:integer <- subtract 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 23 ++run: ingredient 1 is 2 ++mem: location 2 is 34 ++run: product 0 is -11 ++mem: storing -11 in location 3 + +:(before "End Primitive Recipe Declarations") +MULTIPLY, +:(before "End Primitive Recipe Numbers") +Recipe_number["multiply"] = MULTIPLY; +:(before "End Primitive Recipe Implementations") +case MULTIPLY: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + trace("run") << "ingredient 1 is " << arg1[0]; + vector result; + result.push_back(arg0[0] * arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "multiply_literal") +recipe main [ + 1:integer <- multiply 2:literal, 3:literal +] ++run: instruction main/0 ++run: ingredient 0 is 2 ++run: ingredient 1 is 3 ++run: product 0 is 6 ++mem: storing 6 in location 1 + +:(scenario "multiply") +recipe main [ + 1:integer <- copy 4:literal + 2:integer <- copy 6:literal + 3:integer <- multiply 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 4 ++run: ingredient 1 is 2 ++mem: location 2 is 6 ++run: product 0 is 24 ++mem: storing 24 in location 3 + +:(before "End Primitive Recipe Declarations") +DIVIDE, +:(before "End Primitive Recipe Numbers") +Recipe_number["divide"] = DIVIDE; +:(before "End Primitive Recipe Implementations") +case DIVIDE: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + trace("run") << "ingredient 1 is " << arg1[0]; + vector result; + result.push_back(arg0[0] / arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "divide_literal") +recipe main [ + 1:integer <- divide 8:literal, 2:literal +] ++run: instruction main/0 ++run: ingredient 0 is 8 ++run: ingredient 1 is 2 ++run: product 0 is 4 ++mem: storing 4 in location 1 + +:(scenario "divide") +recipe main [ + 1:integer <- copy 27:literal + 2:integer <- copy 3:literal + 3:integer <- divide 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 27 ++run: ingredient 1 is 2 ++mem: location 2 is 3 ++run: product 0 is 9 ++mem: storing 9 in location 3 + +:(before "End Primitive Recipe Declarations") +DIVIDE_WITH_REMAINDER, +:(before "End Primitive Recipe Numbers") +Recipe_number["divide_with_remainder"] = DIVIDE_WITH_REMAINDER; +:(before "End Primitive Recipe Implementations") +case DIVIDE_WITH_REMAINDER: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result0; + result0.push_back(arg0[0] / arg1[0]); + trace("run") << "product 0 is " << result0[0]; + write_memory(instructions[pc].products[0], result0); + vector result1; + result1.push_back(arg0[0] % arg1[0]); + trace("run") << "product 1 is " << result1[0]; + write_memory(instructions[pc].products[1], result1); + break; +} + +:(scenario "divide_with_remainder_literal") +recipe main [ + 1:integer, 2:integer <- divide_with_remainder 9:literal, 2:literal +] ++run: instruction main/0 ++run: ingredient 0 is 9 ++run: ingredient 1 is 2 ++run: product 0 is 4 ++mem: storing 4 in location 1 ++run: product 1 is 1 ++mem: storing 1 in location 2 + +:(scenario "divide_with_remainder") +recipe main [ + 1:integer <- copy 27:literal + 2:integer <- copy 11:literal + 3:integer, 4:integer <- divide_with_remainder 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 27 ++run: ingredient 1 is 2 ++mem: location 2 is 11 ++run: product 0 is 2 ++mem: storing 2 in location 3 ++run: product 1 is 5 ++mem: storing 5 in location 4 diff --git a/cpp/022array b/cpp/022array deleted file mode 100644 index 3bdfe95e..00000000 --- a/cpp/022array +++ /dev/null @@ -1,152 +0,0 @@ -//: Arrays contain a variable number of elements of the same type. -:(scenario copy_array) -# Arrays can be copied around with a single instruction just like integers, -# no matter how large they are. -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 14:literal - 3:integer <- copy 15:literal - 4:integer <- copy 16:literal - 5:array:integer <- copy 1:array:integer -] -+run: instruction main/4 -+run: ingredient 0 is 1 -+mem: location 1 is 3 -+mem: location 2 is 14 -+mem: location 3 is 15 -+mem: location 4 is 16 -+mem: storing 3 in location 5 -+mem: storing 14 in location 6 -+mem: storing 15 in location 7 -+mem: storing 16 in location 8 - -//: disable the size mismatch check since the destination array need not be initialized -:(replace "if (size_of(x) != data.size())" following "void write_memory(reagent x, vector data)") -if (x.types[0] != Type_number["array"] && size_of(x) != data.size()) -:(after "size_t size_of(const reagent& r)") - static const int ARRAY = Type_number["array"]; - if (r.types[0] == ARRAY) { - assert(r.types.size() > 1); - // skip the 'array' type to get at the element type - return 1 + Memory[r.value]*size_of(array_element(r.types)); - } - -//: To access elements of an array, use 'index' -:(scenario "index") -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 14:literal - 3:integer <- copy 15:literal - 4:integer <- copy 16:literal - 5:integer <- index 1:array:integer, 0:literal -] -+run: instruction main/4 -+run: address to copy is 2 -+run: its type is 1 -+mem: location 2 is 14 -+run: product 0 is 14 -+mem: storing 14 in location 5 - -:(scenario "index_direct_offset") -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 14:literal - 3:integer <- copy 15:literal - 4:integer <- copy 16:literal - 5:integer <- copy 0:literal - 6:integer <- index 1:array:integer, 5:integer -] -+run: instruction main/5 -+run: address to copy is 2 -+run: its type is 1 -+mem: location 2 is 14 -+run: product 0 is 14 -+mem: storing 14 in location 6 - -:(before "End Primitive Recipe Declarations") -INDEX, -:(before "End Primitive Recipe Numbers") -Recipe_number["index"] = INDEX; -:(before "End Primitive Recipe Implementations") -case INDEX: { - static const int ARRAY = Type_number["array"]; -//? if (Trace_stream) Trace_stream->dump_layer = "run"; //? 1 - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].to_string(); - reagent base = canonize(instructions[pc].ingredients[0]); -//? trace("run") << "ingredient 0 after canonize: " << instructions[pc].ingredients[0].to_string(); //? 1 - int base_address = base.value; - assert(base.types[0] == ARRAY); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].to_string(); - reagent offset = canonize(instructions[pc].ingredients[1]); - vector offset_val(read_memory(offset)); - vector element_type = array_element(base.types); - int src = base_address + 1 + offset_val[0]*size_of(element_type); - trace("run") << "address to copy is " << src; - trace("run") << "its type is " << element_type[0]; - reagent tmp; - tmp.set_value(src); - copy(element_type.begin(), element_type.end(), inserter(tmp.types, tmp.types.begin())); - tmp.properties.push_back(pair >("raw", vector())); -//? cout << "AAA: " << tmp.to_string() << '\n'; //? 2 - vector result(read_memory(tmp)); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); -//? if (Trace_stream) Trace_stream->dump_layer = ""; //? 1 - break; -} - -:(code) -vector array_element(const vector& types) { - return vector(++types.begin(), types.end()); -} - -:(scenario "index_address") -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 14:literal - 3:integer <- copy 15:literal - 4:integer <- copy 16:literal - 5:integer <- index-address 1:array:integer, 0:literal -] -+run: instruction main/4 -+run: address to copy is 2 -+mem: storing 2 in location 5 - -//: To write to elements of containers, you need their address. - -:(scenario "index_indirect") -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 14:literal - 3:integer <- copy 15:literal - 4:integer <- copy 16:literal - 5:address:array:integer <- copy 1:literal - 6:integer <- index 5:address:array:integer/deref, 1:literal -] -+run: instruction main/5 -+mem: storing 15 in location 6 -// vim:ft=cpp - -:(before "End Primitive Recipe Declarations") -INDEX_ADDRESS, -:(before "End Primitive Recipe Numbers") -Recipe_number["index-address"] = INDEX_ADDRESS; -:(before "End Primitive Recipe Implementations") -case INDEX_ADDRESS: { - static const int ARRAY = Type_number["array"]; - trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; - reagent base = canonize(instructions[pc].ingredients[0]); - int base_address = base.value; - assert(base.types[0] == ARRAY); - trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].to_string(); - reagent offset = canonize(instructions[pc].ingredients[1]); - vector offset_val(read_memory(offset)); - vector element_type = array_element(base.types); - int src = base_address + 1 + offset_val[0]*size_of(element_type); - trace("run") << "address to copy is " << src; - vector result; - result.push_back(src); - trace("run") << "product 0 is " << result[0]; - write_memory(instructions[pc].products[0], result); - break; -} diff --git a/cpp/022boolean b/cpp/022boolean new file mode 100644 index 00000000..6c677f7e --- /dev/null +++ b/cpp/022boolean @@ -0,0 +1,93 @@ +:(before "End Primitive Recipe Declarations") +// Boolean ops. +AND, +:(before "End Primitive Recipe Numbers") +Recipe_number["and"] = AND; +:(before "End Primitive Recipe Implementations") +case AND: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] && arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "and") +recipe main [ + 1:integer <- copy 1:literal + 2:integer <- copy 0:literal + 3:integer <- and 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 1 ++run: ingredient 1 is 2 ++mem: location 2 is 0 ++run: product 0 is 0 ++mem: storing 0 in location 3 + +:(before "End Primitive Recipe Declarations") +OR, +:(before "End Primitive Recipe Numbers") +Recipe_number["or"] = OR; +:(before "End Primitive Recipe Implementations") +case OR: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] || arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "or") +recipe main [ + 1:integer <- copy 1:literal + 2:integer <- copy 0:literal + 3:integer <- or 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 1 ++run: ingredient 1 is 2 ++mem: location 2 is 0 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(before "End Primitive Recipe Declarations") +NOT, +:(before "End Primitive Recipe Numbers") +Recipe_number["not"] = NOT; +:(before "End Primitive Recipe Implementations") +case NOT: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + vector result; + result.push_back(!arg0[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "not") +recipe main [ + 1:integer <- copy 1:literal + 2:integer <- not 1:integer +] ++run: instruction main/1 ++run: ingredient 0 is 1 ++mem: location 1 is 1 ++run: product 0 is 0 ++mem: storing 0 in location 2 diff --git a/cpp/023jump b/cpp/023jump new file mode 100644 index 00000000..669c7258 --- /dev/null +++ b/cpp/023jump @@ -0,0 +1,114 @@ +:(before "End Primitive Recipe Declarations") +// Jump ops. +JUMP, +:(before "End Primitive Recipe Numbers") +Recipe_number["jump"] = JUMP; +:(before "End Primitive Recipe Implementations") +case JUMP: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].value; + pc += instructions[pc].ingredients[0].value; + trace("run") << "pc now " << pc; + break; +} + +:(scenario "jump_can_skip_instructions") +recipe main [ + jump 1:offset + 1:integer <- copy 1:literal +] ++run: instruction main/0 ++run: ingredient 0 is 1 +-run: instruction main/1 +-mem: storing 1 in location 1 + +:(scenario "jump_backward") +recipe main [ + jump 1:offset # 0 -+ + jump 1:offset # | +-+ 1 + # \/ /\ | + jump -2:offset # 2 +-->+ | +] # \/ 3 ++run: instruction main/0 ++run: instruction main/2 ++run: instruction main/1 + +:(before "End Primitive Recipe Declarations") +JUMP_IF, +:(before "End Primitive Recipe Numbers") +Recipe_number["jump-if"] = JUMP_IF; +:(before "End Primitive Recipe Implementations") +case JUMP_IF: { + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 0 is " << arg0[0]; + if (!arg0[0]) { + trace("run") << "jump-if fell through"; + break; + } + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + pc += instructions[pc].ingredients[1].value; + trace("run") << "jumping to instruction " << pc+1; + break; +} + +:(scenario "jump_if") +recipe main [ + jump-if 999:literal 1:offset + 1:integer <- copy 1:literal +] ++run: instruction main/0 ++run: ingredient 1 is 1 ++run: jumping to instruction 2 +-run: instruction main/1 +-mem: storing 1 in location 1 + +:(scenario "jump_if_fallthrough") +recipe main [ + jump-if 0:literal 1:offset + 123:integer <- copy 1:literal +] ++run: instruction main/0 ++run: jump-if fell through ++run: instruction main/1 ++mem: storing 1 in location 123 + +:(before "End Primitive Recipe Declarations") +JUMP_UNLESS, +:(before "End Primitive Recipe Numbers") +Recipe_number["jump-unless"] = JUMP_UNLESS; +:(before "End Primitive Recipe Implementations") +case JUMP_UNLESS: { + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 0 is " << arg0[0]; + if (arg0[0]) { + trace("run") << "jump-unless fell through"; + break; + } + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + pc += instructions[pc].ingredients[1].value; + trace("run") << "jumping to instruction " << pc+1; + break; +} + +:(scenario "jump_unless") +recipe main [ + jump-unless 0:literal 1:offset + 1:integer <- copy 1:literal +] ++run: instruction main/0 ++run: ingredient 1 is 1 ++run: jumping to instruction 2 +-run: instruction main/1 +-mem: storing 1 in location 1 + +:(scenario "jump_unless_fallthrough") +recipe main [ + jump-unless 999:literal 1:offset + 123:integer <- copy 1:literal +] ++run: instruction main/0 ++run: ingredient 0 is 999 ++run: jump-unless fell through ++run: instruction main/1 ++mem: storing 1 in location 123 diff --git a/cpp/023length b/cpp/023length deleted file mode 100644 index 9d3bb714..00000000 --- a/cpp/023length +++ /dev/null @@ -1,30 +0,0 @@ -//: Recipe to compute the length of an array. - -:(scenario "array_length") -recipe main [ - 1:integer <- copy 3:literal - 2:integer <- copy 14:literal - 3:integer <- copy 15:literal - 4:integer <- copy 16:literal - 5:integer <- length 1:array:integer -] -+run: instruction main/4 -+mem: storing 3 in location 5 - -:(before "End Primitive Recipe Declarations") -LENGTH, -:(before "End Primitive Recipe Numbers") -Recipe_number["length"] = LENGTH; -:(before "End Primitive Recipe Implementations") -case LENGTH: { - reagent x = canonize(instructions[pc].ingredients[0]); - if (x.types[0] != Type_number["array"]) { - raise << "tried to calculate length of non-array " << x.to_string() << '\n'; - break; - } - vector result; -//? cout << "length: " << x.value << '\n'; //? 1 - result.push_back(Memory[x.value]); - write_memory(instructions[pc].products[0], result); - break; -} diff --git a/cpp/024compare b/cpp/024compare new file mode 100644 index 00000000..145feaa2 --- /dev/null +++ b/cpp/024compare @@ -0,0 +1,261 @@ +:(before "End Primitive Recipe Declarations") +// Comparison ops. +EQUAL, +:(before "End Primitive Recipe Numbers") +Recipe_number["equal"] = EQUAL; +:(before "End Primitive Recipe Implementations") +case EQUAL: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + vector result; + result.push_back(equal(arg0.begin(), arg0.end(), arg1.begin())); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "equal") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 33:literal + 3:integer <- equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 0 ++mem: storing 0 in location 3 + +:(scenario "equal2") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 34:literal + 3:integer <- equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 34 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(before "End Primitive Recipe Declarations") +GREATER_THAN, +:(before "End Primitive Recipe Numbers") +Recipe_number["greater-than"] = GREATER_THAN; +:(before "End Primitive Recipe Implementations") +case GREATER_THAN: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] > arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "greater_than") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 33:literal + 3:integer <- greater-than 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(scenario "greater_than2") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 34:literal + 3:integer <- greater-than 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 34 ++run: product 0 is 0 ++mem: storing 0 in location 3 + +:(before "End Primitive Recipe Declarations") +LESSER_THAN, +:(before "End Primitive Recipe Numbers") +Recipe_number["lesser-than"] = LESSER_THAN; +:(before "End Primitive Recipe Implementations") +case LESSER_THAN: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] < arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "lesser_than") +recipe main [ + 1:integer <- copy 32:literal + 2:integer <- copy 33:literal + 3:integer <- lesser-than 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 32 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(scenario "lesser_than2") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 33:literal + 3:integer <- lesser-than 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 0 ++mem: storing 0 in location 3 + +:(before "End Primitive Recipe Declarations") +GREATER_OR_EQUAL, +:(before "End Primitive Recipe Numbers") +Recipe_number["greater-or-equal"] = GREATER_OR_EQUAL; +:(before "End Primitive Recipe Implementations") +case GREATER_OR_EQUAL: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] >= arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "greater_or_equal") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 33:literal + 3:integer <- greater-or-equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(scenario "greater_or_equal2") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 34:literal + 3:integer <- greater-or-equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 34 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(scenario "greater_or_equal3") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 35:literal + 3:integer <- greater-or-equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 35 ++run: product 0 is 0 ++mem: storing 0 in location 3 + +:(before "End Primitive Recipe Declarations") +LESSER_OR_EQUAL, +:(before "End Primitive Recipe Numbers") +Recipe_number["lesser-or-equal"] = LESSER_OR_EQUAL; +:(before "End Primitive Recipe Implementations") +case LESSER_OR_EQUAL: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + vector arg0 = read_memory(instructions[pc].ingredients[0]); + assert(arg0.size() == 1); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + vector arg1 = read_memory(instructions[pc].ingredients[1]); + assert(arg1.size() == 1); + vector result; + result.push_back(arg0[0] <= arg1[0]); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +:(scenario "lesser_or_equal") +recipe main [ + 1:integer <- copy 32:literal + 2:integer <- copy 33:literal + 3:integer <- lesser-or-equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 32 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(scenario "lesser_or_equal2") +recipe main [ + 1:integer <- copy 33:literal + 2:integer <- copy 33:literal + 3:integer <- lesser-or-equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 33 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 1 ++mem: storing 1 in location 3 + +:(scenario "lesser_or_equal3") +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 33:literal + 3:integer <- lesser-or-equal 1:integer, 2:integer +] ++run: instruction main/2 ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++run: ingredient 1 is 2 ++mem: location 2 is 33 ++run: product 0 is 0 ++mem: storing 0 in location 3 diff --git a/cpp/025call b/cpp/025call deleted file mode 100644 index 3683db12..00000000 --- a/cpp/025call +++ /dev/null @@ -1,77 +0,0 @@ -//: So far the recipes we define can't run each other. Let's change that. -:(scenario "calling_recipe") -recipe main [ - f -] -recipe f [ - 3:integer <- add 2:literal, 2:literal -] -+mem: storing 4 in location 3 - -:(before "struct routine {") -// Everytime a recipe runs another, we interrupt it and start running the new -// recipe. When that finishes, we continue this one where we left off. -// This requires maintaining a 'stack' of interrupted recipes or 'calls'. -struct call { - recipe_number running_recipe; - size_t pc; - // End call Fields - call(recipe_number r) :running_recipe(r), pc(0) {} -}; -typedef stack call_stack; - -:(replace{} "struct routine") -struct routine { - call_stack calls; - // End routine Fields - routine(recipe_number r); -}; -:(code) - routine::routine(recipe_number r) { - calls.push(call(r)); - } -//: now update routine's helpers -:(replace{} "inline size_t& running_at(routine& rr)") -inline size_t& running_at(routine& rr) { - return rr.calls.top().pc; -} -:(replace{} "inline string recipe_name(routine& rr)") -inline string recipe_name(routine& rr) { - return Recipe[rr.calls.top().running_recipe].name; -} -:(replace{} "inline vector& steps(routine& rr)") -inline vector& steps(routine& rr) { - return Recipe[rr.calls.top().running_recipe].steps; -} - -:(replace{} "default:" following "End Primitive Recipe Implementations") -default: { - // not a primitive; try to look for a matching recipe - if (Recipe.find(instructions[pc].operation) == Recipe.end()) { - raise << "undefined operation " << instructions[pc].operation << ": " << instructions[pc].name << '\n'; - break; - } - rr.calls.push(call(instructions[pc].operation)); - continue; // not done with caller; don't increment pc -} - -//: finally, we need to fix the termination conditions for the run loop - -:(replace{} "inline bool done(routine& rr)") -inline bool done(routine& rr) { - return rr.calls.empty(); -} - -:(before "Running one instruction") -// when we reach the end of one call, we may reach the end of the one below -// it, and the one below that, and so on -while (running_at(rr) >= steps(rr).size()) { - rr.calls.pop(); - if (rr.calls.empty()) return; - // todo: no results returned warning - ++running_at(rr); -} - -:(before "End Includes") -#include -using std::stack; diff --git a/cpp/025trace b/cpp/025trace new file mode 100644 index 00000000..bd05d848 --- /dev/null +++ b/cpp/025trace @@ -0,0 +1,19 @@ +:(scenario "trace") +recipe main [ + trace [foo], [this is a trace in mu] +] ++foo: this is a trace in mu + +:(before "End Primitive Recipe Declarations") +TRACE, +:(before "End Primitive Recipe Numbers") +Recipe_number["trace"] = TRACE; +:(before "End Primitive Recipe Implementations") +case TRACE: { + assert(isa_literal(instructions[pc].ingredients[0])); + string label = instructions[pc].ingredients[0].name; + assert(isa_literal(instructions[pc].ingredients[1])); + string message = instructions[pc].ingredients[1].name; + trace(label) << message; + break; +} diff --git a/cpp/026call_ingredient b/cpp/026call_ingredient deleted file mode 100644 index ecf53539..00000000 --- a/cpp/026call_ingredient +++ /dev/null @@ -1,42 +0,0 @@ -//: Calls can take ingredients just like primitives. To access a recipe's -//: ingredients, use 'next-ingredient'. -:(scenario "next_ingredient") -recipe main [ - f 2:literal -] -recipe f [ - 12:integer <- next-ingredient - 13:integer <- add 1:literal, 12:integer -] -+run: instruction f/1 -+mem: location 12 is 2 -+mem: storing 3 in location 13 - -:(before "End call Fields") -vector > ingredient_atoms; -size_t next_ingredient_to_process; -:(replace{} "call(recipe_number r)") -call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0) {} - -:(replace "rr.calls.push(call(instructions[pc].operation))" following "End Primitive Recipe Implementations") -call callee(instructions[pc].operation); -for (vector::iterator p = instructions[pc].ingredients.begin(); p != instructions[pc].ingredients.end(); ++p) { - callee.ingredient_atoms.push_back(read_memory(*p)); -} -rr.calls.push(callee); - -:(before "End Primitive Recipe Declarations") -NEXT_INGREDIENT, -:(before "End Primitive Recipe Numbers") -Recipe_number["next-ingredient"] = NEXT_INGREDIENT; -:(before "End Primitive Recipe Implementations") -case NEXT_INGREDIENT: { - if (rr.calls.top().next_ingredient_to_process < rr.calls.top().ingredient_atoms.size()) { - trace("run") << "product 0 is " - << rr.calls.top().ingredient_atoms[rr.calls.top().next_ingredient_to_process][0]; - write_memory(instructions[pc].products[0], - rr.calls.top().ingredient_atoms[rr.calls.top().next_ingredient_to_process]); - ++rr.calls.top().next_ingredient_to_process; - } - break; -} diff --git a/cpp/027call_reply b/cpp/027call_reply deleted file mode 100644 index b44552cc..00000000 --- a/cpp/027call_reply +++ /dev/null @@ -1,70 +0,0 @@ -//: Calls can also generate results, using 'reply'. -:(scenario "reply") -recipe main [ - 3:integer, 4:integer <- f 2:literal -] -recipe f [ - 12:integer <- next-ingredient - 13:integer <- add 1:literal, 12:integer - reply 12:integer, 13:integer -] -+run: instruction main/0 -+run: result 0 is 2 -+mem: storing 2 in location 3 -+run: result 1 is 3 -+mem: storing 3 in location 4 - -:(before "End Primitive Recipe Declarations") -REPLY, -:(before "End Primitive Recipe Numbers") -Recipe_number["reply"] = REPLY; -:(before "End Primitive Recipe Implementations") -case REPLY: { - vector > callee_results; - for (size_t i = 0; i < instructions[pc].ingredients.size(); ++i) { - callee_results.push_back(read_memory(instructions[pc].ingredients[i])); - } - rr.calls.pop(); - assert(!rr.calls.empty()); - size_t& caller_pc = rr.calls.top().pc; - instruction& caller_instruction = Recipe[rr.calls.top().running_recipe].steps[caller_pc]; - assert(caller_instruction.products.size() <= callee_results.size()); - for (size_t i = 0; i < caller_instruction.products.size(); ++i) { - trace("run") << "result " << i << " is " << to_string(callee_results[i]); - write_memory(caller_instruction.products[i], callee_results[i]); - } - ++caller_pc; - break; -} - -//: Results can include containers and exclusive containers, addresses and arrays. -:(scenario "reply_container") -recipe main [ - 3:point <- f 2:literal -] -recipe f [ - 12:integer <- next-ingredient - 13:integer <- copy 35:literal - reply 12:point -] -+run: instruction main/0 -+run: result 0 is [2, 35] -+mem: storing 2 in location 3 -+mem: storing 35 in location 4 - -:(code) -string to_string(const vector& in) { - if (in.empty()) return "[]"; - ostringstream out; - if (in.size() == 1) { - out << in[0]; - return out.str(); - } - out << "["; - for (size_t i = 0; i < in.size(); ++i) { - if (i > 0) out << ", "; - out << in[i]; - } - out << "]"; - return out.str(); -} diff --git a/cpp/030brace b/cpp/030brace deleted file mode 100644 index d01fe359..00000000 --- a/cpp/030brace +++ /dev/null @@ -1,387 +0,0 @@ -//: Structured programming -//: -//: Our jump recipes are quite inconvenient to use, so mu provides a -//: lightweight tool called 'transform_braces' to work in a slightly more -//: convenient format with nested braces: -//: -//: { -//: some instructions -//: { -//: more instructions -//: } -//: } -//: -//: Braces are just labels, they require no special parsing. The pseudo -//: recipes 'loop' and 'break' jump to just after the enclosing '{' and '}' -//: respectively. -//: -//: Conditional and unconditional 'loop' and 'break' should give us 80% of the -//: benefits of the control-flow primitives we're used to in other languages, -//: like 'if', 'while', 'for', etc. - -:(scenarios transform_test) -:(scenario "brace_conversion") -recipe main [ - { - break - 1:integer <- copy 0:literal - } -] -+after-brace: recipe main -+after-brace: jump 1:offset -+after-brace: copy ... - -//: one-time setup -:(after "int main") - Transform.push_back(transform_braces); - -:(code) -void transform_braces(const recipe_number r) { -//? cout << "AAA transform_braces\n"; //? 1 -//? exit(0); //? 1 - const int OPEN = 0, CLOSE = 1; - list > braces; - for (size_t index = 0; index < Recipe[r].steps.size(); ++index) { - const instruction& inst = Recipe[r].steps[index]; - if (inst.label == "{") { - trace("brace") << r << ": push (open, " << index << ")"; - braces.push_back(pair(OPEN, index)); - } - if (inst.label == "}") { - trace("brace") << "push (close, " << index << ")"; - braces.push_back(pair(CLOSE, index)); - } - } - stack open_braces; - trace("after-brace") << "recipe " << Recipe[r].name; - for (size_t index = 0; index < Recipe[r].steps.size(); ++index) { - instruction& inst = Recipe[r].steps[index]; -//? cout << "AAA " << inst.name << ": " << inst.operation << '\n'; //? 1 - if (inst.label == "{") open_braces.push(index); - else if (inst.label == "}") open_braces.pop(); - else if (inst.is_label) - ; // do nothing - else if (inst.operation == Recipe_number["loop"]) { - inst.operation = Recipe_number["jump"]; - if (inst.ingredients.size() > 0 && isa_literal(inst.ingredients[0])) { - // explicit target; a later phase will handle it - trace("after-brace") << "jump " << inst.ingredients[0].name << ":offset"; - } - else { - reagent ing; - ing.set_value(open_braces.top()-index); - inst.ingredients.push_back(ing); - trace("after-brace") << "jump " << ing.value << ":offset"; - trace("after-brace") << index << ": " << ing.to_string(); - trace("after-brace") << index << ": " << Recipe[r].steps[index].ingredients[0].to_string(); - } - } - else if (inst.operation == Recipe_number["break"]) { - inst.operation = Recipe_number["jump"]; - if (inst.ingredients.size() > 0 && isa_literal(inst.ingredients[0])) { - // explicit target; a later phase will handle it - trace("after-brace") << "jump " << inst.ingredients[0].name << ":offset"; - } - else { - reagent ing; - ing.set_value(matching_brace(open_braces.top(), braces) - index - 1); - inst.ingredients.push_back(ing); - trace("after-brace") << "jump " << ing.value << ":offset"; - } - } - else if (inst.operation == Recipe_number["loop-if"]) { - inst.operation = Recipe_number["jump-if"]; - if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { - // explicit target; a later phase will handle it - trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; - } - else { - reagent ing; - ing.set_value(open_braces.top()-index); - inst.ingredients.push_back(ing); - trace("after-brace") << "jump-if " << inst.ingredients[0].name << ", " << ing.value << ":offset"; - } - } - else if (inst.operation == Recipe_number["break-if"]) { - inst.operation = Recipe_number["jump-if"]; - if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { - // explicit target; a later phase will handle it - trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; - } - else { - reagent ing; - ing.set_value(matching_brace(open_braces.top(), braces) - index - 1); - inst.ingredients.push_back(ing); - trace("after-brace") << "jump-if " << inst.ingredients[0].name << ", " << ing.value << ":offset"; - } - } - else if (inst.operation == Recipe_number["loop-unless"]) { - inst.operation = Recipe_number["jump-unless"]; - if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { - // explicit target; a later phase will handle it - trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; - } - else { - reagent ing; - ing.set_value(open_braces.top()-index); - inst.ingredients.push_back(ing); - trace("after-brace") << "jump-unless " << inst.ingredients[0].name << ", " << ing.value << ":offset"; - } - } - else if (inst.operation == Recipe_number["break-unless"]) { -//? cout << "AAA break-unless\n"; //? 1 - inst.operation = Recipe_number["jump-unless"]; - if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { - // explicit target; a later phase will handle it - trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; - } - else { - reagent ing; - ing.set_value(matching_brace(open_braces.top(), braces) - index - 1); - inst.ingredients.push_back(ing); - trace("after-brace") << "jump-unless " << inst.ingredients[0].name << ", " << ing.value << ":offset"; - } - } - else { - trace("after-brace") << inst.name << " ..."; - } - } -} - -size_t matching_brace(size_t index, const list >& braces) { - int stacksize; - for (list >::const_iterator p = braces.begin(); p != braces.end(); ++p) { - if (p->second < index) continue; - stacksize += (p->first ? 1 : -1); - if (stacksize == 0) return p->second; - } - assert(false); - return -1; -} - -// temporarily suppress run -void transform_test(string form) { -//? cout << "AAA transform_test {\n"; //? 1 - vector tmp = add_recipes(form); -//? cout << "AAA done adding recipes\n"; //? 1 - transform_all(); -//? cout << "AAA }\n"; //? 1 -} - -//: Make sure these pseudo recipes get consistent numbers in all tests, even -//: though they aren't implemented. - -:(before "End Primitive Recipe Declarations") -BREAK, -BREAK_IF, -BREAK_UNLESS, -LOOP, -LOOP_IF, -LOOP_UNLESS, -:(before "End Primitive Recipe Numbers") -Recipe_number["break"] = BREAK; -Recipe_number["break-if"] = BREAK_IF; -Recipe_number["break-unless"] = BREAK_UNLESS; -Recipe_number["loop"] = LOOP; -Recipe_number["loop-if"] = LOOP_IF; -Recipe_number["loop-unless"] = LOOP_UNLESS; - -:(scenario "loop") -recipe main [ - 1:integer <- copy 0:literal - 2:integer <- copy 0:literal - { - 3:integer <- copy 0:literal - loop - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: copy ... -+after-brace: copy ... -+after-brace: jump -2:offset - -:(scenario "break_empty_block") -recipe main [ - 1:integer <- copy 0:literal - { - break - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: jump 0:offset - -:(scenario "break_cascading") -recipe main [ - 1:integer <- copy 0:literal - { - break - } - { - break - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: jump 0:offset -+after-brace: jump 0:offset - -:(scenario "break_cascading2") -recipe main [ - 1:integer <- copy 0:literal - 2:integer <- copy 0:literal - { - break - 3:integer <- copy 0:literal - } - { - break - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: copy ... -+after-brace: jump 1:offset -+after-brace: copy ... -+after-brace: jump 0:offset - -:(scenario "break_if") -recipe main [ - 1:integer <- copy 0:literal - 2:integer <- copy 0:literal - { - break-if 2:integer - 3:integer <- copy 0:literal - } - { - break - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: copy ... -+after-brace: jump-if 2, 1:offset -+after-brace: copy ... -+after-brace: jump 0:offset - -:(scenario "break_nested") -recipe main [ - 1:integer <- copy 0:literal - { - 2:integer <- copy 0:literal - break - { - 3:integer <- copy 0:literal - } - 4:integer <- copy 0:literal - } -] -+after-brace: jump 4:offset - -:(scenario "break_nested_degenerate") -recipe main [ - 1:integer <- copy 0:literal - { - 2:integer <- copy 0:literal - break - { - } - 4:integer <- copy 0:literal - } -] -+after-brace: jump 3:offset - -:(scenario "break_nested_degenerate2") -recipe main [ - 1:integer <- copy 0:literal - { - 2:integer <- copy 0:literal - break - { - } - } -] -+after-brace: jump 2:offset - -:(scenario "break_label") -recipe main [ - 1:integer <- copy 0:literal - { - break +foo:offset - } -] -+after-brace: jump +foo:offset - -:(scenario "break_unless") -recipe main [ - 1:integer <- copy 0:literal - 2:integer <- copy 0:literal - { - break-unless 2:integer - 3:integer <- copy 0:literal - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: copy ... -+after-brace: jump-unless 2, 1:offset -+after-brace: copy ... - -:(scenario "loop_unless") -recipe main [ - 1:integer <- copy 0:literal - 2:integer <- copy 0:literal - { - loop-unless 2:integer - 3:integer <- copy 0:literal - } -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: copy ... -+after-brace: jump-unless 2, -1:offset -+after-brace: copy ... - -:(scenario "loop_nested") -recipe main [ - 1:integer <- copy 0:literal - { - 2:integer <- copy 0:literal - { - 3:integer <- copy 0:literal - } - loop-if 4:boolean - 5:integer <- copy 0:literal - } -] -+after-brace: recipe main -+after-brace: jump-if 4, -5:offset - -:(scenario "loop_label") -recipe main [ - 1:integer <- copy 0:literal - +foo - 2:integer <- copy 0:literal -] -+after-brace: recipe main -+after-brace: copy ... -+after-brace: copy ... - -//: test how things actually run -:(scenarios run) -:(scenario "factorial") -recipe factorial [ - 1:integer <- copy 5:literal - 2:integer <- copy 1:literal - { - 3:boolean <- equal 1:integer 1:literal - break-if 3:boolean -# $print 1:integer - 2:integer <- multiply 2:integer, 1:integer - 1:integer <- subtract 1:integer, 1:literal - loop - } - 4:integer <- copy 2:integer # trigger a read -] -+mem: location 2 is 120 diff --git a/cpp/030container b/cpp/030container new file mode 100644 index 00000000..fcdd82f9 --- /dev/null +++ b/cpp/030container @@ -0,0 +1,167 @@ +//: Containers contain a fixed number of elements of different types. +:(before "End Mu Types Initialization") +//: We'll use this container as a running example, with two integer elements. +int point = Type_number["point"] = Next_type_number++; +Type[point].size = 2; +Type[point].kind = container; +Type[point].name = "point"; +vector i; +i.push_back(integer); +Type[point].elements.push_back(i); +Type[point].elements.push_back(i); + +:(scenario copy_multiple_locations) +# Containers can be copied around with a single instruction just like integers, +# no matter how large they are. +recipe main [ + 1:integer <- copy 34:literal + 2:integer <- copy 35:literal + 3:point <- copy 1:point +] ++run: ingredient 0 is 1 ++mem: location 1 is 34 ++mem: location 2 is 35 ++mem: storing 34 in location 3 ++mem: storing 35 in location 4 + +:(before "End Mu Types Initialization") +// A more complex container, containing another container as one of its +// elements. +int point_integer = Type_number["point-integer"] = Next_type_number++; +Type[point_integer].size = 2; +Type[point_integer].kind = container; +Type[point_integer].name = "point-integer"; +vector p2; +p2.push_back(point); +Type[point_integer].elements.push_back(p2); +vector i2; +i2.push_back(integer); +Type[point_integer].elements.push_back(i2); + +:(scenario "copy_handles_nested_container_elements") +recipe main [ + 12:integer <- copy 34:literal + 13:integer <- copy 35:literal + 14:integer <- copy 36:literal + 15:point-integer <- copy 12:point-integer +] ++mem: storing 36 in location 17 + +:(before "End size_of(types) Cases") +type_info t = Type[types[0]]; +if (t.kind == container) { + size_t result = 0; + for (size_t i = 0; i < t.elements.size(); ++i) { + result += size_of(t.elements[i]); + } + return result; +} + +//: To access elements of a container, use 'get' +:(scenario "get") +recipe main [ + 12:integer <- copy 34:literal + 13:integer <- copy 35:literal + 15:integer <- get 12:point, 1:offset +] ++run: instruction main/2 ++run: ingredient 0 is 12 ++run: ingredient 1 is 1 ++run: address to copy is 13 ++run: its type is 1 ++mem: location 13 is 35 ++run: product 0 is 35 ++mem: storing 35 in location 15 + +:(before "End Primitive Recipe Declarations") +GET, +:(before "End Primitive Recipe Numbers") +Recipe_number["get"] = GET; +:(before "End Primitive Recipe Implementations") +case GET: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + reagent base = instructions[pc].ingredients[0]; + int base_address = base.value; + int base_type = base.types[0]; + assert(Type[base_type].kind == container); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + assert(isa_literal(instructions[pc].ingredients[1])); + size_t offset = instructions[pc].ingredients[1].value; + int src = base_address; + for (size_t i = 0; i < offset; ++i) { + src += size_of(Type[base_type].elements[i]); + } + trace("run") << "address to copy is " << src; + assert(Type[base_type].kind == container); + assert(Type[base_type].elements.size() > offset); + int src_type = Type[base_type].elements[offset][0]; + trace("run") << "its type is " << src_type; + reagent tmp; + tmp.set_value(src); + tmp.types.push_back(src_type); + vector result(read_memory(tmp)); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} + +//: 'get' requires a literal in ingredient 1. We'll use a synonym called +//: 'offset' +:(before "End Mu Types Initialization") +Type_number["offset"] = 0; + +:(scenario "get_handles_nested_container_elements") +recipe main [ + 12:integer <- copy 34:literal + 13:integer <- copy 35:literal + 14:integer <- copy 36:literal + 15:integer <- get 12:point-integer, 1:offset +] ++run: instruction main/2 ++run: ingredient 0 is 12 ++run: ingredient 1 is 1 ++run: address to copy is 14 ++run: its type is 1 ++mem: location 14 is 36 ++run: product 0 is 36 ++mem: storing 36 in location 15 + +//: To write to elements of containers, you need their address. + +:(scenario "get_address") +recipe main [ + 12:integer <- copy 34:literal + 13:integer <- copy 35:literal + 15:address:integer <- get-address 12:point, 1:offset +] ++run: instruction main/2 ++run: ingredient 0 is 12 ++run: ingredient 1 is 1 ++run: address to copy is 13 ++mem: storing 13 in location 15 + +:(before "End Primitive Recipe Declarations") +GET_ADDRESS, +:(before "End Primitive Recipe Numbers") +Recipe_number["get-address"] = GET_ADDRESS; +:(before "End Primitive Recipe Implementations") +case GET_ADDRESS: { + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + reagent base = instructions[pc].ingredients[0]; + int base_address = base.value; + int base_type = base.types[0]; + assert(Type[base_type].kind == container); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].name; + assert(isa_literal(instructions[pc].ingredients[1])); + size_t offset = instructions[pc].ingredients[1].value; + int src = base_address; + for (size_t i = 0; i < offset; ++i) { + src += size_of(Type[base_type].elements[i]); + } + trace("run") << "address to copy is " << src; + vector result; + result.push_back(src); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} diff --git a/cpp/031address b/cpp/031address new file mode 100644 index 00000000..22355fc6 --- /dev/null +++ b/cpp/031address @@ -0,0 +1,117 @@ +//: Instructions can read from addresses pointing at other locations using the +//: 'deref' property. +:(scenario "copy_indirect") +recipe main [ + 1:address:integer <- copy 2:literal + 2:integer <- copy 34:literal + # This loads location 1 as an address and looks up *that* location. + 3:integer <- copy 1:address:integer/deref +] ++run: instruction main/2 ++mem: location 1 is 2 ++mem: location 2 is 34 ++mem: storing 34 in location 3 + +:(before "int base = x.value" following "vector read_memory(reagent x)") +x = canonize(x); + +//: similarly, write to addresses pointing at other locations using the +//: 'deref' property +:(scenario "store_indirect") +recipe main [ + 1:address:integer <- copy 2:literal + 1:address:integer/deref <- copy 34:literal +] ++run: instruction main/1 ++mem: location 1 is 2 ++mem: storing 34 in location 2 + +:(before "int base = x.value" following "void write_memory(reagent x, vector data)") +x = canonize(x); + +:(code) +reagent canonize(reagent x) { +//? cout << "canonize\n"; //? 1 + reagent r = x; +//? cout << x.to_string() << " => " << r.to_string() << '\n'; //? 1 + while (has_property(r, "deref")) + r = deref(r); + return r; +} + +bool has_property(reagent x, string name) { + for (size_t i = 0; i < x.properties.size(); ++i) { + if (x.properties[i].first == name) return true; + } + return false; +} + +reagent deref(reagent x) { +//? cout << "deref: " << x.to_string() << "\n"; //? 2 + static const int ADDRESS = Type_number["address"]; + reagent result; + assert(x.types[0] == ADDRESS); + + // compute value + result.set_value(Memory[x.value]); + trace("mem") << "location " << x.value << " is " << result.value; + + // populate types + copy(++x.types.begin(), x.types.end(), inserter(result.types, result.types.begin())); + + // drop-one 'deref' + int i = 0; + int len = x.properties.size(); + for (i = 0; i < len; ++i) { + if (x.properties[i].first == "deref") break; + result.properties.push_back(x.properties[i]); + } + ++i; // skip first deref + for (; i < len; ++i) { + result.properties.push_back(x.properties[i]); + } + return result; +} + +//: 'get' can read from container address +:(scenario "get_indirect") +recipe main [ + 1:integer <- copy 2:literal + 2:integer <- copy 34:literal + 3:integer <- copy 35:literal + 4:integer <- get 1:address:point/deref, 0:offset +] ++run: instruction main/3 ++run: address to copy is 2 ++run: product 0 is 34 ++mem: storing 34 in location 4 + +:(scenario "include_nonderef_properties") +recipe main [ + 1:integer <- copy 2:literal + 2:integer <- copy 34:literal + 3:integer <- copy 35:literal + 4:integer <- get 1:address:point/deref/foo, 0:offset +] ++run: instruction main/3 ++run: address to copy is 2 ++run: product 0 is 34 ++mem: storing 34 in location 4 + +:(after "reagent base = " following "case GET:") +base = canonize(base); + +:(scenario "get_address_indirect") +# 'get' can read from container address +recipe main [ + 1:integer <- copy 2:literal + 2:integer <- copy 34:literal + 3:integer <- copy 35:literal + 4:integer <- get-address 1:address:point/deref, 0:offset +] ++run: instruction main/3 ++run: address to copy is 2 ++run: product 0 is 2 + +:(after "reagent base = " following "case GET_ADDRESS:") +base = canonize(base); diff --git a/cpp/031name b/cpp/031name deleted file mode 100644 index 375f9854..00000000 --- a/cpp/031name +++ /dev/null @@ -1,172 +0,0 @@ -//: A big convenience high-level languages provide is the ability to name memory -//: locations. In mu, a transform called 'convert-names' provides this -//: convenience. - -:(scenarios run) -:(scenario "convert_names") -recipe main [ - x:integer <- copy 0:literal -] -+name: assign x 1 -+run: instruction main/0 -+mem: storing 0 in location 1 - -:(scenario "convert_names_warns") -hide warnings -recipe main [ - x:integer <- copy y:integer -] -+warn: use before set: y in main - -:(after "int main") - Transform.push_back(transform_names); - -:(before "End Globals") -unordered_map > Name; -:(after "Clear Other State For recently_added_recipes") -for (size_t i = 0; i < recently_added_recipes.size(); ++i) { - Name.erase(recently_added_recipes[i]); -} - -:(code) -void transform_names(const recipe_number r) { - unordered_map& names = Name[r]; - int curr_idx = 1; -//? cout << "Recipe " << r << '\n'; //? 2 -//? cout << Recipe[r].steps.size(); //? 1 - for (size_t i = 0; i < Recipe[r].steps.size(); ++i) { -//? cout << "instruction " << i << '\n'; //? 2 - instruction& inst = Recipe[r].steps[i]; - // Per-recipe Transforms - // map names to addresses - for (size_t in = 0; in < inst.ingredients.size(); ++in) { -//? cout << "ingredients\n"; //? 2 - if (is_raw(inst.ingredients[in])) continue; -//? cout << "ingredient " << inst.ingredients[in].name << '\n'; //? 2 - if (inst.ingredients[in].name == "default-space") - inst.ingredients[in].initialized = true; - assert(!inst.ingredients[in].types.empty()); - if (inst.ingredients[in].types[0] // not a literal - && !inst.ingredients[in].initialized - && inst.ingredients[in].name.find_first_not_of("0123456789-.") != string::npos) { - if (!already_transformed(inst.ingredients[in], names)) { - raise << "use before set: " << inst.ingredients[in].name << " in " << Recipe[r].name << '\n'; - } - inst.ingredients[in].set_value(lookup_name(inst.ingredients[in], r)); -//? cout << "lookup ingredient " << Recipe[r].name << "/" << i << ": " << inst.ingredients[in].to_string() << '\n'; //? 1 - } - } - for (size_t out = 0; out < inst.products.size(); ++out) { -//? cout << "products\n"; //? 1 - if (is_raw(inst.products[out])) continue; -//? cout << "product " << out << '/' << inst.products.size() << " " << inst.products[out].name << '\n'; //? 4 -//? cout << inst.products[out].types[0] << '\n'; //? 1 - if (inst.products[out].name == "default-space") - inst.products[out].initialized = true; - if (inst.products[out].types[0] // not a literal - && !inst.products[out].initialized - && inst.products[out].name.find_first_not_of("0123456789-.") != string::npos) { - if (names.find(inst.products[out].name) == names.end()) { - trace("name") << "assign " << inst.products[out].name << " " << curr_idx; - names[inst.products[out].name] = curr_idx; - curr_idx += size_of(inst.products[out]); - } - inst.products[out].set_value(lookup_name(inst.products[out], r)); -//? cout << "lookup product " << Recipe[r].name << "/" << i << ": " << inst.products[out].to_string() << '\n'; //? 1 - } - } - } -} - -bool already_transformed(const reagent& r, const unordered_map& names) { - return names.find(r.name) != names.end(); -} - -size_t lookup_name(const reagent& r, const recipe_number default_recipe) { - return Name[default_recipe][r.name]; -} - -type_number skip_addresses(const vector& types) { - for (size_t i = 0; i < types.size(); ++i) { - if (types[i] != Type_number["address"]) return types[i]; - } - raise << "expected a container" << '\n' << die(); - return -1; -} - -int find_element_name(const type_number t, const string& name) { - const type_info& container = Type[t]; -//? cout << "looking for element " << name << " in type " << container.name << " with " << container.element_names.size() << " elements\n"; //? 1 - for (size_t i = 0; i < container.element_names.size(); ++i) { - if (container.element_names[i] == name) return i; - } - raise << "unknown element " << name << " in container " << t << '\n' << die(); - return -1; -} - -bool is_raw(const reagent& r) { - for (size_t i = /*skip value+type*/1; i < r.properties.size(); ++i) { - if (r.properties[i].first == "raw") return true; - } - return false; -} - -:(scenario "convert_names_passes_dummy") -# _ is just a dummy result that never gets consumed -recipe main [ - _, x:integer <- copy 0:literal -] -+name: assign x 1 --name: assign _ 1 - -//: one reserved word that we'll need later -:(scenario "convert_names_passes_default_space") -recipe main [ - default-space:integer, x:integer <- copy 0:literal -] -+name: assign x 1 --name: assign default-space 1 - -//: an escape hatch to suppress name conversion that we'll use later -:(scenario "convert_names_passes_raw") -recipe main [ - x:integer/raw <- copy 0:literal -] --name: assign x 1 - -//: update our running example container for the next test -:(before "End Mu Types Initialization") -Type[point].element_names.push_back("x"); -Type[point].element_names.push_back("y"); -:(scenario "convert_names_transforms_container_elements") -recipe main [ - a:integer <- get 0:point, y:offset - b:integer <- get 0:point, x:offset -] -+name: element y of type point is at offset 1 -+name: element x of type point is at offset 0 - -:(after "Per-recipe Transforms") -// replace element names of containers with offsets -if (inst.operation == Recipe_number["get"] - || inst.operation == Recipe_number["get-address"]) { - // at least 2 args, and second arg is offset - assert(inst.ingredients.size() >= 2); -//? cout << inst.ingredients[1].to_string() << '\n'; //? 1 - assert(isa_literal(inst.ingredients[1])); - if (inst.ingredients[1].name.find_first_not_of("0123456789") == string::npos) continue; - // since first non-address in base type must be a container, we don't have to canonize - type_number container = skip_addresses(inst.ingredients[0].types); - inst.ingredients[1].set_value(find_element_name(container, inst.ingredients[1].name)); - trace("name") << "element " << inst.ingredients[1].name << " of type " << Type[container].name << " is at offset " << inst.ingredients[1].value; -} - -//: this test is actually illegal so can't call run -:(scenarios transform_test) -:(scenario "convert_names_handles_containers") -recipe main [ - a:point <- copy 0:literal - b:integer <- copy 0:literal -] -+name: assign a 1 -+name: assign b 3 diff --git a/cpp/032array b/cpp/032array new file mode 100644 index 00000000..3bdfe95e --- /dev/null +++ b/cpp/032array @@ -0,0 +1,152 @@ +//: Arrays contain a variable number of elements of the same type. +:(scenario copy_array) +# Arrays can be copied around with a single instruction just like integers, +# no matter how large they are. +recipe main [ + 1:integer <- copy 3:literal + 2:integer <- copy 14:literal + 3:integer <- copy 15:literal + 4:integer <- copy 16:literal + 5:array:integer <- copy 1:array:integer +] ++run: instruction main/4 ++run: ingredient 0 is 1 ++mem: location 1 is 3 ++mem: location 2 is 14 ++mem: location 3 is 15 ++mem: location 4 is 16 ++mem: storing 3 in location 5 ++mem: storing 14 in location 6 ++mem: storing 15 in location 7 ++mem: storing 16 in location 8 + +//: disable the size mismatch check since the destination array need not be initialized +:(replace "if (size_of(x) != data.size())" following "void write_memory(reagent x, vector data)") +if (x.types[0] != Type_number["array"] && size_of(x) != data.size()) +:(after "size_t size_of(const reagent& r)") + static const int ARRAY = Type_number["array"]; + if (r.types[0] == ARRAY) { + assert(r.types.size() > 1); + // skip the 'array' type to get at the element type + return 1 + Memory[r.value]*size_of(array_element(r.types)); + } + +//: To access elements of an array, use 'index' +:(scenario "index") +recipe main [ + 1:integer <- copy 3:literal + 2:integer <- copy 14:literal + 3:integer <- copy 15:literal + 4:integer <- copy 16:literal + 5:integer <- index 1:array:integer, 0:literal +] ++run: instruction main/4 ++run: address to copy is 2 ++run: its type is 1 ++mem: location 2 is 14 ++run: product 0 is 14 ++mem: storing 14 in location 5 + +:(scenario "index_direct_offset") +recipe main [ + 1:integer <- copy 3:literal + 2:integer <- copy 14:literal + 3:integer <- copy 15:literal + 4:integer <- copy 16:literal + 5:integer <- copy 0:literal + 6:integer <- index 1:array:integer, 5:integer +] ++run: instruction main/5 ++run: address to copy is 2 ++run: its type is 1 ++mem: location 2 is 14 ++run: product 0 is 14 ++mem: storing 14 in location 6 + +:(before "End Primitive Recipe Declarations") +INDEX, +:(before "End Primitive Recipe Numbers") +Recipe_number["index"] = INDEX; +:(before "End Primitive Recipe Implementations") +case INDEX: { + static const int ARRAY = Type_number["array"]; +//? if (Trace_stream) Trace_stream->dump_layer = "run"; //? 1 + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].to_string(); + reagent base = canonize(instructions[pc].ingredients[0]); +//? trace("run") << "ingredient 0 after canonize: " << instructions[pc].ingredients[0].to_string(); //? 1 + int base_address = base.value; + assert(base.types[0] == ARRAY); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].to_string(); + reagent offset = canonize(instructions[pc].ingredients[1]); + vector offset_val(read_memory(offset)); + vector element_type = array_element(base.types); + int src = base_address + 1 + offset_val[0]*size_of(element_type); + trace("run") << "address to copy is " << src; + trace("run") << "its type is " << element_type[0]; + reagent tmp; + tmp.set_value(src); + copy(element_type.begin(), element_type.end(), inserter(tmp.types, tmp.types.begin())); + tmp.properties.push_back(pair >("raw", vector())); +//? cout << "AAA: " << tmp.to_string() << '\n'; //? 2 + vector result(read_memory(tmp)); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); +//? if (Trace_stream) Trace_stream->dump_layer = ""; //? 1 + break; +} + +:(code) +vector array_element(const vector& types) { + return vector(++types.begin(), types.end()); +} + +:(scenario "index_address") +recipe main [ + 1:integer <- copy 3:literal + 2:integer <- copy 14:literal + 3:integer <- copy 15:literal + 4:integer <- copy 16:literal + 5:integer <- index-address 1:array:integer, 0:literal +] ++run: instruction main/4 ++run: address to copy is 2 ++mem: storing 2 in location 5 + +//: To write to elements of containers, you need their address. + +:(scenario "index_indirect") +recipe main [ + 1:integer <- copy 3:literal + 2:integer <- copy 14:literal + 3:integer <- copy 15:literal + 4:integer <- copy 16:literal + 5:address:array:integer <- copy 1:literal + 6:integer <- index 5:address:array:integer/deref, 1:literal +] ++run: instruction main/5 ++mem: storing 15 in location 6 +// vim:ft=cpp + +:(before "End Primitive Recipe Declarations") +INDEX_ADDRESS, +:(before "End Primitive Recipe Numbers") +Recipe_number["index-address"] = INDEX_ADDRESS; +:(before "End Primitive Recipe Implementations") +case INDEX_ADDRESS: { + static const int ARRAY = Type_number["array"]; + trace("run") << "ingredient 0 is " << instructions[pc].ingredients[0].name; + reagent base = canonize(instructions[pc].ingredients[0]); + int base_address = base.value; + assert(base.types[0] == ARRAY); + trace("run") << "ingredient 1 is " << instructions[pc].ingredients[1].to_string(); + reagent offset = canonize(instructions[pc].ingredients[1]); + vector offset_val(read_memory(offset)); + vector element_type = array_element(base.types); + int src = base_address + 1 + offset_val[0]*size_of(element_type); + trace("run") << "address to copy is " << src; + vector result; + result.push_back(src); + trace("run") << "product 0 is " << result[0]; + write_memory(instructions[pc].products[0], result); + break; +} diff --git a/cpp/032new b/cpp/032new deleted file mode 100644 index e0460170..00000000 --- a/cpp/032new +++ /dev/null @@ -1,76 +0,0 @@ -//: A simple memory allocator to create space for new variables at runtime. - -:(scenarios run) -:(scenario "new") -# call new two times with identical arguments; you should get back different results -recipe main [ - 1:address:integer/raw <- new integer:type - 2:address:integer/raw <- new integer:type - 3:boolean/raw <- equal 1:address:integer/raw, 2:address:integer/raw -] -+mem: storing 0 in location 3 - -:(before "End Globals") -const size_t Alloc_init = 1000; -:(before "End routine Fields") -size_t alloc; -:(replace{} "routine::routine(recipe_number r)") - routine::routine(recipe_number r) :alloc(Alloc_init) { - calls.push(call(r)); - } - -//: first handle 'type' operands -:(before "End Mu Types Initialization") -Type_number["type"] = 0; -:(after "Per-recipe Transforms") -// replace type names with type_numbers -if (inst.operation == Recipe_number["new"]) { - // first arg must be of type 'type' - assert(inst.ingredients.size() >= 1); -//? cout << inst.ingredients[0].to_string() << '\n'; //? 1 - assert(isa_literal(inst.ingredients[0])); - if (inst.ingredients[0].properties[0].second[0] == "type") { - inst.ingredients[0].set_value(Type_number[inst.ingredients[0].name]); - } - trace("new") << inst.ingredients[0].name << " -> " << inst.ingredients[0].value; -} - -:(before "End Primitive Recipe Declarations") -NEW, -:(before "End Primitive Recipe Numbers") -Recipe_number["new"] = NEW; -:(before "End Primitive Recipe Implementations") -case NEW: { - vector result; - trace("mem") << "new alloc: " << Current_routine->alloc; - result.push_back(Current_routine->alloc); - write_memory(instructions[pc].products[0], result); - vector types; - types.push_back(instructions[pc].ingredients[0].value); - if (instructions[pc].ingredients.size() > 1) { - // array - vector capacity = read_memory(instructions[pc].ingredients[1]); - trace("mem") << "array size is " << capacity[0]; - Memory[Current_routine->alloc] = capacity[0]; - Current_routine->alloc += capacity[0]*size_of(types); - } - else { - // scalar - Current_routine->alloc += size_of(types); - } - break; -} - -:(scenario "new_array") -recipe main [ - 1:address:array:integer/raw <- new integer:type, 5:literal - 2:address:integer/raw <- new integer:type - 3:integer/raw <- subtract 2:address:integer/raw, 1:address:array:integer/raw -] -+run: instruction main/0 -+mem: array size is 5 -+run: instruction main/1 -+run: instruction main/2 -+mem: storing 5 in location 3 - -//: vim: ft=cpp diff --git a/cpp/033length b/cpp/033length new file mode 100644 index 00000000..9d3bb714 --- /dev/null +++ b/cpp/033length @@ -0,0 +1,30 @@ +//: Recipe to compute the length of an array. + +:(scenario "array_length") +recipe main [ + 1:integer <- copy 3:literal + 2:integer <- copy 14:literal + 3:integer <- copy 15:literal + 4:integer <- copy 16:literal + 5:integer <- length 1:array:integer +] ++run: instruction main/4 ++mem: storing 3 in location 5 + +:(before "End Primitive Recipe Declarations") +LENGTH, +:(before "End Primitive Recipe Numbers") +Recipe_number["length"] = LENGTH; +:(before "End Primitive Recipe Implementations") +case LENGTH: { + reagent x = canonize(instructions[pc].ingredients[0]); + if (x.types[0] != Type_number["array"]) { + raise << "tried to calculate length of non-array " << x.to_string() << '\n'; + break; + } + vector result; +//? cout << "length: " << x.value << '\n'; //? 1 + result.push_back(Memory[x.value]); + write_memory(instructions[pc].products[0], result); + break; +} diff --git a/cpp/033space b/cpp/033space deleted file mode 100644 index 1bb91b8e..00000000 --- a/cpp/033space +++ /dev/null @@ -1,90 +0,0 @@ -//: Spaces help isolate functions from each other. You can create them at will, -//: and all addresses in arguments are implicitly based on the 'default-space' -//: (unless they have the /raw property) - -:(scenarios run) -:(scenario "set_default_space") -# if default-space is 10, and if an array of 5 locals lies from location 11 to 15 (inclusive), -# then location 0 is really location 11, location 1 is really location 12, and so on. -recipe main [ - 10:integer <- copy 5:literal # pretend array; in practice we'll use new - default-space:address:space <- copy 10:literal - 1:integer <- copy 23:literal -] -+mem: storing 23 in location 12 - -:(scenario "deref_sidesteps_default_space") -recipe main [ - # pretend pointer from outside - 7:integer <- copy 34:literal - # pretend array - 10:integer <- copy 5:literal - # actual start of this function - default-space:address:space <- copy 10:literal - 1:address:integer <- copy 7:literal - 8:integer/raw <- copy 1:address:integer/deref -] -+mem: storing 34 in location 8 - -:(before "End call Fields") -size_t default_space; -:(replace "call(recipe_number r) :running_recipe(r)") -call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0), default_space(0) {} - -:(replace "reagent r = x" following "reagent canonize(reagent x)") -reagent r = absolutize(x); -:(code) -reagent absolutize(reagent x) { -//? if (Recipe_number.find("increment-counter") != Recipe_number.end()) //? 1 -//? cout << "AAA " << "increment-counter/2: " << Recipe[Recipe_number["increment-counter"]].steps[2].products[0].to_string() << '\n'; //? 1 -//? cout << "absolutize " << x.to_string() << '\n'; //? 3 -//? cout << is_raw(x) << '\n'; //? 1 - if (is_raw(x) || is_dummy(x)) return x; -//? cout << "not raw: " << x.to_string() << '\n'; //? 1 - assert(x.initialized); - reagent r = x; - r.set_value(address(r.value, space_base(r))); -//? cout << "after absolutize: " << r.value << '\n'; //? 1 - r.properties.push_back(pair >("raw", vector())); - assert(is_raw(r)); - return r; -} -:(before "return result" following "reagent deref(reagent x)") -result.properties.push_back(pair >("raw", vector())); - -:(code) -int space_base(const reagent& x) { - return Current_routine->calls.top().default_space; -} - -int address(int offset, int base) { - if (base == 0) return offset; // raw -//? cout << base << '\n'; //? 1 - if (offset >= Memory[base]) { - // todo: test - raise << "location " << offset << " is out of bounds " << Memory[base] << '\n'; - } - return base+1 + offset; -} - -:(after "void write_memory(reagent x, vector data)") - if (x.name == "default-space") { - assert(data.size() == 1); - Current_routine->calls.top().default_space = data[0]; -//? cout << "AAA " << Current_routine->calls.top().default_space << '\n'; //? 1 - return; - } - -:(scenario "get_default_space") -recipe main [ - default-space:address:space <- copy 10:literal - 1:integer/raw <- copy default-space:address:space -] -+mem: storing 10 in location 1 - -:(after "vector read_memory(reagent x)") - if (x.name == "default-space") { - vector result; - result.push_back(Current_routine->calls.top().default_space); - return result; - } diff --git a/cpp/034space_surround b/cpp/034space_surround deleted file mode 100644 index 76cd5807..00000000 --- a/cpp/034space_surround +++ /dev/null @@ -1,50 +0,0 @@ -//: So far you can have global variables by not setting default-space, and -//: local variables by setting default-space. You can isolate variables -//: between those extremes by creating 'surrounding' spaces. -//: -//: (Surrounding spaces are like lexical scopes in other languages.) - -:(scenario "surrounding_space") -# location 1 in space 1 refers to the space surrounding the default space, here 20. -recipe main [ - 10:integer <- copy 5:literal # pretend array - 20:integer <- copy 5:literal # pretend array - default-space:address:space <- copy 10:literal - 0:address:space/names:dummy <- copy 20:literal # later layers will explain the /names: property - 1:integer <- copy 32:literal - 1:integer/space:1 <- copy 33:literal -] -+run: instruction main/3 -+mem: storing 20 in location 11 -+run: instruction main/4 -+mem: storing 32 in location 12 -+run: instruction main/5 -+mem: storing 33 in location 22 - -//: If you think of a space as a collection of variables with a common -//: lifetime, surrounding allows managing shorter lifetimes inside a longer -//: one. - -:(replace{} "int space_base(const reagent& x)") -int space_base(const reagent& x) { - return space_base(x, space_index(x), Current_routine->calls.top().default_space); -} - -int space_base(const reagent& x, int space_index, int base) { -//? trace("foo") << "base of space " << space_index << '\n'; //? 1 - if (space_index == 0) { -//? trace("foo") << "base of space " << space_index << " is " << base << '\n'; //? 1 - return base; - } -//? trace("foo") << "base of space " << space_index << " is " << Memory[base+1] << '\n'; //? 1 - int result = space_base(x, space_index-1, Memory[base+1]); - return result; -} - -int space_index(const reagent& x) { - for (size_t i = 0; i < x.properties.size(); ++i) { - if (x.properties[i].first == "space") - return to_int(x.properties[i].second[0]); - } - return 0; -} diff --git a/cpp/035call b/cpp/035call new file mode 100644 index 00000000..3683db12 --- /dev/null +++ b/cpp/035call @@ -0,0 +1,77 @@ +//: So far the recipes we define can't run each other. Let's change that. +:(scenario "calling_recipe") +recipe main [ + f +] +recipe f [ + 3:integer <- add 2:literal, 2:literal +] ++mem: storing 4 in location 3 + +:(before "struct routine {") +// Everytime a recipe runs another, we interrupt it and start running the new +// recipe. When that finishes, we continue this one where we left off. +// This requires maintaining a 'stack' of interrupted recipes or 'calls'. +struct call { + recipe_number running_recipe; + size_t pc; + // End call Fields + call(recipe_number r) :running_recipe(r), pc(0) {} +}; +typedef stack call_stack; + +:(replace{} "struct routine") +struct routine { + call_stack calls; + // End routine Fields + routine(recipe_number r); +}; +:(code) + routine::routine(recipe_number r) { + calls.push(call(r)); + } +//: now update routine's helpers +:(replace{} "inline size_t& running_at(routine& rr)") +inline size_t& running_at(routine& rr) { + return rr.calls.top().pc; +} +:(replace{} "inline string recipe_name(routine& rr)") +inline string recipe_name(routine& rr) { + return Recipe[rr.calls.top().running_recipe].name; +} +:(replace{} "inline vector& steps(routine& rr)") +inline vector& steps(routine& rr) { + return Recipe[rr.calls.top().running_recipe].steps; +} + +:(replace{} "default:" following "End Primitive Recipe Implementations") +default: { + // not a primitive; try to look for a matching recipe + if (Recipe.find(instructions[pc].operation) == Recipe.end()) { + raise << "undefined operation " << instructions[pc].operation << ": " << instructions[pc].name << '\n'; + break; + } + rr.calls.push(call(instructions[pc].operation)); + continue; // not done with caller; don't increment pc +} + +//: finally, we need to fix the termination conditions for the run loop + +:(replace{} "inline bool done(routine& rr)") +inline bool done(routine& rr) { + return rr.calls.empty(); +} + +:(before "Running one instruction") +// when we reach the end of one call, we may reach the end of the one below +// it, and the one below that, and so on +while (running_at(rr) >= steps(rr).size()) { + rr.calls.pop(); + if (rr.calls.empty()) return; + // todo: no results returned warning + ++running_at(rr); +} + +:(before "End Includes") +#include +using std::stack; diff --git a/cpp/035literal_string b/cpp/035literal_string deleted file mode 100644 index 9ca09115..00000000 --- a/cpp/035literal_string +++ /dev/null @@ -1,91 +0,0 @@ -//: Some instructions can take string literals for convenience. -//: -//: Instead of quotes, we'll use [] to delimit strings. That'll reduce the -//: need for escaping since we can support nested brackets. And we can also -//: imagine that 'recipe' might one day itself be defined in mu, doing its own -//: parsing. - -//: First extend the mu parser to support string literals. -:(scenario "string_literal") -recipe main [ - 1:address:array:character <- new [abc def] -] -+parse: ingredient: {name: "abc def", value: 0, type: 0, properties: ["abc def": "literal-string"]} - -:(scenario "string_literal_with_colons") -recipe main [ - 1:address:array:character <- new [abc:def/ghi] -] -+parse: ingredient: {name: "abc:def/ghi", value: 0, type: 0, properties: ["abc:def/ghi": "literal-string"]} - -:(before "End Mu Types Initialization") -Type_number["literal-string"] = 0; - -:(after "string next_word(istream& in)") -if (in.peek() == '[') return slurp_quoted(in); - -:(code) -string slurp_quoted(istream& in) { - assert(!in.eof()); - assert(in.peek() == '['); - ostringstream out; - int size = 0; - while (!in.eof()) { - char c = in.get(); -//? cout << c << '\n'; //? 1 - out << c; -//? cout << out.str() << "$\n"; //? 1 - if (c == '[') ++size; - if (c == ']') --size; - if (size == 0) break; - } - return out.str(); -} - -:(after "reagent::reagent(string s)") -//? cout << s[0] << '\n'; //? 1 - if (s[0] == '[') { - assert(s[s.size()-1] == ']'); - // delete [] delimiters - s.erase(0, 1); - s.erase(s.size()-1, s.size()); - name = s; - types.push_back(0); - properties.push_back(pair >(name, vector())); - properties.back().second.push_back("literal-string"); - return; - } - -:(scenario "string_literal_nested") -recipe main [ - 1:address:array:character <- new [abc [def]] -] -+parse: ingredient: {name: "abc [def]", value: 0, type: 0, properties: ["abc [def]": "literal-string"]} - -//: Next, extend 'new' to handle a string literal argument. -:(scenario "new_string") -recipe main [ - 1:address:array:character <- new [abc def] - 2:character <- index 1:address:array:character/deref, 5:literal -] -# integer code for 'e' -+mem: storing 101 in location 2 - -:(before "End Mu Types Initialization") -Type_number["character"] = Next_type_number++; - -:(after "case NEW" following "Primitive Recipe Implementations") -if (instructions[pc].ingredients[0].properties[0].second[0] == "literal-string") { - // allocate an array just large enough for it - vector result; - result.push_back(Current_routine->alloc); - write_memory(instructions[pc].products[0], result); - // assume that all characters fit in a single location -//? cout << "new string literal: " << instructions[pc].ingredients[0].name << '\n'; //? 1 - Memory[Current_routine->alloc++] = instructions[pc].ingredients[0].name.size(); - for (size_t i = 0; i < instructions[pc].ingredients[0].name.size(); ++i) { - Memory[Current_routine->alloc++] = instructions[pc].ingredients[0].name[i]; - } - // mu strings are not null-terminated in memory - break; -} diff --git a/cpp/036call_ingredient b/cpp/036call_ingredient new file mode 100644 index 00000000..ecf53539 --- /dev/null +++ b/cpp/036call_ingredient @@ -0,0 +1,42 @@ +//: Calls can take ingredients just like primitives. To access a recipe's +//: ingredients, use 'next-ingredient'. +:(scenario "next_ingredient") +recipe main [ + f 2:literal +] +recipe f [ + 12:integer <- next-ingredient + 13:integer <- add 1:literal, 12:integer +] ++run: instruction f/1 ++mem: location 12 is 2 ++mem: storing 3 in location 13 + +:(before "End call Fields") +vector > ingredient_atoms; +size_t next_ingredient_to_process; +:(replace{} "call(recipe_number r)") +call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0) {} + +:(replace "rr.calls.push(call(instructions[pc].operation))" following "End Primitive Recipe Implementations") +call callee(instructions[pc].operation); +for (vector::iterator p = instructions[pc].ingredients.begin(); p != instructions[pc].ingredients.end(); ++p) { + callee.ingredient_atoms.push_back(read_memory(*p)); +} +rr.calls.push(callee); + +:(before "End Primitive Recipe Declarations") +NEXT_INGREDIENT, +:(before "End Primitive Recipe Numbers") +Recipe_number["next-ingredient"] = NEXT_INGREDIENT; +:(before "End Primitive Recipe Implementations") +case NEXT_INGREDIENT: { + if (rr.calls.top().next_ingredient_to_process < rr.calls.top().ingredient_atoms.size()) { + trace("run") << "product 0 is " + << rr.calls.top().ingredient_atoms[rr.calls.top().next_ingredient_to_process][0]; + write_memory(instructions[pc].products[0], + rr.calls.top().ingredient_atoms[rr.calls.top().next_ingredient_to_process]); + ++rr.calls.top().next_ingredient_to_process; + } + break; +} diff --git a/cpp/037call_reply b/cpp/037call_reply new file mode 100644 index 00000000..b44552cc --- /dev/null +++ b/cpp/037call_reply @@ -0,0 +1,70 @@ +//: Calls can also generate results, using 'reply'. +:(scenario "reply") +recipe main [ + 3:integer, 4:integer <- f 2:literal +] +recipe f [ + 12:integer <- next-ingredient + 13:integer <- add 1:literal, 12:integer + reply 12:integer, 13:integer +] ++run: instruction main/0 ++run: result 0 is 2 ++mem: storing 2 in location 3 ++run: result 1 is 3 ++mem: storing 3 in location 4 + +:(before "End Primitive Recipe Declarations") +REPLY, +:(before "End Primitive Recipe Numbers") +Recipe_number["reply"] = REPLY; +:(before "End Primitive Recipe Implementations") +case REPLY: { + vector > callee_results; + for (size_t i = 0; i < instructions[pc].ingredients.size(); ++i) { + callee_results.push_back(read_memory(instructions[pc].ingredients[i])); + } + rr.calls.pop(); + assert(!rr.calls.empty()); + size_t& caller_pc = rr.calls.top().pc; + instruction& caller_instruction = Recipe[rr.calls.top().running_recipe].steps[caller_pc]; + assert(caller_instruction.products.size() <= callee_results.size()); + for (size_t i = 0; i < caller_instruction.products.size(); ++i) { + trace("run") << "result " << i << " is " << to_string(callee_results[i]); + write_memory(caller_instruction.products[i], callee_results[i]); + } + ++caller_pc; + break; +} + +//: Results can include containers and exclusive containers, addresses and arrays. +:(scenario "reply_container") +recipe main [ + 3:point <- f 2:literal +] +recipe f [ + 12:integer <- next-ingredient + 13:integer <- copy 35:literal + reply 12:point +] ++run: instruction main/0 ++run: result 0 is [2, 35] ++mem: storing 2 in location 3 ++mem: storing 35 in location 4 + +:(code) +string to_string(const vector& in) { + if (in.empty()) return "[]"; + ostringstream out; + if (in.size() == 1) { + out << in[0]; + return out.str(); + } + out << "["; + for (size_t i = 0; i < in.size(); ++i) { + if (i > 0) out << ", "; + out << in[i]; + } + out << "]"; + return out.str(); +} diff --git a/cpp/040brace b/cpp/040brace new file mode 100644 index 00000000..d01fe359 --- /dev/null +++ b/cpp/040brace @@ -0,0 +1,387 @@ +//: Structured programming +//: +//: Our jump recipes are quite inconvenient to use, so mu provides a +//: lightweight tool called 'transform_braces' to work in a slightly more +//: convenient format with nested braces: +//: +//: { +//: some instructions +//: { +//: more instructions +//: } +//: } +//: +//: Braces are just labels, they require no special parsing. The pseudo +//: recipes 'loop' and 'break' jump to just after the enclosing '{' and '}' +//: respectively. +//: +//: Conditional and unconditional 'loop' and 'break' should give us 80% of the +//: benefits of the control-flow primitives we're used to in other languages, +//: like 'if', 'while', 'for', etc. + +:(scenarios transform_test) +:(scenario "brace_conversion") +recipe main [ + { + break + 1:integer <- copy 0:literal + } +] ++after-brace: recipe main ++after-brace: jump 1:offset ++after-brace: copy ... + +//: one-time setup +:(after "int main") + Transform.push_back(transform_braces); + +:(code) +void transform_braces(const recipe_number r) { +//? cout << "AAA transform_braces\n"; //? 1 +//? exit(0); //? 1 + const int OPEN = 0, CLOSE = 1; + list > braces; + for (size_t index = 0; index < Recipe[r].steps.size(); ++index) { + const instruction& inst = Recipe[r].steps[index]; + if (inst.label == "{") { + trace("brace") << r << ": push (open, " << index << ")"; + braces.push_back(pair(OPEN, index)); + } + if (inst.label == "}") { + trace("brace") << "push (close, " << index << ")"; + braces.push_back(pair(CLOSE, index)); + } + } + stack open_braces; + trace("after-brace") << "recipe " << Recipe[r].name; + for (size_t index = 0; index < Recipe[r].steps.size(); ++index) { + instruction& inst = Recipe[r].steps[index]; +//? cout << "AAA " << inst.name << ": " << inst.operation << '\n'; //? 1 + if (inst.label == "{") open_braces.push(index); + else if (inst.label == "}") open_braces.pop(); + else if (inst.is_label) + ; // do nothing + else if (inst.operation == Recipe_number["loop"]) { + inst.operation = Recipe_number["jump"]; + if (inst.ingredients.size() > 0 && isa_literal(inst.ingredients[0])) { + // explicit target; a later phase will handle it + trace("after-brace") << "jump " << inst.ingredients[0].name << ":offset"; + } + else { + reagent ing; + ing.set_value(open_braces.top()-index); + inst.ingredients.push_back(ing); + trace("after-brace") << "jump " << ing.value << ":offset"; + trace("after-brace") << index << ": " << ing.to_string(); + trace("after-brace") << index << ": " << Recipe[r].steps[index].ingredients[0].to_string(); + } + } + else if (inst.operation == Recipe_number["break"]) { + inst.operation = Recipe_number["jump"]; + if (inst.ingredients.size() > 0 && isa_literal(inst.ingredients[0])) { + // explicit target; a later phase will handle it + trace("after-brace") << "jump " << inst.ingredients[0].name << ":offset"; + } + else { + reagent ing; + ing.set_value(matching_brace(open_braces.top(), braces) - index - 1); + inst.ingredients.push_back(ing); + trace("after-brace") << "jump " << ing.value << ":offset"; + } + } + else if (inst.operation == Recipe_number["loop-if"]) { + inst.operation = Recipe_number["jump-if"]; + if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { + // explicit target; a later phase will handle it + trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; + } + else { + reagent ing; + ing.set_value(open_braces.top()-index); + inst.ingredients.push_back(ing); + trace("after-brace") << "jump-if " << inst.ingredients[0].name << ", " << ing.value << ":offset"; + } + } + else if (inst.operation == Recipe_number["break-if"]) { + inst.operation = Recipe_number["jump-if"]; + if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { + // explicit target; a later phase will handle it + trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; + } + else { + reagent ing; + ing.set_value(matching_brace(open_braces.top(), braces) - index - 1); + inst.ingredients.push_back(ing); + trace("after-brace") << "jump-if " << inst.ingredients[0].name << ", " << ing.value << ":offset"; + } + } + else if (inst.operation == Recipe_number["loop-unless"]) { + inst.operation = Recipe_number["jump-unless"]; + if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { + // explicit target; a later phase will handle it + trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; + } + else { + reagent ing; + ing.set_value(open_braces.top()-index); + inst.ingredients.push_back(ing); + trace("after-brace") << "jump-unless " << inst.ingredients[0].name << ", " << ing.value << ":offset"; + } + } + else if (inst.operation == Recipe_number["break-unless"]) { +//? cout << "AAA break-unless\n"; //? 1 + inst.operation = Recipe_number["jump-unless"]; + if (inst.ingredients.size() > 1 && isa_literal(inst.ingredients[1])) { + // explicit target; a later phase will handle it + trace("after-brace") << "jump " << inst.ingredients[1].name << ":offset"; + } + else { + reagent ing; + ing.set_value(matching_brace(open_braces.top(), braces) - index - 1); + inst.ingredients.push_back(ing); + trace("after-brace") << "jump-unless " << inst.ingredients[0].name << ", " << ing.value << ":offset"; + } + } + else { + trace("after-brace") << inst.name << " ..."; + } + } +} + +size_t matching_brace(size_t index, const list >& braces) { + int stacksize; + for (list >::const_iterator p = braces.begin(); p != braces.end(); ++p) { + if (p->second < index) continue; + stacksize += (p->first ? 1 : -1); + if (stacksize == 0) return p->second; + } + assert(false); + return -1; +} + +// temporarily suppress run +void transform_test(string form) { +//? cout << "AAA transform_test {\n"; //? 1 + vector tmp = add_recipes(form); +//? cout << "AAA done adding recipes\n"; //? 1 + transform_all(); +//? cout << "AAA }\n"; //? 1 +} + +//: Make sure these pseudo recipes get consistent numbers in all tests, even +//: though they aren't implemented. + +:(before "End Primitive Recipe Declarations") +BREAK, +BREAK_IF, +BREAK_UNLESS, +LOOP, +LOOP_IF, +LOOP_UNLESS, +:(before "End Primitive Recipe Numbers") +Recipe_number["break"] = BREAK; +Recipe_number["break-if"] = BREAK_IF; +Recipe_number["break-unless"] = BREAK_UNLESS; +Recipe_number["loop"] = LOOP; +Recipe_number["loop-if"] = LOOP_IF; +Recipe_number["loop-unless"] = LOOP_UNLESS; + +:(scenario "loop") +recipe main [ + 1:integer <- copy 0:literal + 2:integer <- copy 0:literal + { + 3:integer <- copy 0:literal + loop + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: copy ... ++after-brace: copy ... ++after-brace: jump -2:offset + +:(scenario "break_empty_block") +recipe main [ + 1:integer <- copy 0:literal + { + break + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: jump 0:offset + +:(scenario "break_cascading") +recipe main [ + 1:integer <- copy 0:literal + { + break + } + { + break + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: jump 0:offset ++after-brace: jump 0:offset + +:(scenario "break_cascading2") +recipe main [ + 1:integer <- copy 0:literal + 2:integer <- copy 0:literal + { + break + 3:integer <- copy 0:literal + } + { + break + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: copy ... ++after-brace: jump 1:offset ++after-brace: copy ... ++after-brace: jump 0:offset + +:(scenario "break_if") +recipe main [ + 1:integer <- copy 0:literal + 2:integer <- copy 0:literal + { + break-if 2:integer + 3:integer <- copy 0:literal + } + { + break + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: copy ... ++after-brace: jump-if 2, 1:offset ++after-brace: copy ... ++after-brace: jump 0:offset + +:(scenario "break_nested") +recipe main [ + 1:integer <- copy 0:literal + { + 2:integer <- copy 0:literal + break + { + 3:integer <- copy 0:literal + } + 4:integer <- copy 0:literal + } +] ++after-brace: jump 4:offset + +:(scenario "break_nested_degenerate") +recipe main [ + 1:integer <- copy 0:literal + { + 2:integer <- copy 0:literal + break + { + } + 4:integer <- copy 0:literal + } +] ++after-brace: jump 3:offset + +:(scenario "break_nested_degenerate2") +recipe main [ + 1:integer <- copy 0:literal + { + 2:integer <- copy 0:literal + break + { + } + } +] ++after-brace: jump 2:offset + +:(scenario "break_label") +recipe main [ + 1:integer <- copy 0:literal + { + break +foo:offset + } +] ++after-brace: jump +foo:offset + +:(scenario "break_unless") +recipe main [ + 1:integer <- copy 0:literal + 2:integer <- copy 0:literal + { + break-unless 2:integer + 3:integer <- copy 0:literal + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: copy ... ++after-brace: jump-unless 2, 1:offset ++after-brace: copy ... + +:(scenario "loop_unless") +recipe main [ + 1:integer <- copy 0:literal + 2:integer <- copy 0:literal + { + loop-unless 2:integer + 3:integer <- copy 0:literal + } +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: copy ... ++after-brace: jump-unless 2, -1:offset ++after-brace: copy ... + +:(scenario "loop_nested") +recipe main [ + 1:integer <- copy 0:literal + { + 2:integer <- copy 0:literal + { + 3:integer <- copy 0:literal + } + loop-if 4:boolean + 5:integer <- copy 0:literal + } +] ++after-brace: recipe main ++after-brace: jump-if 4, -5:offset + +:(scenario "loop_label") +recipe main [ + 1:integer <- copy 0:literal + +foo + 2:integer <- copy 0:literal +] ++after-brace: recipe main ++after-brace: copy ... ++after-brace: copy ... + +//: test how things actually run +:(scenarios run) +:(scenario "factorial") +recipe factorial [ + 1:integer <- copy 5:literal + 2:integer <- copy 1:literal + { + 3:boolean <- equal 1:integer 1:literal + break-if 3:boolean +# $print 1:integer + 2:integer <- multiply 2:integer, 1:integer + 1:integer <- subtract 1:integer, 1:literal + loop + } + 4:integer <- copy 2:integer # trigger a read +] ++mem: location 2 is 120 diff --git a/cpp/040scenario b/cpp/040scenario deleted file mode 100644 index c595ce82..00000000 --- a/cpp/040scenario +++ /dev/null @@ -1,132 +0,0 @@ -//: Allow tests to be written in mu files. -:(before "End Types") -struct scenario { - string name; - string to_run; - map memory_expectations; - // End scenario Fields -}; - -:(before "End Globals") -vector Scenarios; - -:(before "End Tests") -time_t mu_time; time(&mu_time); -cerr << "\nMu tests: " << ctime(&mu_time); -for (size_t i = 0; i < Scenarios.size(); ++i) { - setup(); - Trace_file = Scenarios[i].name; - START_TRACING_UNTIL_END_OF_SCOPE -//? Trace_stream->dump_layer = "all"; //? 1 -//? cout << "Before:\n"; dump_memory(); //? 1 -//? cout << Scenarios[i].to_run; //? 1 - run(Scenarios[i].to_run); -//? cout << "After:\n"; dump_memory(); //? 1 - for (map::iterator p = Scenarios[i].memory_expectations.begin(); - p != Scenarios[i].memory_expectations.end(); - ++p) { - if (Memory[p->first] != p->second) { - cerr << Scenarios[i].name << ": Expected location " << p->first << " to contain " << p->second << " but saw " << Memory[p->first] << '\n'; - Passed = false; - } - } - // End Scenario Checks - if (Passed) cerr << "."; -} - -:(before "End Command Handlers") -else if (command == "scenario") { -//? cout << "AAA scenario\n"; //? 1 - Scenarios.push_back(parse_scenario(in)); -} - -:(code) -scenario parse_scenario(istream& in) { - scenario x; - x.name = next_word(in); - trace("parse") << "reading scenario " << x.name; - skip_bracket(in, "'scenario' must begin with '['"); - ostringstream buffer; - slurp_until_matching_bracket(in, buffer); -//? cout << "inner buffer: ^" << buffer.str() << "$\n"; //? 1 - istringstream inner(buffer.str()); - inner >> std::noskipws; - while (!inner.eof()) { - skip_whitespace_and_comments(inner); - string scenario_command = next_word(inner); - if (scenario_command.empty() && inner.eof()) break; - // Scenario Command Handlers - if (scenario_command == "run") { - handle_scenario_run_directive(inner, x); - trace("parse") << "scenario will run: " << x.to_run; - } - else if (scenario_command == "memory") { - handle_scenario_memory_directive(inner, x); - } - // End Scenario Command Handlers - else { - raise << "unknown command in scenario: ^" << scenario_command << "$\n"; - } - } - return x; -} - -void handle_scenario_run_directive(istream& in, scenario& result) { - skip_bracket(in, "'run' inside scenario must begin with '['"); - ostringstream buffer; - slurp_until_matching_bracket(in, buffer); - result.to_run = "recipe test-"+result.name+" [" + buffer.str() + "]"; -} - -void handle_scenario_memory_directive(istream& in, scenario& out) { - if (next_word(in) != "should") { - raise << "'memory' directive inside scenario must continue 'memory should'\n"; - } - if (next_word(in) != "contain") { - raise << "'memory' directive inside scenario must continue 'memory should contain'\n"; - } - skip_bracket(in, "'memory' directive inside scenario must begin with 'memory should contain ['\n"); - while (true) { - skip_whitespace_and_comments(in); - if (in.eof()) break; -//? cout << "a: " << in.peek() << '\n'; //? 1 - if (in.peek() == ']') break; - int address = 0; in >> address; -//? cout << "address: " << address << '\n'; //? 2 -//? cout << "b: " << in.peek() << '\n'; //? 1 - skip_whitespace_and_comments(in); -//? cout << "c: " << in.peek() << '\n'; //? 1 - string _assign; in >> _assign; assert(_assign == "<-"); - skip_whitespace_and_comments(in); - int value = 0; in >> value; - out.memory_expectations[address] = value; - trace("parse") << "memory expectation: *" << address << " == " << value; - } - skip_whitespace(in); - assert(in.get() == ']'); -} - -void slurp_until_matching_bracket(istream& in, ostream& out) { - int brace_depth = 1; // just scanned '[' - char c; - while (in >> c) { - if (c == '[') ++brace_depth; - if (c == ']') --brace_depth; - if (brace_depth == 0) break; // drop final ']' - out << c; - } -} - -void skip_bracket(istream& in, string message) { - skip_whitespace(in); skip_comments_and_newlines(in); skip_whitespace(in); - if (in.get() != '[') - raise << message << '\n'; -} - -void skip_whitespace_and_comments(istream& in) { - while (true) { - if (isspace(in.peek())) in.get(); - else if (in.peek() == '#') skip_comment(in); - else break; - } -} diff --git a/cpp/041name b/cpp/041name new file mode 100644 index 00000000..375f9854 --- /dev/null +++ b/cpp/041name @@ -0,0 +1,172 @@ +//: A big convenience high-level languages provide is the ability to name memory +//: locations. In mu, a transform called 'convert-names' provides this +//: convenience. + +:(scenarios run) +:(scenario "convert_names") +recipe main [ + x:integer <- copy 0:literal +] ++name: assign x 1 ++run: instruction main/0 ++mem: storing 0 in location 1 + +:(scenario "convert_names_warns") +hide warnings +recipe main [ + x:integer <- copy y:integer +] ++warn: use before set: y in main + +:(after "int main") + Transform.push_back(transform_names); + +:(before "End Globals") +unordered_map > Name; +:(after "Clear Other State For recently_added_recipes") +for (size_t i = 0; i < recently_added_recipes.size(); ++i) { + Name.erase(recently_added_recipes[i]); +} + +:(code) +void transform_names(const recipe_number r) { + unordered_map& names = Name[r]; + int curr_idx = 1; +//? cout << "Recipe " << r << '\n'; //? 2 +//? cout << Recipe[r].steps.size(); //? 1 + for (size_t i = 0; i < Recipe[r].steps.size(); ++i) { +//? cout << "instruction " << i << '\n'; //? 2 + instruction& inst = Recipe[r].steps[i]; + // Per-recipe Transforms + // map names to addresses + for (size_t in = 0; in < inst.ingredients.size(); ++in) { +//? cout << "ingredients\n"; //? 2 + if (is_raw(inst.ingredients[in])) continue; +//? cout << "ingredient " << inst.ingredients[in].name << '\n'; //? 2 + if (inst.ingredients[in].name == "default-space") + inst.ingredients[in].initialized = true; + assert(!inst.ingredients[in].types.empty()); + if (inst.ingredients[in].types[0] // not a literal + && !inst.ingredients[in].initialized + && inst.ingredients[in].name.find_first_not_of("0123456789-.") != string::npos) { + if (!already_transformed(inst.ingredients[in], names)) { + raise << "use before set: " << inst.ingredients[in].name << " in " << Recipe[r].name << '\n'; + } + inst.ingredients[in].set_value(lookup_name(inst.ingredients[in], r)); +//? cout << "lookup ingredient " << Recipe[r].name << "/" << i << ": " << inst.ingredients[in].to_string() << '\n'; //? 1 + } + } + for (size_t out = 0; out < inst.products.size(); ++out) { +//? cout << "products\n"; //? 1 + if (is_raw(inst.products[out])) continue; +//? cout << "product " << out << '/' << inst.products.size() << " " << inst.products[out].name << '\n'; //? 4 +//? cout << inst.products[out].types[0] << '\n'; //? 1 + if (inst.products[out].name == "default-space") + inst.products[out].initialized = true; + if (inst.products[out].types[0] // not a literal + && !inst.products[out].initialized + && inst.products[out].name.find_first_not_of("0123456789-.") != string::npos) { + if (names.find(inst.products[out].name) == names.end()) { + trace("name") << "assign " << inst.products[out].name << " " << curr_idx; + names[inst.products[out].name] = curr_idx; + curr_idx += size_of(inst.products[out]); + } + inst.products[out].set_value(lookup_name(inst.products[out], r)); +//? cout << "lookup product " << Recipe[r].name << "/" << i << ": " << inst.products[out].to_string() << '\n'; //? 1 + } + } + } +} + +bool already_transformed(const reagent& r, const unordered_map& names) { + return names.find(r.name) != names.end(); +} + +size_t lookup_name(const reagent& r, const recipe_number default_recipe) { + return Name[default_recipe][r.name]; +} + +type_number skip_addresses(const vector& types) { + for (size_t i = 0; i < types.size(); ++i) { + if (types[i] != Type_number["address"]) return types[i]; + } + raise << "expected a container" << '\n' << die(); + return -1; +} + +int find_element_name(const type_number t, const string& name) { + const type_info& container = Type[t]; +//? cout << "looking for element " << name << " in type " << container.name << " with " << container.element_names.size() << " elements\n"; //? 1 + for (size_t i = 0; i < container.element_names.size(); ++i) { + if (container.element_names[i] == name) return i; + } + raise << "unknown element " << name << " in container " << t << '\n' << die(); + return -1; +} + +bool is_raw(const reagent& r) { + for (size_t i = /*skip value+type*/1; i < r.properties.size(); ++i) { + if (r.properties[i].first == "raw") return true; + } + return false; +} + +:(scenario "convert_names_passes_dummy") +# _ is just a dummy result that never gets consumed +recipe main [ + _, x:integer <- copy 0:literal +] ++name: assign x 1 +-name: assign _ 1 + +//: one reserved word that we'll need later +:(scenario "convert_names_passes_default_space") +recipe main [ + default-space:integer, x:integer <- copy 0:literal +] ++name: assign x 1 +-name: assign default-space 1 + +//: an escape hatch to suppress name conversion that we'll use later +:(scenario "convert_names_passes_raw") +recipe main [ + x:integer/raw <- copy 0:literal +] +-name: assign x 1 + +//: update our running example container for the next test +:(before "End Mu Types Initialization") +Type[point].element_names.push_back("x"); +Type[point].element_names.push_back("y"); +:(scenario "convert_names_transforms_container_elements") +recipe main [ + a:integer <- get 0:point, y:offset + b:integer <- get 0:point, x:offset +] ++name: element y of type point is at offset 1 ++name: element x of type point is at offset 0 + +:(after "Per-recipe Transforms") +// replace element names of containers with offsets +if (inst.operation == Recipe_number["get"] + || inst.operation == Recipe_number["get-address"]) { + // at least 2 args, and second arg is offset + assert(inst.ingredients.size() >= 2); +//? cout << inst.ingredients[1].to_string() << '\n'; //? 1 + assert(isa_literal(inst.ingredients[1])); + if (inst.ingredients[1].name.find_first_not_of("0123456789") == string::npos) continue; + // since first non-address in base type must be a container, we don't have to canonize + type_number container = skip_addresses(inst.ingredients[0].types); + inst.ingredients[1].set_value(find_element_name(container, inst.ingredients[1].name)); + trace("name") << "element " << inst.ingredients[1].name << " of type " << Type[container].name << " is at offset " << inst.ingredients[1].value; +} + +//: this test is actually illegal so can't call run +:(scenarios transform_test) +:(scenario "convert_names_handles_containers") +recipe main [ + a:point <- copy 0:literal + b:integer <- copy 0:literal +] ++name: assign a 1 ++name: assign b 3 diff --git a/cpp/041scenario_test.mu b/cpp/041scenario_test.mu deleted file mode 100644 index bf30ce8f..00000000 --- a/cpp/041scenario_test.mu +++ /dev/null @@ -1,9 +0,0 @@ -# tests for 'scenario' in previous layer -scenario first_scenario_in_mu [ - run [ - 1:integer <- add 2:literal, 2:literal - ] - memory should contain [ - 1 <- 4 - ] -] diff --git a/cpp/042new b/cpp/042new new file mode 100644 index 00000000..0d7742f8 --- /dev/null +++ b/cpp/042new @@ -0,0 +1,102 @@ +//: A simple memory allocator to create space for new variables at runtime. + +:(scenarios run) +:(scenario "new") +# call new two times with identical arguments; you should get back different results +recipe main [ + 1:address:integer/raw <- new integer:type + 2:address:integer/raw <- new integer:type + 3:boolean/raw <- equal 1:address:integer/raw, 2:address:integer/raw +] ++mem: storing 0 in location 3 + +:(before "End Globals") +const size_t Alloc_init = 1000; +:(before "End routine Fields") +size_t alloc; +:(replace{} "routine::routine(recipe_number r)") + routine::routine(recipe_number r) :alloc(Alloc_init) { + calls.push(call(r)); + } + +//: First handle 'type' operands +:(before "End Mu Types Initialization") +Type_number["type"] = 0; +:(after "Per-recipe Transforms") +// replace type names with type_numbers +if (inst.operation == Recipe_number["new"]) { + // first arg must be of type 'type' + assert(inst.ingredients.size() >= 1); +//? cout << inst.ingredients[0].to_string() << '\n'; //? 1 + assert(isa_literal(inst.ingredients[0])); + if (inst.ingredients[0].properties[0].second[0] == "type") { + inst.ingredients[0].set_value(Type_number[inst.ingredients[0].name]); + } + trace("new") << inst.ingredients[0].name << " -> " << inst.ingredients[0].value; +} + +//: Now implement the primitive recipe. +:(before "End Primitive Recipe Declarations") +NEW, +:(before "End Primitive Recipe Numbers") +Recipe_number["new"] = NEW; +:(before "End Primitive Recipe Implementations") +case NEW: { + vector result; + trace("mem") << "new alloc: " << Current_routine->alloc; + result.push_back(Current_routine->alloc); + write_memory(instructions[pc].products[0], result); + vector types; + types.push_back(instructions[pc].ingredients[0].value); + if (instructions[pc].ingredients.size() > 1) { + // array + vector capacity = read_memory(instructions[pc].ingredients[1]); + trace("mem") << "array size is " << capacity[0]; + Memory[Current_routine->alloc] = capacity[0]; + Current_routine->alloc += capacity[0]*size_of(types); + } + else { + // scalar + Current_routine->alloc += size_of(types); + } + break; +} + +:(scenario "new_array") +recipe main [ + 1:address:array:integer/raw <- new integer:type, 5:literal + 2:address:integer/raw <- new integer:type + 3:integer/raw <- subtract 2:address:integer/raw, 1:address:array:integer/raw +] ++run: instruction main/0 ++mem: array size is 5 ++run: instruction main/1 ++run: instruction main/2 ++mem: storing 5 in location 3 + +//: Next, extend 'new' to handle a string literal argument. +:(scenario "new_string") +recipe main [ + 1:address:array:character <- new [abc def] + 2:character <- index 1:address:array:character/deref, 5:literal +] +# integer code for 'e' ++mem: storing 101 in location 2 + +:(after "case NEW" following "Primitive Recipe Implementations") +if (instructions[pc].ingredients[0].properties[0].second[0] == "literal-string") { + // allocate an array just large enough for it + vector result; + result.push_back(Current_routine->alloc); + write_memory(instructions[pc].products[0], result); + // assume that all characters fit in a single location +//? cout << "new string literal: " << instructions[pc].ingredients[0].name << '\n'; //? 1 + Memory[Current_routine->alloc++] = instructions[pc].ingredients[0].name.size(); + for (size_t i = 0; i < instructions[pc].ingredients[0].name.size(); ++i) { + Memory[Current_routine->alloc++] = instructions[pc].ingredients[0].name[i]; + } + // mu strings are not null-terminated in memory + break; +} + +//: vim: ft=cpp diff --git a/cpp/042trace b/cpp/042trace deleted file mode 100644 index bd05d848..00000000 --- a/cpp/042trace +++ /dev/null @@ -1,19 +0,0 @@ -:(scenario "trace") -recipe main [ - trace [foo], [this is a trace in mu] -] -+foo: this is a trace in mu - -:(before "End Primitive Recipe Declarations") -TRACE, -:(before "End Primitive Recipe Numbers") -Recipe_number["trace"] = TRACE; -:(before "End Primitive Recipe Implementations") -case TRACE: { - assert(isa_literal(instructions[pc].ingredients[0])); - string label = instructions[pc].ingredients[0].name; - assert(isa_literal(instructions[pc].ingredients[1])); - string message = instructions[pc].ingredients[1].name; - trace(label) << message; - break; -} diff --git a/cpp/043scenario_trace b/cpp/043scenario_trace deleted file mode 100644 index 90dab204..00000000 --- a/cpp/043scenario_trace +++ /dev/null @@ -1,101 +0,0 @@ -:(before "End scenario Fields") -vector > trace_checks; -vector > trace_negative_checks; - -:(before "End Scenario Command Handlers") -else if (scenario_command == "trace") { - handle_scenario_trace_directive(inner, x); -} - -:(before "End Scenario Checks") -check_trace_contents(Scenarios[i]); -check_trace_negative_contents(Scenarios[i]); - -:(code) -void handle_scenario_trace_directive(istream& in, scenario& out) { - if (next_word(in) != "should") { - raise << "'trace' directive inside scenario must continue 'trace should'\n"; - } - string s = next_word(in); - if (s == "not") { - handle_scenario_trace_negative_directive(in, out); - return; - } - if (s != "contain") { - raise << "'trace' directive inside scenario must continue 'trace should [not] contain'\n"; - } - skip_bracket(in, "'trace' directive inside scenario must begin with 'trace should contain ['\n"); - while (true) { - skip_whitespace_and_comments(in); - if (in.eof()) break; - if (in.peek() == ']') break; - string curr_line; - getline(in, curr_line); - istringstream tmp(curr_line); - tmp >> std::noskipws; - string label = slurp_until(tmp, ':'); - if (tmp.get() != ' ') { - raise << "'trace' directive inside scenario should contain lines of the form 'label: message', instead got " << curr_line; - continue; - } - string message = slurp_rest(tmp); - out.trace_checks.push_back(pair(label, message)); - trace("scenario") << "trace: " << label << ": " << message << '\n'; - } - skip_whitespace(in); - assert(in.get() == ']'); -} - -void handle_scenario_trace_negative_directive(istream& in, scenario& out) { - // 'not' already slurped - if (next_word(in) != "contain") { - raise << "'trace' directive inside scenario must continue 'trace should not contain'\n"; - } - skip_bracket(in, "'trace' directive inside scenario must begin with 'trace should not contain ['\n"); - while (true) { - skip_whitespace_and_comments(in); - if (in.eof()) break; - if (in.peek() == ']') break; - string curr_line; - getline(in, curr_line); - istringstream tmp(curr_line); - tmp >> std::noskipws; - string label = slurp_until(tmp, ':'); - if (tmp.get() != ' ') { - raise << "'trace' directive inside scenario should contain lines of the form 'label: message', instead got " << curr_line; - continue; - } - string message = slurp_rest(tmp); - out.trace_negative_checks.push_back(pair(label, message)); - trace("scenario") << "trace: " << label << ": " << message << '\n'; - } - skip_whitespace(in); - assert(in.get() == ']'); -} - -string slurp_rest(istream& in) { - ostringstream out; - char c; - while (in >> c) { - out << c; - } - return out.str(); -} - -void check_trace_contents(const scenario& s) { - if (s.trace_checks.empty()) return; - ostringstream contents; - for (size_t i = 0; i < s.trace_checks.size(); ++i) { - contents << s.trace_checks[i].first << ": " << s.trace_checks[i].second << ""; - } - CHECK_TRACE_CONTENTS(contents.str()); -} - -void check_trace_negative_contents(const scenario& s) { - for (size_t i = 0; i < s.trace_negative_checks.size(); ++i) { - if (trace_count(s.trace_negative_checks[i].first, s.trace_negative_checks[i].second) > 0) { - raise << "trace shouldn't contain " << s.trace_negative_checks[i].first << ": " << s.trace_negative_checks[i].second << '\n'; - Passed = false; - } - } -} diff --git a/cpp/043space b/cpp/043space new file mode 100644 index 00000000..1bb91b8e --- /dev/null +++ b/cpp/043space @@ -0,0 +1,90 @@ +//: Spaces help isolate functions from each other. You can create them at will, +//: and all addresses in arguments are implicitly based on the 'default-space' +//: (unless they have the /raw property) + +:(scenarios run) +:(scenario "set_default_space") +# if default-space is 10, and if an array of 5 locals lies from location 11 to 15 (inclusive), +# then location 0 is really location 11, location 1 is really location 12, and so on. +recipe main [ + 10:integer <- copy 5:literal # pretend array; in practice we'll use new + default-space:address:space <- copy 10:literal + 1:integer <- copy 23:literal +] ++mem: storing 23 in location 12 + +:(scenario "deref_sidesteps_default_space") +recipe main [ + # pretend pointer from outside + 7:integer <- copy 34:literal + # pretend array + 10:integer <- copy 5:literal + # actual start of this function + default-space:address:space <- copy 10:literal + 1:address:integer <- copy 7:literal + 8:integer/raw <- copy 1:address:integer/deref +] ++mem: storing 34 in location 8 + +:(before "End call Fields") +size_t default_space; +:(replace "call(recipe_number r) :running_recipe(r)") +call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0), default_space(0) {} + +:(replace "reagent r = x" following "reagent canonize(reagent x)") +reagent r = absolutize(x); +:(code) +reagent absolutize(reagent x) { +//? if (Recipe_number.find("increment-counter") != Recipe_number.end()) //? 1 +//? cout << "AAA " << "increment-counter/2: " << Recipe[Recipe_number["increment-counter"]].steps[2].products[0].to_string() << '\n'; //? 1 +//? cout << "absolutize " << x.to_string() << '\n'; //? 3 +//? cout << is_raw(x) << '\n'; //? 1 + if (is_raw(x) || is_dummy(x)) return x; +//? cout << "not raw: " << x.to_string() << '\n'; //? 1 + assert(x.initialized); + reagent r = x; + r.set_value(address(r.value, space_base(r))); +//? cout << "after absolutize: " << r.value << '\n'; //? 1 + r.properties.push_back(pair >("raw", vector())); + assert(is_raw(r)); + return r; +} +:(before "return result" following "reagent deref(reagent x)") +result.properties.push_back(pair >("raw", vector())); + +:(code) +int space_base(const reagent& x) { + return Current_routine->calls.top().default_space; +} + +int address(int offset, int base) { + if (base == 0) return offset; // raw +//? cout << base << '\n'; //? 1 + if (offset >= Memory[base]) { + // todo: test + raise << "location " << offset << " is out of bounds " << Memory[base] << '\n'; + } + return base+1 + offset; +} + +:(after "void write_memory(reagent x, vector data)") + if (x.name == "default-space") { + assert(data.size() == 1); + Current_routine->calls.top().default_space = data[0]; +//? cout << "AAA " << Current_routine->calls.top().default_space << '\n'; //? 1 + return; + } + +:(scenario "get_default_space") +recipe main [ + default-space:address:space <- copy 10:literal + 1:integer/raw <- copy default-space:address:space +] ++mem: storing 10 in location 1 + +:(after "vector read_memory(reagent x)") + if (x.name == "default-space") { + vector result; + result.push_back(Current_routine->calls.top().default_space); + return result; + } diff --git a/cpp/044scenario_trace_test.mu b/cpp/044scenario_trace_test.mu deleted file mode 100644 index abf0ef9a..00000000 --- a/cpp/044scenario_trace_test.mu +++ /dev/null @@ -1,27 +0,0 @@ -# tests for trace-checking scenario in previous layer -scenario first_scenario_checking_trace [ - run [ - 1:integer <- add 2:literal, 2:literal - ] - trace should contain [ - mem: storing 4 in location 1 - ] -] - -scenario first_scenario_checking_trace_negative [ - run [ - 1:integer <- add 2:literal, 2:literal - ] - trace should not contain [ - mem: storing 5 in location 1 - ] -] - -scenario trace_in_mu [ - run [ - trace [foo], [aaa] - ] - trace should contain [ - foo: aaa - ] -] diff --git a/cpp/044space_surround b/cpp/044space_surround new file mode 100644 index 00000000..76cd5807 --- /dev/null +++ b/cpp/044space_surround @@ -0,0 +1,50 @@ +//: So far you can have global variables by not setting default-space, and +//: local variables by setting default-space. You can isolate variables +//: between those extremes by creating 'surrounding' spaces. +//: +//: (Surrounding spaces are like lexical scopes in other languages.) + +:(scenario "surrounding_space") +# location 1 in space 1 refers to the space surrounding the default space, here 20. +recipe main [ + 10:integer <- copy 5:literal # pretend array + 20:integer <- copy 5:literal # pretend array + default-space:address:space <- copy 10:literal + 0:address:space/names:dummy <- copy 20:literal # later layers will explain the /names: property + 1:integer <- copy 32:literal + 1:integer/space:1 <- copy 33:literal +] ++run: instruction main/3 ++mem: storing 20 in location 11 ++run: instruction main/4 ++mem: storing 32 in location 12 ++run: instruction main/5 ++mem: storing 33 in location 22 + +//: If you think of a space as a collection of variables with a common +//: lifetime, surrounding allows managing shorter lifetimes inside a longer +//: one. + +:(replace{} "int space_base(const reagent& x)") +int space_base(const reagent& x) { + return space_base(x, space_index(x), Current_routine->calls.top().default_space); +} + +int space_base(const reagent& x, int space_index, int base) { +//? trace("foo") << "base of space " << space_index << '\n'; //? 1 + if (space_index == 0) { +//? trace("foo") << "base of space " << space_index << " is " << base << '\n'; //? 1 + return base; + } +//? trace("foo") << "base of space " << space_index << " is " << Memory[base+1] << '\n'; //? 1 + int result = space_base(x, space_index-1, Memory[base+1]); + return result; +} + +int space_index(const reagent& x) { + for (size_t i = 0; i < x.properties.size(); ++i) { + if (x.properties[i].first == "space") + return to_int(x.properties[i].second[0]); + } + return 0; +} diff --git a/cpp/045closure_name b/cpp/045closure_name deleted file mode 100644 index 76a1bdd7..00000000 --- a/cpp/045closure_name +++ /dev/null @@ -1,142 +0,0 @@ -//: Writing to a literal (not computed) address of 0 in a recipe chains two -//: spaces together. When a variable has a property of /space:1, it looks up -//: the variable in the chained/surrounding space. /space:2 looks up the -//: surrounding space of the surrounding space, etc. -:(scenario "closure") -recipe main [ - default-space:address:space <- new location:type, 30:literal - 1:address:space/names:init-counter <- init-counter -#? $print [AAAAAAAAAAAAAAAA] -#? $print 1:address:space - 2:integer/raw <- increment-counter 1:address:space/names:init-counter - 3:integer/raw <- increment-counter 1:address:space/names:init-counter -] - -recipe init-counter [ - default-space:address:space <- new location:type, 30:literal - x:integer <- copy 23:literal - y:integer <- copy 3:literal # variable that will be incremented - reply default-space:address:space -] - -recipe increment-counter [ - default-space:address:space <- new space:literal, 30:literal - 0:address:space/names:init-counter <- next-ingredient # outer space must be created by 'init-counter' above - y:integer/space:1 <- add y:integer/space:1, 1:literal # increment - y:integer <- copy 234:literal # dummy - reply y:integer/space:1 -] - -+name: recipe increment-counter is surrounded by init-counter -+mem: storing 5 in location 3 - -//: To make this work, compute the recipe that provides names for the -//: surrounding space of each recipe. This must happen before transform_names. -:(before "End Globals") -unordered_map Surrounding_space; - -:(after "int main") - Transform.push_back(collect_surrounding_spaces); - -:(code) -void collect_surrounding_spaces(const recipe_number r) { - for (size_t i = 0; i < Recipe[r].steps.size(); ++i) { - const instruction& inst = Recipe[r].steps[i]; - if (inst.is_label) continue; - for (size_t j = 0; j < inst.products.size(); ++j) { - if (isa_literal(inst.products[j])) continue; - if (inst.products[j].name != "0") continue; - if (inst.products[j].types.size() != 2 - || inst.products[j].types[0] != Type_number["address"] - || inst.products[j].types[1] != Type_number["space"]) { - raise << "slot 0 should always have type address:space, but is " << inst.products[j].to_string() << '\n'; - continue; - } - vector s = property(inst.products[j], "names"); - if (s.empty()) - raise << "slot 0 requires a /names property in recipe " << Recipe[r].name << die(); - if (s.size() > 1) raise << "slot 0 should have a single value in /names, got " << inst.products[j].to_string() << '\n'; - string surrounding_recipe_name = s[0]; - if (Surrounding_space.find(r) != Surrounding_space.end() - && Surrounding_space[r] != Recipe_number[surrounding_recipe_name]) { - raise << "recipe " << Recipe[r].name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n'; - continue; - } - trace("name") << "recipe " << Recipe[r].name << " is surrounded by " << surrounding_recipe_name; - Surrounding_space[r] = Recipe_number[surrounding_recipe_name]; - } - } -} - -vector property(const reagent& r, const string& name) { - for (size_t p = 0; p != r.properties.size(); ++p) { - if (r.properties[p].first == name) - return r.properties[p].second; - } - return vector(); -} - -//: Once surrounding spaces are available, transform_names uses them to handle -//: /space properties. - -:(replace{} "size_t lookup_name(const reagent& r, const recipe_number default_recipe)") -size_t lookup_name(const reagent& x, const recipe_number default_recipe) { -//? cout << "AAA " << default_recipe << " " << Recipe[default_recipe].name << '\n'; //? 2 -//? cout << "AAA " << x.to_string() << '\n'; //? 1 - if (!has_property(x, "space")) { - if (Name[default_recipe].empty()) raise << "name not found: " << x.name << '\n' << die(); - return Name[default_recipe][x.name]; - } - vector p = property(x, "space"); - if (p.size() != 1) raise << "/space property should have exactly one (non-negative integer) value\n"; - int n = to_int(p[0]); - assert(n >= 0); - recipe_number surrounding_recipe = lookup_surrounding_recipe(default_recipe, n); - set done; - vector path; - return lookup_name(x, surrounding_recipe, done, path); -} - -// If the recipe we need to lookup this name in doesn't have names done yet, -// recursively call transform_names on it. -size_t lookup_name(const reagent& x, const recipe_number r, set& done, vector& path) { - if (!Name[r].empty()) return Name[r][x.name]; - if (done.find(r) != done.end()) { - raise << "can't compute address of " << x.to_string() << " because "; - for (size_t i = 1; i < path.size(); ++i) { - raise << path[i-1] << " requires computing names of " << path[i] << '\n'; - } - raise << path[path.size()-1] << " requires computing names of " << r << "..ad infinitum\n" << die(); - return 0; - } - done.insert(r); - path.push_back(r); - transform_names(r); // Not passing 'done' through. Might this somehow cause an infinite loop? - assert(!Name[r].empty()); - return Name[r][x.name]; -} - -recipe_number lookup_surrounding_recipe(const recipe_number r, size_t n) { - if (n == 0) return r; - if (Surrounding_space.find(r) == Surrounding_space.end()) { - raise << "don't know surrounding recipe of " << Recipe[r].name << '\n'; - return 0; - } - assert(Surrounding_space[r]); - return lookup_surrounding_recipe(Surrounding_space[r], n-1); -} - -//: weaken use-before-set warnings just a tad -:(replace{} "bool already_transformed(const reagent& r, const unordered_map& names)") -bool already_transformed(const reagent& r, const unordered_map& names) { - if (has_property(r, "space")) { - vector p = property(r, "space"); - assert(p.size() == 1); - if (p[0] != "0") return true; - } - return names.find(r.name) != names.end(); -} - -:(before "End Includes") -#include -using std::set; diff --git a/cpp/050scenario b/cpp/050scenario new file mode 100644 index 00000000..c595ce82 --- /dev/null +++ b/cpp/050scenario @@ -0,0 +1,132 @@ +//: Allow tests to be written in mu files. +:(before "End Types") +struct scenario { + string name; + string to_run; + map memory_expectations; + // End scenario Fields +}; + +:(before "End Globals") +vector Scenarios; + +:(before "End Tests") +time_t mu_time; time(&mu_time); +cerr << "\nMu tests: " << ctime(&mu_time); +for (size_t i = 0; i < Scenarios.size(); ++i) { + setup(); + Trace_file = Scenarios[i].name; + START_TRACING_UNTIL_END_OF_SCOPE +//? Trace_stream->dump_layer = "all"; //? 1 +//? cout << "Before:\n"; dump_memory(); //? 1 +//? cout << Scenarios[i].to_run; //? 1 + run(Scenarios[i].to_run); +//? cout << "After:\n"; dump_memory(); //? 1 + for (map::iterator p = Scenarios[i].memory_expectations.begin(); + p != Scenarios[i].memory_expectations.end(); + ++p) { + if (Memory[p->first] != p->second) { + cerr << Scenarios[i].name << ": Expected location " << p->first << " to contain " << p->second << " but saw " << Memory[p->first] << '\n'; + Passed = false; + } + } + // End Scenario Checks + if (Passed) cerr << "."; +} + +:(before "End Command Handlers") +else if (command == "scenario") { +//? cout << "AAA scenario\n"; //? 1 + Scenarios.push_back(parse_scenario(in)); +} + +:(code) +scenario parse_scenario(istream& in) { + scenario x; + x.name = next_word(in); + trace("parse") << "reading scenario " << x.name; + skip_bracket(in, "'scenario' must begin with '['"); + ostringstream buffer; + slurp_until_matching_bracket(in, buffer); +//? cout << "inner buffer: ^" << buffer.str() << "$\n"; //? 1 + istringstream inner(buffer.str()); + inner >> std::noskipws; + while (!inner.eof()) { + skip_whitespace_and_comments(inner); + string scenario_command = next_word(inner); + if (scenario_command.empty() && inner.eof()) break; + // Scenario Command Handlers + if (scenario_command == "run") { + handle_scenario_run_directive(inner, x); + trace("parse") << "scenario will run: " << x.to_run; + } + else if (scenario_command == "memory") { + handle_scenario_memory_directive(inner, x); + } + // End Scenario Command Handlers + else { + raise << "unknown command in scenario: ^" << scenario_command << "$\n"; + } + } + return x; +} + +void handle_scenario_run_directive(istream& in, scenario& result) { + skip_bracket(in, "'run' inside scenario must begin with '['"); + ostringstream buffer; + slurp_until_matching_bracket(in, buffer); + result.to_run = "recipe test-"+result.name+" [" + buffer.str() + "]"; +} + +void handle_scenario_memory_directive(istream& in, scenario& out) { + if (next_word(in) != "should") { + raise << "'memory' directive inside scenario must continue 'memory should'\n"; + } + if (next_word(in) != "contain") { + raise << "'memory' directive inside scenario must continue 'memory should contain'\n"; + } + skip_bracket(in, "'memory' directive inside scenario must begin with 'memory should contain ['\n"); + while (true) { + skip_whitespace_and_comments(in); + if (in.eof()) break; +//? cout << "a: " << in.peek() << '\n'; //? 1 + if (in.peek() == ']') break; + int address = 0; in >> address; +//? cout << "address: " << address << '\n'; //? 2 +//? cout << "b: " << in.peek() << '\n'; //? 1 + skip_whitespace_and_comments(in); +//? cout << "c: " << in.peek() << '\n'; //? 1 + string _assign; in >> _assign; assert(_assign == "<-"); + skip_whitespace_and_comments(in); + int value = 0; in >> value; + out.memory_expectations[address] = value; + trace("parse") << "memory expectation: *" << address << " == " << value; + } + skip_whitespace(in); + assert(in.get() == ']'); +} + +void slurp_until_matching_bracket(istream& in, ostream& out) { + int brace_depth = 1; // just scanned '[' + char c; + while (in >> c) { + if (c == '[') ++brace_depth; + if (c == ']') --brace_depth; + if (brace_depth == 0) break; // drop final ']' + out << c; + } +} + +void skip_bracket(istream& in, string message) { + skip_whitespace(in); skip_comments_and_newlines(in); skip_whitespace(in); + if (in.get() != '[') + raise << message << '\n'; +} + +void skip_whitespace_and_comments(istream& in) { + while (true) { + if (isspace(in.peek())) in.get(); + else if (in.peek() == '#') skip_comment(in); + else break; + } +} diff --git a/cpp/050string.mu b/cpp/050string.mu deleted file mode 100644 index e85dc083..00000000 --- a/cpp/050string.mu +++ /dev/null @@ -1,96 +0,0 @@ -recipe string-equal [ - default-space:address:space <- new location:type, 30:literal - a:address:array:character <- next-ingredient - a-len:integer <- length a:address:array:character/deref - b:address:array:character <- next-ingredient - b-len:integer <- length b:address:array:character/deref - # compare lengths - { - trace [string-equal], [comparing lengths] - length-equal?:boolean <- equal a-len:integer, b-len:integer - break-if length-equal?:boolean - reply 0:literal - } - # compare each corresponding character - trace [string-equal], [comparing characters] - i:integer <- copy 0:literal - { - done?:boolean <- greater-or-equal i:integer, a-len:integer - break-if done?:boolean - a2:character <- index a:address:array:character/deref, i:integer - b2:character <- index b:address:array:character/deref, i:integer - { - chars-match?:boolean <- equal a2:character, b2:character - break-if chars-match?:boolean - reply 0:literal - } - i:integer <- add i:integer, 1:literal - loop - } - reply 1:literal -] - -scenario string-equal-reflexive [ - run [ - default-space:address:space <- new location:type, 30:literal - x:address:array:character <- new [abc] - 3:boolean/raw <- string-equal x:address:array:character, x:address:array:character - ] - memory should contain [ - 3 <- 1 # x == x for all x - ] -] - -scenario string-equal-identical [ - run [ - default-space:address:space <- new location:type, 30:literal - x:address:array:character <- new [abc] - y:address:array:character <- new [abc] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character - ] - memory should contain [ - 3 <- 1 # abc == abc - ] -] - -scenario string-equal-distinct-lengths [ - run [ - default-space:address:space <- new location:type, 30:literal - x:address:array:character <- new [abc] - y:address:array:character <- new [abcd] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character - ] - memory should contain [ - 3 <- 0 # abc != abcd - ] - trace should contain [ - string-equal: comparing lengths - ] - trace should not contain [ - string-equal: comparing characters - ] -] - -scenario string-equal-with-empty [ - run [ - default-space:address:space <- new location:type, 30:literal - x:address:array:character <- new [] - y:address:array:character <- new [abcd] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character - ] - memory should contain [ - 3 <- 0 # "" != abcd - ] -] - -scenario string-equal-common-lengths-but-distinct [ - run [ - default-space:address:space <- new location:type, 30:literal - x:address:array:character <- new [abc] - y:address:array:character <- new [abd] - 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character - ] - memory should contain [ - 3 <- 0 # abc != abd - ] -] diff --git a/cpp/051scenario_test.mu b/cpp/051scenario_test.mu new file mode 100644 index 00000000..bf30ce8f --- /dev/null +++ b/cpp/051scenario_test.mu @@ -0,0 +1,9 @@ +# tests for 'scenario' in previous layer +scenario first_scenario_in_mu [ + run [ + 1:integer <- add 2:literal, 2:literal + ] + memory should contain [ + 1 <- 4 + ] +] diff --git a/cpp/052scenario_trace b/cpp/052scenario_trace new file mode 100644 index 00000000..90dab204 --- /dev/null +++ b/cpp/052scenario_trace @@ -0,0 +1,101 @@ +:(before "End scenario Fields") +vector > trace_checks; +vector > trace_negative_checks; + +:(before "End Scenario Command Handlers") +else if (scenario_command == "trace") { + handle_scenario_trace_directive(inner, x); +} + +:(before "End Scenario Checks") +check_trace_contents(Scenarios[i]); +check_trace_negative_contents(Scenarios[i]); + +:(code) +void handle_scenario_trace_directive(istream& in, scenario& out) { + if (next_word(in) != "should") { + raise << "'trace' directive inside scenario must continue 'trace should'\n"; + } + string s = next_word(in); + if (s == "not") { + handle_scenario_trace_negative_directive(in, out); + return; + } + if (s != "contain") { + raise << "'trace' directive inside scenario must continue 'trace should [not] contain'\n"; + } + skip_bracket(in, "'trace' directive inside scenario must begin with 'trace should contain ['\n"); + while (true) { + skip_whitespace_and_comments(in); + if (in.eof()) break; + if (in.peek() == ']') break; + string curr_line; + getline(in, curr_line); + istringstream tmp(curr_line); + tmp >> std::noskipws; + string label = slurp_until(tmp, ':'); + if (tmp.get() != ' ') { + raise << "'trace' directive inside scenario should contain lines of the form 'label: message', instead got " << curr_line; + continue; + } + string message = slurp_rest(tmp); + out.trace_checks.push_back(pair(label, message)); + trace("scenario") << "trace: " << label << ": " << message << '\n'; + } + skip_whitespace(in); + assert(in.get() == ']'); +} + +void handle_scenario_trace_negative_directive(istream& in, scenario& out) { + // 'not' already slurped + if (next_word(in) != "contain") { + raise << "'trace' directive inside scenario must continue 'trace should not contain'\n"; + } + skip_bracket(in, "'trace' directive inside scenario must begin with 'trace should not contain ['\n"); + while (true) { + skip_whitespace_and_comments(in); + if (in.eof()) break; + if (in.peek() == ']') break; + string curr_line; + getline(in, curr_line); + istringstream tmp(curr_line); + tmp >> std::noskipws; + string label = slurp_until(tmp, ':'); + if (tmp.get() != ' ') { + raise << "'trace' directive inside scenario should contain lines of the form 'label: message', instead got " << curr_line; + continue; + } + string message = slurp_rest(tmp); + out.trace_negative_checks.push_back(pair(label, message)); + trace("scenario") << "trace: " << label << ": " << message << '\n'; + } + skip_whitespace(in); + assert(in.get() == ']'); +} + +string slurp_rest(istream& in) { + ostringstream out; + char c; + while (in >> c) { + out << c; + } + return out.str(); +} + +void check_trace_contents(const scenario& s) { + if (s.trace_checks.empty()) return; + ostringstream contents; + for (size_t i = 0; i < s.trace_checks.size(); ++i) { + contents << s.trace_checks[i].first << ": " << s.trace_checks[i].second << ""; + } + CHECK_TRACE_CONTENTS(contents.str()); +} + +void check_trace_negative_contents(const scenario& s) { + for (size_t i = 0; i < s.trace_negative_checks.size(); ++i) { + if (trace_count(s.trace_negative_checks[i].first, s.trace_negative_checks[i].second) > 0) { + raise << "trace shouldn't contain " << s.trace_negative_checks[i].first << ": " << s.trace_negative_checks[i].second << '\n'; + Passed = false; + } + } +} diff --git a/cpp/053scenario_trace_test.mu b/cpp/053scenario_trace_test.mu new file mode 100644 index 00000000..abf0ef9a --- /dev/null +++ b/cpp/053scenario_trace_test.mu @@ -0,0 +1,27 @@ +# tests for trace-checking scenario in previous layer +scenario first_scenario_checking_trace [ + run [ + 1:integer <- add 2:literal, 2:literal + ] + trace should contain [ + mem: storing 4 in location 1 + ] +] + +scenario first_scenario_checking_trace_negative [ + run [ + 1:integer <- add 2:literal, 2:literal + ] + trace should not contain [ + mem: storing 5 in location 1 + ] +] + +scenario trace_in_mu [ + run [ + trace [foo], [aaa] + ] + trace should contain [ + foo: aaa + ] +] diff --git a/cpp/054closure_name b/cpp/054closure_name new file mode 100644 index 00000000..76a1bdd7 --- /dev/null +++ b/cpp/054closure_name @@ -0,0 +1,142 @@ +//: Writing to a literal (not computed) address of 0 in a recipe chains two +//: spaces together. When a variable has a property of /space:1, it looks up +//: the variable in the chained/surrounding space. /space:2 looks up the +//: surrounding space of the surrounding space, etc. +:(scenario "closure") +recipe main [ + default-space:address:space <- new location:type, 30:literal + 1:address:space/names:init-counter <- init-counter +#? $print [AAAAAAAAAAAAAAAA] +#? $print 1:address:space + 2:integer/raw <- increment-counter 1:address:space/names:init-counter + 3:integer/raw <- increment-counter 1:address:space/names:init-counter +] + +recipe init-counter [ + default-space:address:space <- new location:type, 30:literal + x:integer <- copy 23:literal + y:integer <- copy 3:literal # variable that will be incremented + reply default-space:address:space +] + +recipe increment-counter [ + default-space:address:space <- new space:literal, 30:literal + 0:address:space/names:init-counter <- next-ingredient # outer space must be created by 'init-counter' above + y:integer/space:1 <- add y:integer/space:1, 1:literal # increment + y:integer <- copy 234:literal # dummy + reply y:integer/space:1 +] + ++name: recipe increment-counter is surrounded by init-counter ++mem: storing 5 in location 3 + +//: To make this work, compute the recipe that provides names for the +//: surrounding space of each recipe. This must happen before transform_names. +:(before "End Globals") +unordered_map Surrounding_space; + +:(after "int main") + Transform.push_back(collect_surrounding_spaces); + +:(code) +void collect_surrounding_spaces(const recipe_number r) { + for (size_t i = 0; i < Recipe[r].steps.size(); ++i) { + const instruction& inst = Recipe[r].steps[i]; + if (inst.is_label) continue; + for (size_t j = 0; j < inst.products.size(); ++j) { + if (isa_literal(inst.products[j])) continue; + if (inst.products[j].name != "0") continue; + if (inst.products[j].types.size() != 2 + || inst.products[j].types[0] != Type_number["address"] + || inst.products[j].types[1] != Type_number["space"]) { + raise << "slot 0 should always have type address:space, but is " << inst.products[j].to_string() << '\n'; + continue; + } + vector s = property(inst.products[j], "names"); + if (s.empty()) + raise << "slot 0 requires a /names property in recipe " << Recipe[r].name << die(); + if (s.size() > 1) raise << "slot 0 should have a single value in /names, got " << inst.products[j].to_string() << '\n'; + string surrounding_recipe_name = s[0]; + if (Surrounding_space.find(r) != Surrounding_space.end() + && Surrounding_space[r] != Recipe_number[surrounding_recipe_name]) { + raise << "recipe " << Recipe[r].name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n'; + continue; + } + trace("name") << "recipe " << Recipe[r].name << " is surrounded by " << surrounding_recipe_name; + Surrounding_space[r] = Recipe_number[surrounding_recipe_name]; + } + } +} + +vector property(const reagent& r, const string& name) { + for (size_t p = 0; p != r.properties.size(); ++p) { + if (r.properties[p].first == name) + return r.properties[p].second; + } + return vector(); +} + +//: Once surrounding spaces are available, transform_names uses them to handle +//: /space properties. + +:(replace{} "size_t lookup_name(const reagent& r, const recipe_number default_recipe)") +size_t lookup_name(const reagent& x, const recipe_number default_recipe) { +//? cout << "AAA " << default_recipe << " " << Recipe[default_recipe].name << '\n'; //? 2 +//? cout << "AAA " << x.to_string() << '\n'; //? 1 + if (!has_property(x, "space")) { + if (Name[default_recipe].empty()) raise << "name not found: " << x.name << '\n' << die(); + return Name[default_recipe][x.name]; + } + vector p = property(x, "space"); + if (p.size() != 1) raise << "/space property should have exactly one (non-negative integer) value\n"; + int n = to_int(p[0]); + assert(n >= 0); + recipe_number surrounding_recipe = lookup_surrounding_recipe(default_recipe, n); + set done; + vector path; + return lookup_name(x, surrounding_recipe, done, path); +} + +// If the recipe we need to lookup this name in doesn't have names done yet, +// recursively call transform_names on it. +size_t lookup_name(const reagent& x, const recipe_number r, set& done, vector& path) { + if (!Name[r].empty()) return Name[r][x.name]; + if (done.find(r) != done.end()) { + raise << "can't compute address of " << x.to_string() << " because "; + for (size_t i = 1; i < path.size(); ++i) { + raise << path[i-1] << " requires computing names of " << path[i] << '\n'; + } + raise << path[path.size()-1] << " requires computing names of " << r << "..ad infinitum\n" << die(); + return 0; + } + done.insert(r); + path.push_back(r); + transform_names(r); // Not passing 'done' through. Might this somehow cause an infinite loop? + assert(!Name[r].empty()); + return Name[r][x.name]; +} + +recipe_number lookup_surrounding_recipe(const recipe_number r, size_t n) { + if (n == 0) return r; + if (Surrounding_space.find(r) == Surrounding_space.end()) { + raise << "don't know surrounding recipe of " << Recipe[r].name << '\n'; + return 0; + } + assert(Surrounding_space[r]); + return lookup_surrounding_recipe(Surrounding_space[r], n-1); +} + +//: weaken use-before-set warnings just a tad +:(replace{} "bool already_transformed(const reagent& r, const unordered_map& names)") +bool already_transformed(const reagent& r, const unordered_map& names) { + if (has_property(r, "space")) { + vector p = property(r, "space"); + assert(p.size() == 1); + if (p[0] != "0") return true; + } + return names.find(r.name) != names.end(); +} + +:(before "End Includes") +#include +using std::set; diff --git a/cpp/060string.mu b/cpp/060string.mu new file mode 100644 index 00000000..e85dc083 --- /dev/null +++ b/cpp/060string.mu @@ -0,0 +1,96 @@ +recipe string-equal [ + default-space:address:space <- new location:type, 30:literal + a:address:array:character <- next-ingredient + a-len:integer <- length a:address:array:character/deref + b:address:array:character <- next-ingredient + b-len:integer <- length b:address:array:character/deref + # compare lengths + { + trace [string-equal], [comparing lengths] + length-equal?:boolean <- equal a-len:integer, b-len:integer + break-if length-equal?:boolean + reply 0:literal + } + # compare each corresponding character + trace [string-equal], [comparing characters] + i:integer <- copy 0:literal + { + done?:boolean <- greater-or-equal i:integer, a-len:integer + break-if done?:boolean + a2:character <- index a:address:array:character/deref, i:integer + b2:character <- index b:address:array:character/deref, i:integer + { + chars-match?:boolean <- equal a2:character, b2:character + break-if chars-match?:boolean + reply 0:literal + } + i:integer <- add i:integer, 1:literal + loop + } + reply 1:literal +] + +scenario string-equal-reflexive [ + run [ + default-space:address:space <- new location:type, 30:literal + x:address:array:character <- new [abc] + 3:boolean/raw <- string-equal x:address:array:character, x:address:array:character + ] + memory should contain [ + 3 <- 1 # x == x for all x + ] +] + +scenario string-equal-identical [ + run [ + default-space:address:space <- new location:type, 30:literal + x:address:array:character <- new [abc] + y:address:array:character <- new [abc] + 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + ] + memory should contain [ + 3 <- 1 # abc == abc + ] +] + +scenario string-equal-distinct-lengths [ + run [ + default-space:address:space <- new location:type, 30:literal + x:address:array:character <- new [abc] + y:address:array:character <- new [abcd] + 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + ] + memory should contain [ + 3 <- 0 # abc != abcd + ] + trace should contain [ + string-equal: comparing lengths + ] + trace should not contain [ + string-equal: comparing characters + ] +] + +scenario string-equal-with-empty [ + run [ + default-space:address:space <- new location:type, 30:literal + x:address:array:character <- new [] + y:address:array:character <- new [abcd] + 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + ] + memory should contain [ + 3 <- 0 # "" != abcd + ] +] + +scenario string-equal-common-lengths-but-distinct [ + run [ + default-space:address:space <- new location:type, 30:literal + x:address:array:character <- new [abc] + y:address:array:character <- new [abd] + 3:boolean/raw <- string-equal x:address:array:character, y:address:array:character + ] + memory should contain [ + 3 <- 0 # abc != abd + ] +] -- cgit 1.4.1-2-gfad0