Bläddra i källkod

Adapting jsiek's executable semantics tooling for commit. (#237)

Notes versus what jsiek wrote:

- This adopts Bazel for building.
    - System-local versions of bison/flex are used. I found https://github.com/jmillikin/rules_bison, but those print a lot of warnings (things like -Wsign-compare IIRC) which makes builds hard to read. Plus I think the underlying bison_cc_library rule didn't work, so this would really only get a hermetic bison/flex build (helpful, but didn't seem worth more time).
    - I'm adding in a .bazeliskrc to push a somewhat more standard choice of bazel versions. I noticed I was getting unstable versions by default, possible Google-specific, but seemed good to include.
    - The `-lpthread` kludge.
- Turn all of the examples into golden tests.
    - Including adding a golden test rule.
- Fixed various style guide issues. For example:
    - Fixing function names to be CamelCase instead of snake_case (https://google.github.io/styleguide/cppguide.html#Function_Names)
    - Removed exception use (https://google.github.io/styleguide/cppguide.html#Exceptions)
    - File name fixes (https://github.com/carbon-language/carbon-lang/blob/trunk/docs/project/cpp_style_guide.md#file-names)
- Dropped `using` of `std` names -- I believe this is preferred (maybe we should be explicit about this in the Carbon style guide)
- Switched `enum` uses to `enum class` for ease-of-identification.
- Spent some time breaking out files to hopefully be easier to read/edit pieces, and understand relations between structs.
- Added `code requires` to `syntax.ypp` to address include issues

Possibly other things -- but the fundamental structure is, I believe, unchanged. I put in the golden tests pretty early to ensure I wasn't mutating output/results.
Jon Meow 5 år sedan
förälder
incheckning
6e5070de18
97 ändrade filer med 11896 tillägg och 1 borttagningar
  1. 5 0
      .bazeliskrc
  2. 18 1
      .pre-commit-config.yaml
  3. 2 0
      bazel/cc_toolchains/clang_cc_toolchain_config.bzl
  4. 5 0
      bazel/testing/BUILD
  5. 25 0
      bazel/testing/golden_test.bzl
  6. 36 0
      bazel/testing/golden_test.sh
  7. 19 0
      docs/project/contribution_tools.md
  8. 107 0
      executable_semantics/BUILD
  9. 133 0
      executable_semantics/README.md
  10. 61 0
      executable_semantics/ast/BUILD
  11. 64 0
      executable_semantics/ast/declaration.cpp
  12. 47 0
      executable_semantics/ast/declaration.h
  13. 284 0
      executable_semantics/ast/expression.cpp
  14. 106 0
      executable_semantics/ast/expression.h
  15. 49 0
      executable_semantics/ast/expression_or_field_list.cpp
  16. 32 0
      executable_semantics/ast/expression_or_field_list.h
  17. 39 0
      executable_semantics/ast/function_definition.cpp
  18. 29 0
      executable_semantics/ast/function_definition.h
  19. 30 0
      executable_semantics/ast/member.cpp
  20. 33 0
      executable_semantics/ast/member.h
  21. 190 0
      executable_semantics/ast/statement.cpp
  22. 84 0
      executable_semantics/ast/statement.h
  23. 23 0
      executable_semantics/ast/struct_definition.h
  24. 33 0
      executable_semantics/interpreter/BUILD
  25. 108 0
      executable_semantics/interpreter/action.cpp
  26. 50 0
      executable_semantics/interpreter/action.h
  27. 38 0
      executable_semantics/interpreter/assoc_list.h
  28. 39 0
      executable_semantics/interpreter/cons_list.h
  29. 1350 0
      executable_semantics/interpreter/interpreter.cpp
  30. 60 0
      executable_semantics/interpreter/interpreter.h
  31. 680 0
      executable_semantics/interpreter/typecheck.cpp
  32. 56 0
      executable_semantics/interpreter/typecheck.h
  33. 402 0
      executable_semantics/interpreter/value.cpp
  34. 139 0
      executable_semantics/interpreter/value.h
  35. 27 0
      executable_semantics/main.cpp
  36. 90 0
      executable_semantics/syntax.lpp
  37. 314 0
      executable_semantics/syntax.ypp
  38. 45 0
      executable_semantics/syntax_helpers.cpp
  39. 29 0
      executable_semantics/syntax_helpers.h
  40. 11 0
      executable_semantics/testdata/block1.6c
  41. 265 0
      executable_semantics/testdata/block1.golden
  42. 14 0
      executable_semantics/testdata/break1.6c
  43. 821 0
      executable_semantics/testdata/break1.golden
  44. 32 0
      executable_semantics/testdata/choice1.6c
  45. 43 0
      executable_semantics/testdata/choice1.golden
  46. 13 0
      executable_semantics/testdata/continue1.6c
  47. 616 0
      executable_semantics/testdata/continue1.golden
  48. 11 0
      executable_semantics/testdata/fun1.6c
  49. 19 0
      executable_semantics/testdata/fun1.golden
  50. 18 0
      executable_semantics/testdata/fun2.6c
  51. 25 0
      executable_semantics/testdata/fun2.golden
  52. 12 0
      executable_semantics/testdata/fun3.6c
  53. 211 0
      executable_semantics/testdata/fun3.golden
  54. 11 0
      executable_semantics/testdata/fun4.6c
  55. 148 0
      executable_semantics/testdata/fun4.golden
  56. 9 0
      executable_semantics/testdata/fun5.6c
  57. 214 0
      executable_semantics/testdata/fun5.golden
  58. 11 0
      executable_semantics/testdata/fun6_fail_type.6c
  59. 27 0
      executable_semantics/testdata/fun6_fail_type.golden
  60. 14 0
      executable_semantics/testdata/fun_recur.6c
  61. 21 0
      executable_semantics/testdata/fun_recur.golden
  62. 12 0
      executable_semantics/testdata/funptr1.6c
  63. 25 0
      executable_semantics/testdata/funptr1.golden
  64. 13 0
      executable_semantics/testdata/match_int.6c
  65. 175 0
      executable_semantics/testdata/match_int.golden
  66. 15 0
      executable_semantics/testdata/match_int_default.6c
  67. 217 0
      executable_semantics/testdata/match_int_default.golden
  68. 21 0
      executable_semantics/testdata/match_type.6c
  69. 653 0
      executable_semantics/testdata/match_type.golden
  70. 9 0
      executable_semantics/testdata/next.6c
  71. 124 0
      executable_semantics/testdata/next.golden
  72. 8 0
      executable_semantics/testdata/pattern_init.6c
  73. 235 0
      executable_semantics/testdata/pattern_init.golden
  74. 9 0
      executable_semantics/testdata/record1.6c
  75. 298 0
      executable_semantics/testdata/record1.golden
  76. 13 0
      executable_semantics/testdata/struct1.6c
  77. 256 0
      executable_semantics/testdata/struct1.golden
  78. 15 0
      executable_semantics/testdata/struct2.6c
  79. 322 0
      executable_semantics/testdata/struct2.golden
  80. 12 0
      executable_semantics/testdata/struct3.6c
  81. 186 0
      executable_semantics/testdata/struct3.golden
  82. 10 0
      executable_semantics/testdata/tuple1.6c
  83. 389 0
      executable_semantics/testdata/tuple1.golden
  84. 8 0
      executable_semantics/testdata/tuple2.6c
  85. 199 0
      executable_semantics/testdata/tuple2.golden
  86. 10 0
      executable_semantics/testdata/tuple_assign.6c
  87. 298 0
      executable_semantics/testdata/tuple_assign.golden
  88. 11 0
      executable_semantics/testdata/tuple_match.6c
  89. 318 0
      executable_semantics/testdata/tuple_match.golden
  90. 18 0
      executable_semantics/testdata/undef1.6c
  91. 1 0
      executable_semantics/testdata/undef1.golden
  92. 13 0
      executable_semantics/testdata/undef2.6c
  93. 3 0
      executable_semantics/testdata/undef2.golden
  94. 10 0
      executable_semantics/testdata/while1.6c
  95. 464 0
      executable_semantics/testdata/while1.golden
  96. 7 0
      executable_semantics/testdata/zero.6c
  97. 72 0
      executable_semantics/testdata/zero.golden

+ 5 - 0
.bazeliskrc

@@ -0,0 +1,5 @@
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+USE_BAZEL_VERSION=latest

+ 18 - 1
.pre-commit-config.yaml

@@ -24,6 +24,8 @@ repos:
       - id: mixed-line-ending
         args: ['--fix=lf']
       - id: trailing-whitespace
+        exclude: '^(.*/testdata/.*\.golden)$'
+
   - repo: https://github.com/google/pre-commit-tool-hooks
     rev: 1d04a2848ac54d64bd6474ccec69aac45fa88414 # frozen: v1.1.1
     hooks:
@@ -34,7 +36,22 @@ repos:
             Part of the Carbon Language project, under the Apache License v2.0 with LLVM
             Exceptions. See /LICENSE for license information.
             SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-        exclude: '^(website/(firebase/.firebaserc|jekyll/(Gemfile.lock|theme/.*))|.bazelversion|compile_flags.txt|.*\.def)$'
+          - --custom_format
+          - '\.6c$'
+          - ''
+          - '// '
+          - ''
+          - --custom_format
+          - '\.lpp$'
+          - '/*'
+          - ''
+          - '*/'
+          - --custom_format
+          - '\.ypp$'
+          - ''
+          - '// '
+          - ''
+        exclude: '^(website/(firebase/.firebaserc|jekyll/(Gemfile.lock|theme/.*))|.bazelversion|compile_flags.txt|.*\.def|.*/testdata/.*\.golden)$'
       - id: check-google-doc-style
       - id: markdown-toc
   - repo: https://github.com/codespell-project/codespell

+ 2 - 0
bazel/cc_toolchains/clang_cc_toolchain_config.bzl

@@ -352,6 +352,8 @@ def _impl(ctx):
                             # paths. Those might have a system installed libc++
                             # and we want to find the one next to our Clang.
                             "-L" + llvm_bindir + "/../lib",
+                            # Link with pthread.
+                            "-lpthread",
                         ],
                     ),
                 ]),

+ 5 - 0
bazel/testing/BUILD

@@ -0,0 +1,5 @@
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+exports_files(["golden_test.sh"])

+ 25 - 0
bazel/testing/golden_test.bzl

@@ -0,0 +1,25 @@
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+"""Rule for a golden test."""
+
+def golden_test(name, golden, subject, **kwargs):
+    """Compares two files. Passes if they are identical.
+
+    Args:
+      name: Name of the build rule.
+      subject: The generated file to be compared.
+      golden: The golden file to be compared.
+      **kwargs: Any additional parameters for the generated sh_test.
+    """
+    native.sh_test(
+        name = name,
+        srcs = ["//bazel/testing:golden_test.sh"],
+        args = [
+            "$(location %s)" % golden,
+            "$(location %s)" % subject,
+        ],
+        data = [golden, subject],
+        **kwargs
+    )

+ 36 - 0
bazel/testing/golden_test.sh

@@ -0,0 +1,36 @@
+#!/bin/bash
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+set -e -u -o pipefail
+
+GOLDEN=$1
+SUBJECT=$2
+
+if [[ $# == 3 && $3 == "--update" ]]; then
+  cp "${SUBJECT}" "${GOLDEN}"
+  exit $?
+fi
+
+CMD=("diff" "-u" "${GOLDEN}" "${SUBJECT}")
+
+if "${CMD[@]}"; then
+  echo "PASS"
+  exit 0
+fi
+
+cat <<EOT
+When running under:
+  ${TEST_SRCDIR}
+the golden contents of:
+  ${GOLDEN}
+do not match generated target:
+  ${SUBJECT}
+
+To update the golden file, run the following:
+
+  bazel run ${TEST_TARGET} -- --update
+EOT
+
+exit 1

+ 19 - 0
docs/project/contribution_tools.md

@@ -23,6 +23,7 @@ contributions.
         -   [Cargo (optional)](#cargo-optional)
 -   [Main tools](#main-tools)
     -   [Bazel and Bazelisk](#bazel-and-bazelisk)
+    -   [Bison and Flex](#bison-and-flex)
     -   [buildifier](#buildifier)
     -   [Clang and LLVM](#clang-and-llvm)
     -   [Ninja](#ninja)
@@ -151,6 +152,24 @@ Our recommended way of installing is:
 brew install bazelisk
 ```
 
+### Bison and Flex
+
+[Bison](https://www.gnu.org/software/bison/) and
+[Flex](https://github.com/westes/flex) are used by executable semantics.
+Although we may
+[switch to a hemertic toolchain later](https://github.com/carbon-language/carbon-lang/issues/266),
+an install is currently required.
+
+Our recommended way of installing is:
+
+```bash
+brew install bison flex
+```
+
+On MacOS, it will be necessary to explicitly add the installed paths to the
+`PATH` environment variable so that the brew-installed versions are used instead
+of Xcode-installed versions. Read `brew` output for instructions.
+
 ### buildifier
 
 [Buildifier](https://github.com/bazelbuild/buildtools/tree/master/buildifier) is

+ 107 - 0
executable_semantics/BUILD

@@ -0,0 +1,107 @@
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# TODO(https://github.com/carbon-language/carbon-lang/issues/266):
+# Migrate bison/flex usage to a more hermetic bazel build.
+
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+load("//bazel/testing:golden_test.bzl", "golden_test")
+
+cc_binary(
+    name = "executable_semantics",
+    srcs = ["main.cpp"],
+    deps = [":syntax"],
+)
+
+cc_library(
+    name = "syntax",
+    srcs = [
+        "syntax.tab.cpp",
+        "syntax.yy.cpp",
+        "syntax_helpers.cpp",
+        "syntax_helpers.h",
+    ],
+    hdrs = ["syntax.tab.h"],
+    # Disable warnings for generated code.
+    copts = [
+        "-Wno-unneeded-internal-declaration",
+        "-Wno-unused-function",
+        "-Wno-writable-strings",
+    ],
+    deps = [
+        "//executable_semantics/ast:declaration",
+        "//executable_semantics/ast:expression",
+        "//executable_semantics/ast:expression_or_field_list",
+        "//executable_semantics/interpreter",
+    ],
+)
+
+genrule(
+    name = "syntax_bison_srcs",
+    srcs = ["syntax.ypp"],
+    outs = [
+        "syntax.tab.cpp",
+        "syntax.tab.h",
+    ],
+    cmd = "bison " +
+          "--output=$(location syntax.tab.cpp) " +
+          "--defines=$(location syntax.tab.h) " +
+          "$(location syntax.ypp)",
+)
+
+genrule(
+    name = "syntax_flex_srcs",
+    srcs = ["syntax.lpp"],
+    outs = ["syntax.yy.cpp"],
+    cmd = "flex " +
+          "--outfile=$(location syntax.yy.cpp) " +
+          "$(location syntax.lpp)",
+)
+
+EXAMPLES = [
+    "block1",
+    "break1",
+    "choice1",
+    "continue1",
+    "fun_recur",
+    "fun1",
+    "fun2",
+    "fun3",
+    "fun4",
+    "fun5",
+    "fun6_fail_type",
+    "funptr1",
+    "match_int_default",
+    "match_int",
+    "match_type",
+    "next",
+    "pattern_init",
+    "record1",
+    "struct1",
+    "struct2",
+    "struct3",
+    "tuple_assign",
+    "tuple_match",
+    "tuple1",
+    "tuple2",
+    "undef1",
+    "undef2",
+    "while1",
+    "zero",
+]
+
+[genrule(
+    name = "%s_out" % e,
+    srcs = ["testdata/%s.6c" % e],
+    outs = ["testdata/%s.out" % e],
+    # Suppress command errors.
+    cmd = "$(location executable_semantics) $< > $@ 2>&1 || true",
+    tools = [":executable_semantics"],
+) for e in EXAMPLES]
+
+[golden_test(
+    name = "%s_test" % e,
+    golden = "testdata/%s.golden" % e,
+    subject = "testdata/%s.out" % e,
+) for e in EXAMPLES]

+ 133 - 0
executable_semantics/README.md

@@ -0,0 +1,133 @@
+# Executable Semantics
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+This directory contains a work-in-progress executable semantics. It started as
+an executable semantics for Featherweight C and it is migrating into an
+executable semantics for the Carbon language. It includes a parser, type
+checker, and abstract machine.
+
+This language currently includes several kinds of values: integer, booleans,
+functions, and structs. A kind of safe union, called a `choice`, is in progress.
+Regarding control-flow, it includes if statements, while loops, break, continue,
+function calls, and a variant of `switch` called `match` is in progress.
+
+The grammar of the language matches the one in Proposal
+[#162](https://github.com/carbon-language/carbon-lang/pull/162). The type
+checker and abstract machine do not yet have a corresponding proposal.
+Nevertheless they are present here to help test the parser but should not be
+considered definitive.
+
+The parser is implemented using the flex and bison parser generator tools.
+
+-   [`syntax.lpp`](syntax/syntax.lpp) the lexer specification
+-   [`syntax.ypp`](syntax/syntax.ypp) the grammar
+
+The parser translates program text into an abstract syntax tree (AST), defined
+in the [ast](ast/) subdirectory.
+
+The [type checker](interpreter/typecheck.h) defines what it means for an AST to
+be a valid program. The type checker prints an error and exits if the AST is
+invalid.
+
+The parser and type checker together specify the static (compile-time)
+semantics.
+
+The dynamic (run-time) semantics is specified by an abstract machine. Abstract
+machines have several positive characteristics that make them good for
+specification:
+
+-   abstract machines operate on the AST of the program (and not some
+    lower-level representation such as bytecode) so they directly connect the
+    program to its behavior
+
+-   abstract machines can easily handle language features with complex
+    control-flow, such as goto, exceptions, coroutines, and even first-class
+    continuations.
+
+The one down-side of abstract machines is that they are not as simple as a
+definitional interpreter (a recursive function that interprets the program), but
+it is more difficult to handle complex control flow in a definitional
+interpreter.
+
+[InterpProgram()](interpreter/interpreter.h) runs an abstract machine using the
+[interpreter](interpreter/), as described below.
+
+The abstract machine implements a state-transition system. The state is defined
+by the `State` structure, which includes three components: the procedure call
+stack, the heap, and the function definitions. The `Step` function updates the
+state by executing a little bit of the program. The `Step` function is called
+repeatedly to execute the entire program.
+
+An implementation of the language (such as a compiler) must be observationally
+equivalent to this abstract machine. The notion of observation is different for
+each language, and can include things like input and output. This language is
+currently so simple that the only thing that is observable is the final result,
+an integer. So an implementation must produce the same final result as the one
+produces by the abstract machine. In particular, an implementation does **not**
+have to mimic each step of the abstract machine and does not have to use the
+same kinds of data structures to store the state of the program.
+
+A procedure call frame, defined by the `Frame` structure, includes a pointer to
+the function being called, the environment that maps variables to their
+addresses, and a to-do list of actions. Each action corresponds to an expression
+or statement in the program. The `Action` structure represents an action. An
+action often spawns other actions that needs to be completed first and
+afterwards uses their results to complete its action. To keep track of this
+process, each action includes a position field `pos` that stores an integer that
+starts at `-1` and increments as the action makes progress. For example, suppose
+the action associated with an addition expression `e1 + e2` is at the top of the
+to-do list:
+
+    (e1 + e2) [-1] :: ...
+
+When this action kicks off (in the `StepExp` function), it increments `pos` to
+`0` and pushes `e1` onto the to-do list, so the top of the todo list now looks
+like:
+
+    e1 [-1] :: (e1 + e2) [0] :: ...
+
+Skipping over the processing of `e1`, it eventually turns into an integer value
+`n1`:
+
+    n1 :: (e1 + e2) [0]
+
+Because there is a value at the top of the to-do list, the `Step` function
+invokes `HandleValue` which then dispatches on the next action on the to-do
+list, in this case the addition. The addition action spawns an action for
+subexpression `e2`, increments `pos` to `1`, and remembers `n1`.
+
+    e2 [-1] :: (e1 + e2) [1](n1) :: ...
+
+Skipping over the processing of `e2`, it eventually turns into an integer value
+`n2`:
+
+    n2 :: (e1 + e2) [1](n1) :: ...
+
+Again the `Step` function invokes `HandleValue` and dispatches to the addition
+action which performs the arithmetic and pushes the result on the to-do list.
+Let `n3` be the sum of `n1` and `n2`.
+
+    n3 :: ...
+
+The heap is an array of values. It is used not only for `malloc` but also to
+store anything that is mutable, including function parameters and local
+variables. A pointer is simply an index into the array. The `malloc` expression
+causes the heap to grow (at the end) and returns the index of the last slot. The
+dereference expression returns the nth value of the heap, as specified by the
+dereferenced pointer. The assignment operation stores the value of the
+right-hand side into the heap at the index specified by the left-hand side
+lvalue.
+
+As you might expect, function calls push a new frame on the stack and the
+`return` statement pops a frame off the stack. The parameter passing semantics
+is call-by-value, so the machine applies `CopyVal` to the incoming arguments and
+the outgoing return value. Also, the machine is careful to kill the parameters
+and local variables when the function call is complete.
+
+The [`testdata/`](testdata/) subdirectory includes some example programs with
+golden output.

+ 61 - 0
executable_semantics/ast/BUILD

@@ -0,0 +1,61 @@
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+load("@rules_cc//cc:defs.bzl", "cc_library")
+
+package(default_visibility = ["//executable_semantics:__subpackages__"])
+
+cc_library(
+    name = "declaration",
+    srcs = ["declaration.cpp"],
+    hdrs = ["declaration.h"],
+    deps = [
+        ":function_definition",
+        ":member",
+        ":struct_definition",
+    ],
+)
+
+cc_library(
+    name = "expression",
+    srcs = ["expression.cpp"],
+    hdrs = ["expression.h"],
+)
+
+cc_library(
+    name = "expression_or_field_list",
+    srcs = ["expression_or_field_list.cpp"],
+    hdrs = ["expression_or_field_list.h"],
+    deps = [":expression"],
+)
+
+cc_library(
+    name = "function_definition",
+    srcs = ["function_definition.cpp"],
+    hdrs = ["function_definition.h"],
+    deps = [
+        ":expression",
+        ":statement",
+    ],
+)
+
+cc_library(
+    name = "member",
+    srcs = ["member.cpp"],
+    hdrs = ["member.h"],
+    deps = [":expression"],
+)
+
+cc_library(
+    name = "statement",
+    srcs = ["statement.cpp"],
+    hdrs = ["statement.h"],
+    deps = [":expression"],
+)
+
+cc_library(
+    name = "struct_definition",
+    hdrs = ["struct_definition.h"],
+    deps = [":member"],
+)

+ 64 - 0
executable_semantics/ast/declaration.cpp

@@ -0,0 +1,64 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/ast/declaration.h"
+
+#include <iostream>
+
+namespace Carbon {
+
+auto MakeFunDecl(FunctionDefinition* f) -> Declaration* {
+  auto* d = new Declaration();
+  d->tag = DeclarationKind::FunctionDeclaration;
+  d->u.fun_def = f;
+  return d;
+}
+
+auto MakeStructDecl(int line_num, std::string name, std::list<Member*>* members)
+    -> Declaration* {
+  auto* d = new Declaration();
+  d->tag = DeclarationKind::StructDeclaration;
+  d->u.struct_def = new StructDefinition();
+  d->u.struct_def->line_num = line_num;
+  d->u.struct_def->name = new std::string(std::move(name));
+  d->u.struct_def->members = members;
+  return d;
+}
+
+auto MakeChoiceDecl(int line_num, std::string name,
+                    std::list<std::pair<std::string, Expression*>>* alts)
+    -> Declaration* {
+  auto* d = new Declaration();
+  d->tag = DeclarationKind::ChoiceDeclaration;
+  d->u.choice_def.line_num = line_num;
+  d->u.choice_def.name = new std::string(std::move(name));
+  d->u.choice_def.alternatives = alts;
+  return d;
+}
+
+void PrintDecl(Declaration* d) {
+  switch (d->tag) {
+    case DeclarationKind::FunctionDeclaration:
+      PrintFunDef(d->u.fun_def);
+      break;
+    case DeclarationKind::StructDeclaration:
+      std::cout << "struct " << *d->u.struct_def->name << " {" << std::endl;
+      for (auto& member : *d->u.struct_def->members) {
+        PrintMember(member);
+      }
+      std::cout << "}" << std::endl;
+      break;
+    case DeclarationKind::ChoiceDeclaration:
+      std::cout << "choice " << *d->u.choice_def.name << " {" << std::endl;
+      for (auto& alternative : *d->u.choice_def.alternatives) {
+        std::cout << "alt " << alternative.first << " ";
+        PrintExp(alternative.second);
+        std::cout << ";" << std::endl;
+      }
+      std::cout << "}" << std::endl;
+      break;
+  }
+}
+
+}  // namespace Carbon

+ 47 - 0
executable_semantics/ast/declaration.h

@@ -0,0 +1,47 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_DECLARATION_H_
+#define EXECUTABLE_SEMANTICS_AST_DECLARATION_H_
+
+#include <list>
+#include <string>
+
+#include "executable_semantics/ast/function_definition.h"
+#include "executable_semantics/ast/member.h"
+#include "executable_semantics/ast/struct_definition.h"
+
+namespace Carbon {
+
+enum class DeclarationKind {
+  FunctionDeclaration,
+  StructDeclaration,
+  ChoiceDeclaration
+};
+
+struct Declaration {
+  DeclarationKind tag;
+  union {
+    struct FunctionDefinition* fun_def;
+    struct StructDefinition* struct_def;
+    struct {
+      int line_num;
+      std::string* name;
+      std::list<std::pair<std::string, Expression*>>* alternatives;
+    } choice_def;
+  } u;
+};
+
+auto MakeFunDecl(struct FunctionDefinition* f) -> Declaration*;
+auto MakeStructDecl(int line_num, std::string name, std::list<Member*>* members)
+    -> Declaration*;
+auto MakeChoiceDecl(int line_num, std::string name,
+                    std::list<std::pair<std::string, Expression*>>* alts)
+    -> Declaration*;
+
+void PrintDecl(Declaration* d);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_DECLARATION_H_

+ 284 - 0
executable_semantics/ast/expression.cpp

@@ -0,0 +1,284 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/ast/expression.h"
+
+#include <iostream>
+
+namespace Carbon {
+
+auto MakeTypeType(int line_num) -> Expression* {
+  auto* t = new Expression();
+  t->tag = ExpressionKind::TypeT;
+  t->line_num = line_num;
+  return t;
+}
+
+auto MakeIntType(int line_num) -> Expression* {
+  auto* t = new Expression();
+  t->tag = ExpressionKind::IntT;
+  t->line_num = line_num;
+  return t;
+}
+
+auto MakeBoolType(int line_num) -> Expression* {
+  auto* t = new Expression();
+  t->tag = ExpressionKind::BoolT;
+  t->line_num = line_num;
+  return t;
+}
+
+auto MakeAutoType(int line_num) -> Expression* {
+  auto* t = new Expression();
+  t->tag = ExpressionKind::AutoT;
+  t->line_num = line_num;
+  return t;
+}
+
+auto MakeFunType(int line_num, Expression* param, Expression* ret)
+    -> Expression* {
+  auto* t = new Expression();
+  t->tag = ExpressionKind::FunctionT;
+  t->line_num = line_num;
+  t->u.function_type.parameter = param;
+  t->u.function_type.return_type = ret;
+  return t;
+}
+
+auto MakeVar(int line_num, std::string var) -> Expression* {
+  auto* v = new Expression();
+  v->line_num = line_num;
+  v->tag = ExpressionKind::Variable;
+  v->u.variable.name = new std::string(std::move(var));
+  return v;
+}
+
+auto MakeVarPat(int line_num, std::string var, Expression* type)
+    -> Expression* {
+  auto* v = new Expression();
+  v->line_num = line_num;
+  v->tag = ExpressionKind::PatternVariable;
+  v->u.pattern_variable.name = new std::string(std::move(var));
+  v->u.pattern_variable.type = type;
+  return v;
+}
+
+auto MakeInt(int line_num, int i) -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::Integer;
+  e->u.integer = i;
+  return e;
+}
+
+auto MakeBool(int line_num, bool b) -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::Boolean;
+  e->u.boolean = b;
+  return e;
+}
+
+auto MakeOp(int line_num, enum Operator op, std::vector<Expression*>* args)
+    -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::PrimitiveOp;
+  e->u.primitive_op.op = op;
+  e->u.primitive_op.arguments = args;
+  return e;
+}
+
+auto MakeUnOp(int line_num, enum Operator op, Expression* arg) -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::PrimitiveOp;
+  e->u.primitive_op.op = op;
+  auto* args = new std::vector<Expression*>();
+  args->push_back(arg);
+  e->u.primitive_op.arguments = args;
+  return e;
+}
+
+auto MakeBinOp(int line_num, enum Operator op, Expression* arg1,
+               Expression* arg2) -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::PrimitiveOp;
+  e->u.primitive_op.op = op;
+  auto* args = new std::vector<Expression*>();
+  args->push_back(arg1);
+  args->push_back(arg2);
+  e->u.primitive_op.arguments = args;
+  return e;
+}
+
+auto MakeCall(int line_num, Expression* fun, Expression* arg) -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::Call;
+  e->u.call.function = fun;
+  e->u.call.argument = arg;
+  return e;
+}
+
+auto MakeGetField(int line_num, Expression* exp, std::string field)
+    -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::GetField;
+  e->u.get_field.aggregate = exp;
+  e->u.get_field.field = new std::string(std::move(field));
+  return e;
+}
+
+auto MakeTuple(int line_num,
+               std::vector<std::pair<std::string, Expression*>>* args)
+    -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::Tuple;
+  int i = 0;
+  for (auto& arg : *args) {
+    if (arg.first == "") {
+      arg.first = std::to_string(i);
+      ++i;
+    }
+  }
+  e->u.tuple.fields = args;
+  return e;
+}
+
+auto MakeIndex(int line_num, Expression* exp, Expression* i) -> Expression* {
+  auto* e = new Expression();
+  e->line_num = line_num;
+  e->tag = ExpressionKind::Index;
+  e->u.index.aggregate = exp;
+  e->u.index.offset = i;
+  return e;
+}
+
+static void PrintOp(Operator op) {
+  switch (op) {
+    case Operator::Neg:
+      std::cout << "-";
+      break;
+    case Operator::Add:
+      std::cout << "+";
+      break;
+    case Operator::Sub:
+      std::cout << "-";
+      break;
+    case Operator::Not:
+      std::cout << "!";
+      break;
+    case Operator::And:
+      std::cout << "&&";
+      break;
+    case Operator::Or:
+      std::cout << "||";
+      break;
+    case Operator::Eq:
+      std::cout << "==";
+      break;
+  }
+}
+
+static void PrintFields(
+    std::vector<std::pair<std::string, Expression*>>* fields) {
+  int i = 0;
+  for (auto iter = fields->begin(); iter != fields->end(); ++iter, ++i) {
+    if (i != 0) {
+      std::cout << ", ";
+    }
+    std::cout << iter->first << " = ";
+    PrintExp(iter->second);
+  }
+}
+
+void PrintExp(Expression* e) {
+  switch (e->tag) {
+    case ExpressionKind::Index:
+      PrintExp(e->u.index.aggregate);
+      std::cout << "[";
+      PrintExp(e->u.index.offset);
+      std::cout << "]";
+      break;
+    case ExpressionKind::GetField:
+      PrintExp(e->u.get_field.aggregate);
+      std::cout << ".";
+      std::cout << *e->u.get_field.field;
+      break;
+    case ExpressionKind::Tuple:
+      std::cout << "(";
+      PrintFields(e->u.tuple.fields);
+      std::cout << ")";
+      break;
+    case ExpressionKind::Integer:
+      std::cout << e->u.integer;
+      break;
+    case ExpressionKind::Boolean:
+      std::cout << std::boolalpha;
+      std::cout << e->u.boolean;
+      break;
+    case ExpressionKind::PrimitiveOp:
+      std::cout << "(";
+      if (e->u.primitive_op.arguments->size() == 0) {
+        PrintOp(e->u.primitive_op.op);
+      } else if (e->u.primitive_op.arguments->size() == 1) {
+        PrintOp(e->u.primitive_op.op);
+        std::cout << " ";
+        auto iter = e->u.primitive_op.arguments->begin();
+        PrintExp(*iter);
+      } else if (e->u.primitive_op.arguments->size() == 2) {
+        auto iter = e->u.primitive_op.arguments->begin();
+        PrintExp(*iter);
+        std::cout << " ";
+        PrintOp(e->u.primitive_op.op);
+        std::cout << " ";
+        ++iter;
+        PrintExp(*iter);
+      }
+      std::cout << ")";
+      break;
+    case ExpressionKind::Variable:
+      std::cout << *e->u.variable.name;
+      break;
+    case ExpressionKind::PatternVariable:
+      PrintExp(e->u.pattern_variable.type);
+      std::cout << ": ";
+      std::cout << *e->u.pattern_variable.name;
+      break;
+    case ExpressionKind::Call:
+      PrintExp(e->u.call.function);
+      if (e->u.call.argument->tag == ExpressionKind::Tuple) {
+        PrintExp(e->u.call.argument);
+      } else {
+        std::cout << "(";
+        PrintExp(e->u.call.argument);
+        std::cout << ")";
+      }
+      break;
+    case ExpressionKind::BoolT:
+      std::cout << "Bool";
+      break;
+    case ExpressionKind::IntT:
+      std::cout << "Int";
+      break;
+    case ExpressionKind::TypeT:
+      std::cout << "Type";
+      break;
+    case ExpressionKind::AutoT:
+      std::cout << "auto";
+      break;
+    case ExpressionKind::FunctionT:
+      std::cout << "fn ";
+      PrintExp(e->u.function_type.parameter);
+      std::cout << " -> ";
+      PrintExp(e->u.function_type.return_type);
+      break;
+  }
+}
+
+}  // namespace Carbon

+ 106 - 0
executable_semantics/ast/expression.h

@@ -0,0 +1,106 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_
+#define EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_
+
+#include <string>
+#include <vector>
+
+namespace Carbon {
+
+enum class ExpressionKind {
+  AutoT,
+  BoolT,
+  Boolean,
+  Call,
+  FunctionT,
+  GetField,
+  Index,
+  IntT,
+  Integer,
+  PatternVariable,
+  PrimitiveOp,
+  Tuple,
+  TypeT,
+  Variable,
+};
+enum class Operator {
+  Add,
+  And,
+  Eq,
+  Neg,
+  Not,
+  Or,
+  Sub,
+};
+
+struct Expression {
+  int line_num;
+  ExpressionKind tag;
+  union {
+    struct {
+      std::string* name;
+    } variable;
+    struct {
+      Expression* aggregate;
+      std::string* field;
+    } get_field;
+    struct {
+      Expression* aggregate;
+      Expression* offset;
+    } index;
+    struct {
+      std::string* name;
+      Expression* type;
+    } pattern_variable;
+    int integer;
+    bool boolean;
+    struct {
+      std::vector<std::pair<std::string, Expression*>>* fields;
+    } tuple;
+    struct {
+      Operator op;
+      std::vector<Expression*>* arguments;
+    } primitive_op;
+    struct {
+      Expression* function;
+      Expression* argument;
+    } call;
+    struct {
+      Expression* parameter;
+      Expression* return_type;
+    } function_type;
+  } u;
+};
+
+auto MakeVar(int line_num, std::string var) -> Expression*;
+auto MakeVarPat(int line_num, std::string var, Expression* type) -> Expression*;
+auto MakeInt(int line_num, int i) -> Expression*;
+auto MakeBool(int line_num, bool b) -> Expression*;
+auto MakeOp(int line_num, Operator op, std::vector<Expression*>* args)
+    -> Expression*;
+auto MakeUnOp(int line_num, enum Operator op, Expression* arg) -> Expression*;
+auto MakeBinOp(int line_num, enum Operator op, Expression* arg1,
+               Expression* arg2) -> Expression*;
+auto MakeCall(int line_num, Expression* fun, Expression* arg) -> Expression*;
+auto MakeGetField(int line_num, Expression* exp, std::string field)
+    -> Expression*;
+auto MakeTuple(int line_num,
+               std::vector<std::pair<std::string, Expression*>>* args)
+    -> Expression*;
+auto MakeIndex(int line_num, Expression* exp, Expression* i) -> Expression*;
+
+auto MakeTypeType(int line_num) -> Expression*;
+auto MakeIntType(int line_num) -> Expression*;
+auto MakeBoolType(int line_num) -> Expression*;
+auto MakeFunType(int line_num, Expression* param, Expression* ret)
+    -> Expression*;
+auto MakeAutoType(int line_num) -> Expression*;
+
+void PrintExp(Expression* exp);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_

+ 49 - 0
executable_semantics/ast/expression_or_field_list.cpp

@@ -0,0 +1,49 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/ast/expression_or_field_list.h"
+
+namespace Carbon {
+
+auto MakeExp(Expression* exp) -> ExpOrFieldList* {
+  auto e = new ExpOrFieldList();
+  e->tag = ExpOrFieldListKind::Exp;
+  e->u.exp = exp;
+  return e;
+}
+
+auto MakeFieldList(std::list<std::pair<std::string, Expression*>>* fields)
+    -> ExpOrFieldList* {
+  auto e = new ExpOrFieldList();
+  e->tag = ExpOrFieldListKind::FieldList;
+  e->u.fields = fields;
+  return e;
+}
+
+auto MakeConsField(ExpOrFieldList* e1, ExpOrFieldList* e2) -> ExpOrFieldList* {
+  auto fields = new std::list<std::pair<std::string, Expression*>>();
+  switch (e1->tag) {
+    case ExpOrFieldListKind::Exp:
+      fields->push_back(std::make_pair("", e1->u.exp));
+      break;
+    case ExpOrFieldListKind::FieldList:
+      for (auto& field : *e1->u.fields) {
+        fields->push_back(field);
+      }
+      break;
+  }
+  switch (e2->tag) {
+    case ExpOrFieldListKind::Exp:
+      fields->push_back(std::make_pair("", e2->u.exp));
+      break;
+    case ExpOrFieldListKind::FieldList:
+      for (auto& field : *e2->u.fields) {
+        fields->push_back(field);
+      }
+      break;
+  }
+  return MakeFieldList(fields);
+}
+
+}  // namespace Carbon

+ 32 - 0
executable_semantics/ast/expression_or_field_list.h

@@ -0,0 +1,32 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_EXPRESSION_OR_FIELD_LIST_H_
+#define EXECUTABLE_SEMANTICS_AST_EXPRESSION_OR_FIELD_LIST_H_
+
+#include <list>
+
+#include "executable_semantics/ast/expression.h"
+
+namespace Carbon {
+
+enum class ExpOrFieldListKind { Exp, FieldList };
+
+// This is used in the parsing of tuples and parenthesized expressions.
+struct ExpOrFieldList {
+  ExpOrFieldListKind tag;
+  union {
+    Expression* exp;
+    std::list<std::pair<std::string, Expression*>>* fields;
+  } u;
+};
+
+auto MakeExp(Expression* exp) -> ExpOrFieldList*;
+auto MakeFieldList(std::list<std::pair<std::string, Expression*>>* fields)
+    -> ExpOrFieldList*;
+auto MakeConsField(ExpOrFieldList* e1, ExpOrFieldList* e2) -> ExpOrFieldList*;
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_EXPRESSION_OR_FIELD_LIST_H_

+ 39 - 0
executable_semantics/ast/function_definition.cpp

@@ -0,0 +1,39 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/ast/function_definition.h"
+
+#include <iostream>
+
+namespace Carbon {
+
+auto MakeFunDef(int line_num, std::string name, Expression* ret_type,
+                Expression* param_pattern, Statement* body)
+    -> struct FunctionDefinition* {
+  auto* f = new struct FunctionDefinition();
+  f->line_num = line_num;
+  f->name = std::move(name);
+  f->return_type = ret_type;
+  f->param_pattern = param_pattern;
+  f->body = body;
+  return f;
+}
+
+void PrintFunDefDepth(struct FunctionDefinition* f, int depth) {
+  std::cout << "fn " << f->name << " ";
+  PrintExp(f->param_pattern);
+  std::cout << " -> ";
+  PrintExp(f->return_type);
+  if (f->body) {
+    std::cout << " {" << std::endl;
+    PrintStatement(f->body, depth);
+    std::cout << std::endl << "}" << std::endl;
+  } else {
+    std::cout << ";" << std::endl;
+  }
+}
+
+void PrintFunDef(struct FunctionDefinition* f) { PrintFunDefDepth(f, -1); }
+
+}  // namespace Carbon

+ 29 - 0
executable_semantics/ast/function_definition.h

@@ -0,0 +1,29 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_FUNCTION_DEFINITION_H_
+#define EXECUTABLE_SEMANTICS_AST_FUNCTION_DEFINITION_H_
+
+#include "executable_semantics/ast/expression.h"
+#include "executable_semantics/ast/statement.h"
+
+namespace Carbon {
+
+struct FunctionDefinition {
+  int line_num;
+  std::string name;
+  Expression* param_pattern;
+  Expression* return_type;
+  Statement* body;
+};
+
+auto MakeFunDef(int line_num, std::string name, Expression* ret_type,
+                Expression* param, Statement* body)
+    -> struct FunctionDefinition*;
+void PrintFunDef(struct FunctionDefinition*);
+void PrintFunDefDepth(struct FunctionDefinition*, int);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_FUNCTION_DEFINITION_H_

+ 30 - 0
executable_semantics/ast/member.cpp

@@ -0,0 +1,30 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/ast/member.h"
+
+#include <iostream>
+
+namespace Carbon {
+
+auto MakeField(int line_num, std::string name, Expression* type) -> Member* {
+  auto m = new Member();
+  m->line_num = line_num;
+  m->tag = MemberKind::FieldMember;
+  m->u.field.name = new std::string(std::move(name));
+  m->u.field.type = type;
+  return m;
+}
+
+void PrintMember(Member* m) {
+  switch (m->tag) {
+    case MemberKind::FieldMember:
+      std::cout << "var " << *m->u.field.name << " : ";
+      PrintExp(m->u.field.type);
+      std::cout << ";" << std::endl;
+      break;
+  }
+}
+
+}  // namespace Carbon

+ 33 - 0
executable_semantics/ast/member.h

@@ -0,0 +1,33 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_MEMBER_H_
+#define EXECUTABLE_SEMANTICS_AST_MEMBER_H_
+
+#include <string>
+
+#include "executable_semantics/ast/expression.h"
+
+namespace Carbon {
+
+enum class MemberKind { FieldMember };
+
+struct Member {
+  int line_num;
+  MemberKind tag;
+  union {
+    struct {
+      std::string* name;
+      Expression* type;
+    } field;
+  } u;
+};
+
+auto MakeField(int line_num, std::string name, Expression* type) -> Member*;
+
+void PrintMember(Member* m);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_MEMBER_H_

+ 190 - 0
executable_semantics/ast/statement.cpp

@@ -0,0 +1,190 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/ast/statement.h"
+
+#include <iostream>
+
+namespace Carbon {
+
+auto MakeExpStmt(int line_num, Expression* exp) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::ExpressionStatement;
+  s->u.exp = exp;
+  return s;
+}
+
+auto MakeAssign(int line_num, Expression* lhs, Expression* rhs) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Assign;
+  s->u.assign.lhs = lhs;
+  s->u.assign.rhs = rhs;
+  return s;
+}
+
+auto MakeVarDef(int line_num, Expression* pat, Expression* init) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::VariableDefinition;
+  s->u.variable_definition.pat = pat;
+  s->u.variable_definition.init = init;
+  return s;
+}
+
+auto MakeIf(int line_num, Expression* cond, Statement* then_stmt,
+            Statement* else_stmt) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::If;
+  s->u.if_stmt.cond = cond;
+  s->u.if_stmt.then_stmt = then_stmt;
+  s->u.if_stmt.else_stmt = else_stmt;
+  return s;
+}
+
+auto MakeWhile(int line_num, Expression* cond, Statement* body) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::While;
+  s->u.while_stmt.cond = cond;
+  s->u.while_stmt.body = body;
+  return s;
+}
+
+auto MakeBreak(int line_num) -> Statement* {
+  std::cout << "MakeBlock" << std::endl;
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Break;
+  return s;
+}
+
+auto MakeContinue(int line_num) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Continue;
+  return s;
+}
+
+auto MakeReturn(int line_num, Expression* e) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Return;
+  s->u.return_stmt = e;
+  return s;
+}
+
+auto MakeSeq(int line_num, Statement* s1, Statement* s2) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Sequence;
+  s->u.sequence.stmt = s1;
+  s->u.sequence.next = s2;
+  return s;
+}
+
+auto MakeBlock(int line_num, Statement* stmt) -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Block;
+  s->u.block.stmt = stmt;
+  return s;
+}
+
+auto MakeMatch(int line_num, Expression* exp,
+               std::list<std::pair<Expression*, Statement*>>* clauses)
+    -> Statement* {
+  auto* s = new Statement();
+  s->line_num = line_num;
+  s->tag = StatementKind::Match;
+  s->u.match_stmt.exp = exp;
+  s->u.match_stmt.clauses = clauses;
+  return s;
+}
+
+void PrintStatement(Statement* s, int depth) {
+  if (!s) {
+    return;
+  }
+  if (depth == 0) {
+    std::cout << " ... ";
+    return;
+  }
+  switch (s->tag) {
+    case StatementKind::Match:
+      std::cout << "match (";
+      PrintExp(s->u.match_stmt.exp);
+      std::cout << ") {";
+      if (depth < 0 || depth > 1) {
+        std::cout << std::endl;
+        for (auto& clause : *s->u.match_stmt.clauses) {
+          std::cout << "case ";
+          PrintExp(clause.first);
+          std::cout << " =>" << std::endl;
+          PrintStatement(clause.second, depth - 1);
+          std::cout << std::endl;
+        }
+      } else {
+        std::cout << "...";
+      }
+      std::cout << "}";
+      break;
+    case StatementKind::While:
+      std::cout << "while (";
+      PrintExp(s->u.while_stmt.cond);
+      std::cout << ")" << std::endl;
+      PrintStatement(s->u.while_stmt.body, depth - 1);
+      break;
+    case StatementKind::Break:
+      std::cout << "break;";
+      break;
+    case StatementKind::Continue:
+      std::cout << "continue;";
+      break;
+    case StatementKind::VariableDefinition:
+      std::cout << "var ";
+      PrintExp(s->u.variable_definition.pat);
+      std::cout << " = ";
+      PrintExp(s->u.variable_definition.init);
+      std::cout << ";";
+      break;
+    case StatementKind::ExpressionStatement:
+      PrintExp(s->u.exp);
+      std::cout << ";";
+      break;
+    case StatementKind::Assign:
+      PrintExp(s->u.assign.lhs);
+      std::cout << " = ";
+      PrintExp(s->u.assign.rhs);
+      std::cout << ";";
+      break;
+    case StatementKind::If:
+      std::cout << "if (";
+      PrintExp(s->u.if_stmt.cond);
+      std::cout << ")" << std::endl;
+      PrintStatement(s->u.if_stmt.then_stmt, depth - 1);
+      std::cout << std::endl << "else" << std::endl;
+      PrintStatement(s->u.if_stmt.else_stmt, depth - 1);
+      break;
+    case StatementKind::Return:
+      std::cout << "return ";
+      PrintExp(s->u.return_stmt);
+      std::cout << ";";
+      break;
+    case StatementKind::Sequence:
+      PrintStatement(s->u.sequence.stmt, depth);
+      if (depth < 0 || depth > 1) {
+        std::cout << std::endl;
+      }
+      PrintStatement(s->u.sequence.next, depth - 1);
+      break;
+    case StatementKind::Block:
+      std::cout << "{" << std::endl;
+      PrintStatement(s->u.block.stmt, depth - 1);
+      std::cout << std::endl << "}" << std::endl;
+  }
+}
+}  // namespace Carbon

+ 84 - 0
executable_semantics/ast/statement.h

@@ -0,0 +1,84 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_STATEMENT_H_
+#define EXECUTABLE_SEMANTICS_AST_STATEMENT_H_
+
+#include <list>
+
+#include "executable_semantics/ast/expression.h"
+
+namespace Carbon {
+
+enum class StatementKind {
+  ExpressionStatement,
+  Assign,
+  VariableDefinition,
+  If,
+  Return,
+  Sequence,
+  Block,
+  While,
+  Break,
+  Continue,
+  Match
+};
+
+struct Statement {
+  int line_num;
+  StatementKind tag;
+  union {
+    Expression* exp;
+    struct {
+      Expression* lhs;
+      Expression* rhs;
+    } assign;
+    struct {
+      Expression* pat;
+      Expression* init;
+    } variable_definition;
+    struct {
+      Expression* cond;
+      Statement* then_stmt;
+      Statement* else_stmt;
+    } if_stmt;
+    Expression* return_stmt;
+    struct {
+      Statement* stmt;
+      Statement* next;
+    } sequence;
+    struct {
+      Statement* stmt;
+    } block;
+    struct {
+      Expression* cond;
+      Statement* body;
+    } while_stmt;
+    struct {
+      Expression* exp;
+      std::list<std::pair<Expression*, Statement*>>* clauses;
+    } match_stmt;
+  } u;
+};
+
+auto MakeExpStmt(int line_num, Expression* exp) -> Statement*;
+auto MakeAssign(int line_num, Expression* lhs, Expression* rhs) -> Statement*;
+auto MakeVarDef(int line_num, Expression* pat, Expression* init) -> Statement*;
+auto MakeIf(int line_num, Expression* cond, Statement* then_stmt,
+            Statement* else_stmt) -> Statement*;
+auto MakeReturn(int line_num, Expression* e) -> Statement*;
+auto MakeSeq(int line_num, Statement* s1, Statement* s2) -> Statement*;
+auto MakeBlock(int line_num, Statement* s) -> Statement*;
+auto MakeWhile(int line_num, Expression* cond, Statement* body) -> Statement*;
+auto MakeBreak(int line_num) -> Statement*;
+auto MakeContinue(int line_num) -> Statement*;
+auto MakeMatch(int line_num, Expression* exp,
+               std::list<std::pair<Expression*, Statement*>>* clauses)
+    -> Statement*;
+
+void PrintStatement(Statement*, int);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_STATEMENT_H_

+ 23 - 0
executable_semantics/ast/struct_definition.h

@@ -0,0 +1,23 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_
+#define EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_
+
+#include <list>
+#include <string>
+
+#include "executable_semantics/ast/member.h"
+
+namespace Carbon {
+
+struct StructDefinition {
+  int line_num;
+  std::string* name;
+  std::list<Member*>* members;
+};
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_

+ 33 - 0
executable_semantics/interpreter/BUILD

@@ -0,0 +1,33 @@
+# Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+load("@rules_cc//cc:defs.bzl", "cc_library")
+
+package(default_visibility = ["//executable_semantics:__subpackages__"])
+
+# TODO: It may be helpful to break this apart.
+cc_library(
+    name = "interpreter",
+    srcs = [
+        "action.cpp",
+        "interpreter.cpp",
+        "typecheck.cpp",
+        "value.cpp",
+    ],
+    hdrs = [
+        "action.h",
+        "assoc_list.h",
+        "cons_list.h",
+        "interpreter.h",
+        "typecheck.h",
+        "value.h",
+    ],
+    deps = [
+        "//executable_semantics/ast:declaration",
+        "//executable_semantics/ast:expression",
+        "//executable_semantics/ast:function_definition",
+        "//executable_semantics/ast:member",
+        "//executable_semantics/ast:statement",
+    ],
+)

+ 108 - 0
executable_semantics/interpreter/action.cpp

@@ -0,0 +1,108 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include "executable_semantics/ast/expression.h"
+#include "executable_semantics/ast/function_definition.h"
+#include "executable_semantics/interpreter/interpreter.h"
+#include "executable_semantics/interpreter/typecheck.h"
+
+namespace Carbon {
+
+void PrintAct(Action* act, std::ostream& out) {
+  switch (act->tag) {
+    case ActionKind::DeleteTmpAction:
+      std::cout << "delete_tmp(" << act->u.delete_tmp << ")";
+      break;
+    case ActionKind::ExpToLValAction:
+      out << "exp=>lval";
+      break;
+    case ActionKind::LValAction:
+    case ActionKind::ExpressionAction:
+      PrintExp(act->u.exp);
+      break;
+    case ActionKind::StatementAction:
+      PrintStatement(act->u.stmt, 1);
+      break;
+    case ActionKind::ValAction:
+      PrintValue(act->u.val, out);
+      break;
+  }
+  out << "<" << act->pos << ">";
+  if (act->results.size() > 0) {
+    out << "(";
+    for (auto& result : act->results) {
+      if (result) {
+        PrintValue(result, out);
+      }
+      out << ",";
+    }
+    out << ")";
+  }
+}
+
+void PrintActList(Cons<Action*>* ls, std::ostream& out) {
+  if (ls) {
+    PrintAct(ls->curr, out);
+    if (ls->next) {
+      out << " :: ";
+      PrintActList(ls->next, out);
+    }
+  }
+}
+
+auto MakeExpAct(Expression* e) -> Action* {
+  auto* act = new Action();
+  act->tag = ActionKind::ExpressionAction;
+  act->u.exp = e;
+  act->pos = -1;
+  return act;
+}
+
+auto MakeLvalAct(Expression* e) -> Action* {
+  auto* act = new Action();
+  act->tag = ActionKind::LValAction;
+  act->u.exp = e;
+  act->pos = -1;
+  return act;
+}
+
+auto MakeStmtAct(Statement* s) -> Action* {
+  auto* act = new Action();
+  act->tag = ActionKind::StatementAction;
+  act->u.stmt = s;
+  act->pos = -1;
+  return act;
+}
+
+auto MakeValAct(Value* v) -> Action* {
+  auto* act = new Action();
+  act->tag = ActionKind::ValAction;
+  act->u.val = v;
+  act->pos = -1;
+  return act;
+}
+
+auto MakeExpToLvalAct() -> Action* {
+  auto* act = new Action();
+  act->tag = ActionKind::ExpToLValAction;
+  act->pos = -1;
+  return act;
+}
+
+auto MakeDeleteAct(Address a) -> Action* {
+  auto* act = new Action();
+  act->tag = ActionKind::DeleteTmpAction;
+  act->pos = -1;
+  act->u.delete_tmp = a;
+  return act;
+}
+
+}  // namespace Carbon

+ 50 - 0
executable_semantics/interpreter/action.h

@@ -0,0 +1,50 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_
+#define EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_
+
+#include <iostream>
+#include <vector>
+
+#include "executable_semantics/ast/expression.h"
+#include "executable_semantics/ast/statement.h"
+#include "executable_semantics/interpreter/cons_list.h"
+#include "executable_semantics/interpreter/value.h"
+
+namespace Carbon {
+
+enum class ActionKind {
+  LValAction,
+  ExpressionAction,
+  StatementAction,
+  ValAction,
+  ExpToLValAction,
+  DeleteTmpAction
+};
+
+struct Action {
+  ActionKind tag;
+  union {
+    Expression* exp;  // for LValAction and ExpressionAction
+    Statement* stmt;
+    Value* val;  // for finished actions with a value (ValAction)
+    Address delete_tmp;
+  } u;
+  int pos;                      // position or state of the action
+  std::vector<Value*> results;  // results from subexpression
+};
+
+void PrintAct(Action* act, std::ostream& out);
+void PrintActList(Cons<Action*>* ls, std::ostream& out);
+auto MakeExpAct(Expression* e) -> Action*;
+auto MakeLvalAct(Expression* e) -> Action*;
+auto MakeStmtAct(Statement* s) -> Action*;
+auto MakeValAct(Value* v) -> Action*;
+auto MakeExpToLvalAct() -> Action*;
+auto MakeDeleteAct(Address a) -> Action*;
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_INTERPRETER_ACTION_H_

+ 38 - 0
executable_semantics/interpreter/assoc_list.h

@@ -0,0 +1,38 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_ASSOC_LIST_H_
+#define EXECUTABLE_SEMANTICS_INTERPRETER_ASSOC_LIST_H_
+
+#include <iostream>
+#include <list>
+#include <string>
+
+namespace Carbon {
+
+template <class K, class V>
+struct AssocList {
+  AssocList(K k, V v, AssocList* n) : key(k), value(v), next(n) {}
+
+  K key;
+  V value;
+  AssocList* next;
+};
+
+template <class K, class V>
+auto Lookup(int line_num, AssocList<K, V>* alist, const K& key,
+            void (*print_key)(const K&)) -> V {
+  if (alist == NULL) {
+    std::cerr << line_num << ": could not find `" << key << "`" << std::endl;
+    exit(-1);
+  } else if (alist->key == key) {
+    return alist->value;
+  } else {
+    return Lookup(line_num, alist->next, key, print_key);
+  }
+}
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_INTERPRETER_ASSOC_LIST_H_

+ 39 - 0
executable_semantics/interpreter/cons_list.h

@@ -0,0 +1,39 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_CONS_LIST_H_
+#define EXECUTABLE_SEMANTICS_INTERPRETER_CONS_LIST_H_
+
+namespace Carbon {
+
+template <class T>
+struct Cons {
+  Cons(T e, Cons* n) : curr(e), next(n) {}
+
+  T curr;
+  Cons* next;
+};
+
+template <class T>
+auto MakeCons(const T& x) -> Cons<T>* {
+  return new Cons<T>(x, nullptr);
+}
+
+template <class T>
+auto MakeCons(const T& x, Cons<T>* ls) -> Cons<T>* {
+  return new Cons<T>(x, ls);
+}
+
+template <class T>
+auto Length(Cons<T>* ls) -> unsigned int {
+  if (ls) {
+    return 1 + Length(ls->next);
+  } else {
+    return 0;
+  }
+}
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_INTERPRETER_CONS_LIST_H_

+ 1350 - 0
executable_semantics/interpreter/interpreter.cpp

@@ -0,0 +1,1350 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/interpreter/interpreter.h"
+
+#include <iostream>
+#include <iterator>
+#include <map>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include "executable_semantics/ast/expression.h"
+#include "executable_semantics/ast/function_definition.h"
+#include "executable_semantics/interpreter/typecheck.h"
+
+namespace Carbon {
+
+State* state = nullptr;
+
+auto PatternMatch(Value* pat, Value* val, Env*, std::list<std::string>*, int)
+    -> Env*;
+void HandleValue();
+
+template <class T>
+static auto FindField(const std::string& field,
+                      const std::vector<std::pair<std::string, T>>& inits)
+    -> std::optional<T> {
+  for (const auto& i : inits) {
+    if (i.first == field) {
+      return i.second;
+    }
+  }
+  return std::nullopt;
+}
+
+/**** Auxiliary Functions ****/
+
+auto AllocateValue(Value* v) -> Address {
+  // Putting the following two side effects together in this function
+  // ensures that we don't do anything else in between, which is really bad!
+  // Consider whether to include a copy of the input v in this function
+  // or to leave it up to the caller.
+  Address a = state->heap.size();
+  state->heap.push_back(v);
+  return a;
+}
+
+auto CopyVal(Value* val, int line_num) -> Value* {
+  CheckAlive(val, line_num);
+  switch (val->tag) {
+    case ValKind::TupleV: {
+      auto elts = new std::vector<std::pair<std::string, Address>>();
+      for (auto& i : *val->u.tuple.elts) {
+        Value* elt = CopyVal(state->heap[i.second], line_num);
+        elts->push_back(make_pair(i.first, AllocateValue(elt)));
+      }
+      return MakeTupleVal(elts);
+    }
+    case ValKind::AltV: {
+      Value* arg = CopyVal(val->u.alt.arg, line_num);
+      return MakeAltVal(*val->u.alt.alt_name, *val->u.alt.choice_name, arg);
+    }
+    case ValKind::StructV: {
+      Value* inits = CopyVal(val->u.struct_val.inits, line_num);
+      return MakeStructVal(val->u.struct_val.type, inits);
+    }
+    case ValKind::IntV:
+      return MakeIntVal(val->u.integer);
+    case ValKind::BoolV:
+      return MakeBoolVal(val->u.boolean);
+    case ValKind::FunV:
+      return MakeFunVal(*val->u.fun.name, val->u.fun.param, val->u.fun.body);
+    case ValKind::PtrV:
+      return MakePtrVal(val->u.ptr);
+    case ValKind::FunctionTV:
+      return MakeFunTypeVal(CopyVal(val->u.fun_type.param, line_num),
+                            CopyVal(val->u.fun_type.ret, line_num));
+
+    case ValKind::PointerTV:
+      return MakePtrTypeVal(CopyVal(val->u.ptr_type.type, line_num));
+    case ValKind::IntTV:
+      return MakeIntTypeVal();
+    case ValKind::BoolTV:
+      return MakeBoolTypeVal();
+    case ValKind::TypeTV:
+      return MakeTypeTypeVal();
+    case ValKind::VarTV:
+      return MakeVarTypeVal(*val->u.var_type);
+    case ValKind::AutoTV:
+      return MakeAutoTypeVal();
+    case ValKind::TupleTV: {
+      auto new_fields = new VarValues();
+      for (auto& field : *val->u.tuple_type.fields) {
+        auto v = CopyVal(field.second, line_num);
+        new_fields->push_back(make_pair(field.first, v));
+      }
+      return MakeTupleTypeVal(new_fields);
+    }
+    case ValKind::StructTV:
+    case ValKind::ChoiceTV:
+    case ValKind::VarPatV:
+    case ValKind::AltConsV:
+      return val;  // no need to copy these because they are immutable?
+      // No, they need to be copied so they don't get killed. -Jeremy
+  }
+}
+
+void KillValue(Value* val) {
+  val->alive = false;
+  switch (val->tag) {
+    case ValKind::AltV:
+      KillValue(val->u.alt.arg);
+      break;
+    case ValKind::StructV:
+      KillValue(val->u.struct_val.inits);
+      break;
+    case ValKind::TupleV:
+      for (auto& elt : *val->u.tuple.elts) {
+        if (state->heap[elt.second]->alive) {
+          KillValue(state->heap[elt.second]);
+        } else {
+          std::cerr << "runtime error, killing an already dead value"
+                    << std::endl;
+          exit(-1);
+        }
+      }
+      break;
+    default:
+      break;
+  }
+}
+
+void PrintEnv(Env* env, std::ostream& out) {
+  if (env) {
+    std::cout << env->key << ": ";
+    PrintValue(state->heap[env->value], out);
+    std::cout << ", ";
+    PrintEnv(env->next, out);
+  }
+}
+
+/***** Frame and State Operations *****/
+
+void PrintFrame(Frame* frame, std::ostream& out) {
+  out << frame->name;
+  out << "{";
+  PrintActList(frame->todo, out);
+  out << "}";
+}
+
+void PrintStack(Cons<Frame*>* ls, std::ostream& out) {
+  if (ls) {
+    PrintFrame(ls->curr, out);
+    if (ls->next) {
+      out << " :: ";
+      PrintStack(ls->next, out);
+    }
+  }
+}
+
+void PrintHeap(const std::vector<Value*>& heap, std::ostream& out) {
+  for (auto& iter : heap) {
+    if (iter) {
+      PrintValue(iter, out);
+    } else {
+      out << "_";
+    }
+    out << ", ";
+  }
+}
+
+auto CurrentEnv(State* state) -> Env* {
+  Frame* frame = state->stack->curr;
+  return frame->scopes->curr->env;
+}
+
+void PrintState(std::ostream& out) {
+  out << "{" << std::endl;
+  out << "stack: ";
+  PrintStack(state->stack, out);
+  out << std::endl << "heap: ";
+  PrintHeap(state->heap, out);
+  out << std::endl << "env: ";
+  PrintEnv(CurrentEnv(state), out);
+  out << std::endl << "}" << std::endl;
+}
+
+/***** Auxiliary Functions *****/
+
+auto ValToInt(Value* v, int line_num) -> int {
+  CheckAlive(v, line_num);
+  switch (v->tag) {
+    case ValKind::IntV:
+      return v->u.integer;
+    default:
+      std::cerr << line_num << ": runtime error: expected an integer"
+                << std::endl;
+      exit(-1);
+  }
+}
+
+auto ValToBool(Value* v, int line_num) -> int {
+  CheckAlive(v, line_num);
+  switch (v->tag) {
+    case ValKind::BoolV:
+      return v->u.boolean;
+    default:
+      std::cerr << "runtime type error: expected a Boolean" << std::endl;
+      exit(-1);
+  }
+}
+
+auto ValToPtr(Value* v, int line_num) -> Address {
+  CheckAlive(v, line_num);
+  switch (v->tag) {
+    case ValKind::PtrV:
+      return v->u.ptr;
+    default:
+      std::cerr << "runtime type error: expected a pointer, not ";
+      PrintValue(v, std::cerr);
+      std::cerr << std::endl;
+      exit(-1);
+  }
+}
+
+auto EvalPrim(Operator op, const std::vector<Value*>& args, int line_num)
+    -> Value* {
+  switch (op) {
+    case Operator::Neg:
+      return MakeIntVal(-ValToInt(args[0], line_num));
+    case Operator::Add:
+      return MakeIntVal(ValToInt(args[0], line_num) +
+                        ValToInt(args[1], line_num));
+    case Operator::Sub:
+      return MakeIntVal(ValToInt(args[0], line_num) -
+                        ValToInt(args[1], line_num));
+    case Operator::Not:
+      return MakeBoolVal(!ValToBool(args[0], line_num));
+    case Operator::And:
+      return MakeBoolVal(ValToBool(args[0], line_num) &&
+                         ValToBool(args[1], line_num));
+    case Operator::Or:
+      return MakeBoolVal(ValToBool(args[0], line_num) ||
+                         ValToBool(args[1], line_num));
+    case Operator::Eq:
+      return MakeBoolVal(ValueEqual(args[0], args[1], line_num));
+  }
+}
+
+Env* globals;
+
+void InitGlobals(std::list<Declaration*>* fs) {
+  globals = nullptr;
+  for (auto& iter : *fs) {
+    switch (iter->tag) {
+      case DeclarationKind::ChoiceDeclaration: {
+        auto d = iter;
+        auto alts = new VarValues();
+        for (auto i = d->u.choice_def.alternatives->begin();
+             i != d->u.choice_def.alternatives->end(); ++i) {
+          auto t =
+              ToType(d->u.choice_def.line_num, InterpExp(nullptr, i->second));
+          alts->push_back(make_pair(i->first, t));
+        }
+        auto ct = MakeChoiceTypeVal(d->u.choice_def.name, alts);
+        auto a = AllocateValue(ct);
+        globals = new Env(*d->u.choice_def.name, a, globals);
+        break;
+      }
+      case DeclarationKind::StructDeclaration: {
+        auto d = iter;
+        auto fields = new VarValues();
+        auto methods = new VarValues();
+        for (auto i = d->u.struct_def->members->begin();
+             i != d->u.struct_def->members->end(); ++i) {
+          switch ((*i)->tag) {
+            case MemberKind::FieldMember: {
+              auto t = ToType(d->u.struct_def->line_num,
+                              InterpExp(nullptr, (*i)->u.field.type));
+              fields->push_back(make_pair(*(*i)->u.field.name, t));
+              break;
+            }
+          }
+        }
+        auto st = MakeStructTypeVal(*d->u.struct_def->name, fields, methods);
+        auto a = AllocateValue(st);
+        globals = new Env(*d->u.struct_def->name, a, globals);
+        break;
+      }
+      case DeclarationKind::FunctionDeclaration: {
+        struct FunctionDefinition* fun = iter->u.fun_def;
+        Env* env = nullptr;
+        auto pt = InterpExp(env, fun->param_pattern);
+        auto f = MakeFunVal(fun->name, pt, fun->body);
+        Address a = AllocateValue(f);
+        globals = new Env(fun->name, a, globals);
+        break;
+      }
+    }
+  }
+}
+
+//    { S, H} -> { { C, E, F} :: S, H}
+// where C is the body of the function,
+//       E is the environment (functions + parameters + locals)
+//       F is the function
+void CallFunction(int line_num, std::vector<Value*> operas, State* state) {
+  CheckAlive(operas[0], line_num);
+  switch (operas[0]->tag) {
+    case ValKind::FunV: {
+      // Bind arguments to parameters
+      std::list<std::string> params;
+      Env* env = PatternMatch(operas[0]->u.fun.param, operas[1], globals,
+                              &params, line_num);
+      if (!env) {
+        std::cerr << "internal error in call_function, pattern match failed"
+                  << std::endl;
+        exit(-1);
+      }
+      // Create the new frame and push it on the stack
+      auto* scope = new Scope(env, params);
+      auto* frame = new Frame(*operas[0]->u.fun.name, MakeCons(scope),
+                              MakeCons(MakeStmtAct(operas[0]->u.fun.body)));
+      state->stack = MakeCons(frame, state->stack);
+      break;
+    }
+    case ValKind::StructTV: {
+      Value* arg = CopyVal(operas[1], line_num);
+      Value* sv = MakeStructVal(operas[0], arg);
+      Frame* frame = state->stack->curr;
+      frame->todo = MakeCons(MakeValAct(sv), frame->todo);
+      break;
+    }
+    case ValKind::AltConsV: {
+      Value* arg = CopyVal(operas[1], line_num);
+      Value* av = MakeAltVal(*operas[0]->u.alt_cons.alt_name,
+                             *operas[0]->u.alt_cons.choice_name, arg);
+      Frame* frame = state->stack->curr;
+      frame->todo = MakeCons(MakeValAct(av), frame->todo);
+      break;
+    }
+    default:
+      std::cerr << line_num << ": in call, expected a function, not ";
+      PrintValue(operas[0], std::cerr);
+      std::cerr << std::endl;
+      exit(-1);
+  }
+}
+
+void KillScope(int line_num, Scope* scope) {
+  for (const auto& l : scope->locals) {
+    Address a = Lookup(line_num, scope->env, l, PrintErrorString);
+    KillValue(state->heap[a]);
+  }
+}
+
+void KillLocals(int line_num, Frame* frame) {
+  Cons<Scope*>* scopes = frame->scopes;
+  for (Scope* scope = scopes->curr; scopes; scopes = scopes->next) {
+    KillScope(line_num, scope);
+  }
+}
+
+void CreateTuple(Frame* frame, Action* act, Expression* /*exp*/) {
+  //    { { (v1,...,vn) :: C, E, F} :: S, H}
+  // -> { { `(v1,...,vn) :: C, E, F} :: S, H}
+  auto elts = new std::vector<std::pair<std::string, Address>>();
+  auto f = act->u.exp->u.tuple.fields->begin();
+  for (auto i = act->results.begin(); i != act->results.end(); ++i, ++f) {
+    Address a = AllocateValue(*i);  // copy?
+    elts->push_back(make_pair(f->first, a));
+  }
+  Value* tv = MakeTupleVal(elts);
+  frame->todo = MakeCons(MakeValAct(tv), frame->todo->next);
+}
+
+auto ToValue(Expression* value) -> Value* {
+  switch (value->tag) {
+    case ExpressionKind::Integer:
+      return MakeIntVal(value->u.integer);
+    case ExpressionKind::Boolean:
+      return MakeBoolVal(value->u.boolean);
+    case ExpressionKind::IntT:
+      return MakeIntTypeVal();
+    case ExpressionKind::BoolT:
+      return MakeBoolTypeVal();
+    case ExpressionKind::TypeT:
+      return MakeTypeTypeVal();
+    case ExpressionKind::FunctionT:
+      // Instead add to patterns?
+    default:
+      std::cerr << "internal error in to_value, didn't expect ";
+      PrintExp(value);
+      std::cerr << std::endl;
+      exit(-1);
+  }
+}
+
+// Returns 0 if the value doesn't match the pattern.
+auto PatternMatch(Value* p, Value* v, Env* env, std::list<std::string>* vars,
+                  int line_num) -> Env* {
+  std::cout << "pattern_match(";
+  PrintValue(p, std::cout);
+  std::cout << ", ";
+  PrintValue(v, std::cout);
+  std::cout << ")" << std::endl;
+  switch (p->tag) {
+    case ValKind::VarPatV: {
+      Address a = AllocateValue(CopyVal(v, line_num));
+      vars->push_back(*p->u.var_pat.name);
+      return new Env(*p->u.var_pat.name, a, env);
+    }
+    case ValKind::TupleV:
+      switch (v->tag) {
+        case ValKind::TupleV: {
+          if (p->u.tuple.elts->size() != v->u.tuple.elts->size()) {
+            std::cerr << "runtime error: arity mismatch in tuple pattern match"
+                      << std::endl;
+            exit(-1);
+          }
+          for (auto& elt : *p->u.tuple.elts) {
+            auto a = FindField(elt.first, *v->u.tuple.elts);
+            if (a == std::nullopt) {
+              std::cerr << "runtime error: field " << elt.first << "not in ";
+              PrintValue(v, std::cerr);
+              std::cerr << std::endl;
+              exit(-1);
+            }
+            env = PatternMatch(state->heap[elt.second], state->heap[*a], env,
+                               vars, line_num);
+          }
+          return env;
+        }
+        default:
+          std::cerr
+              << "internal error, expected a tuple value in pattern, not ";
+          PrintValue(v, std::cerr);
+          std::cerr << std::endl;
+          exit(-1);
+      }
+    case ValKind::AltV:
+      switch (v->tag) {
+        case ValKind::AltV: {
+          if (*p->u.alt.choice_name != *v->u.alt.choice_name ||
+              *p->u.alt.alt_name != *v->u.alt.alt_name) {
+            return nullptr;
+          }
+          env = PatternMatch(p->u.alt.arg, v->u.alt.arg, env, vars, line_num);
+          return env;
+        }
+        default:
+          std::cerr
+              << "internal error, expected a choice alternative in pattern, "
+                 "not ";
+          PrintValue(v, std::cerr);
+          std::cerr << std::endl;
+          exit(-1);
+      }
+    case ValKind::FunctionTV:
+      switch (v->tag) {
+        case ValKind::FunctionTV:
+          env = PatternMatch(p->u.fun_type.param, v->u.fun_type.param, env,
+                             vars, line_num);
+          env = PatternMatch(p->u.fun_type.ret, v->u.fun_type.ret, env, vars,
+                             line_num);
+          return env;
+        default:
+          return nullptr;
+      }
+    default:
+      if (ValueEqual(p, v, line_num)) {
+        return env;
+      } else {
+        return nullptr;
+      }
+  }
+}
+
+void PatternAssignment(Value* pat, Value* val, int line_num) {
+  switch (pat->tag) {
+    case ValKind::PtrV:
+      state->heap[ValToPtr(pat, line_num)] = val;
+      break;
+    case ValKind::TupleV: {
+      switch (val->tag) {
+        case ValKind::TupleV: {
+          if (pat->u.tuple.elts->size() != val->u.tuple.elts->size()) {
+            std::cerr << "runtime error: arity mismatch in tuple pattern match"
+                      << std::endl;
+            exit(-1);
+          }
+          for (auto& elt : *pat->u.tuple.elts) {
+            auto a = FindField(elt.first, *val->u.tuple.elts);
+            if (a == std::nullopt) {
+              std::cerr << "runtime error: field " << elt.first << "not in ";
+              PrintValue(val, std::cerr);
+              std::cerr << std::endl;
+              exit(-1);
+            }
+            PatternAssignment(state->heap[elt.second], state->heap[*a],
+                              line_num);
+          }
+          break;
+        }
+        default:
+          std::cerr
+              << "internal error, expected a tuple value on right-hand-side, "
+                 "not ";
+          PrintValue(val, std::cerr);
+          std::cerr << std::endl;
+          exit(-1);
+      }
+      break;
+    }
+    case ValKind::AltV: {
+      switch (val->tag) {
+        case ValKind::AltV: {
+          if (*pat->u.alt.choice_name != *val->u.alt.choice_name ||
+              *pat->u.alt.alt_name != *val->u.alt.alt_name) {
+            std::cerr << "internal error in pattern assignment" << std::endl;
+            exit(-1);
+          }
+          PatternAssignment(pat->u.alt.arg, val->u.alt.arg, line_num);
+          break;
+        }
+        default:
+          std::cerr
+              << "internal error, expected an alternative in left-hand-side, "
+                 "not ";
+          PrintValue(val, std::cerr);
+          std::cerr << std::endl;
+          exit(-1);
+      }
+      break;
+    }
+    default:
+      if (!ValueEqual(pat, val, line_num)) {
+        std::cerr << "internal error in pattern assignment" << std::endl;
+        exit(-1);
+      }
+  }
+}
+
+/***** state transitions for lvalues *****/
+
+void StepLvalue() {
+  Frame* frame = state->stack->curr;
+  Action* act = frame->todo->curr;
+  Expression* exp = act->u.exp;
+  std::cout << "--- step lvalue ";
+  PrintExp(exp);
+  std::cout << " --->" << std::endl;
+  switch (exp->tag) {
+    case ExpressionKind::Variable: {
+      //    { {x :: C, E, F} :: S, H}
+      // -> { {E(x) :: C, E, F} :: S, H}
+      Address a = Lookup(exp->line_num, CurrentEnv(state),
+                         *(exp->u.variable.name), PrintErrorString);
+      Value* v = MakePtrVal(a);
+      CheckAlive(v, exp->line_num);
+      frame->todo = MakeCons(MakeValAct(v), frame->todo->next);
+      break;
+    }
+    case ExpressionKind::GetField: {
+      //    { {e.f :: C, E, F} :: S, H}
+      // -> { e :: [].f :: C, E, F} :: S, H}
+      frame->todo =
+          MakeCons(MakeLvalAct(exp->u.get_field.aggregate), frame->todo);
+      act->pos++;
+      break;
+    }
+    case ExpressionKind::Index: {
+      //    { {e[i] :: C, E, F} :: S, H}
+      // -> { e :: [][i] :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(exp->u.index.aggregate), frame->todo);
+      act->pos++;
+      break;
+    }
+    case ExpressionKind::Tuple: {
+      //    { {(f1=e1,...) :: C, E, F} :: S, H}
+      // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H}
+      Expression* e1 = (*exp->u.tuple.fields)[0].second;
+      frame->todo = MakeCons(MakeLvalAct(e1), frame->todo);
+      act->pos++;
+      break;
+    }
+    case ExpressionKind::Integer:
+    case ExpressionKind::Boolean:
+    case ExpressionKind::Call:
+    case ExpressionKind::PrimitiveOp:
+    case ExpressionKind::IntT:
+    case ExpressionKind::BoolT:
+    case ExpressionKind::TypeT:
+    case ExpressionKind::FunctionT:
+    case ExpressionKind::AutoT:
+    case ExpressionKind::PatternVariable: {
+      frame->todo = MakeCons(MakeExpAct(exp),
+                             MakeCons(MakeExpToLvalAct(), frame->todo->next));
+    }
+  }
+}
+
+/***** state transitions for expressions *****/
+
+void StepExp() {
+  Frame* frame = state->stack->curr;
+  Action* act = frame->todo->curr;
+  Expression* exp = act->u.exp;
+  std::cout << "--- step exp ";
+  PrintExp(exp);
+  std::cout << " --->" << std::endl;
+  switch (exp->tag) {
+    case ExpressionKind::PatternVariable: {
+      frame->todo =
+          MakeCons(MakeExpAct(exp->u.pattern_variable.type), frame->todo);
+      act->pos++;
+      break;
+    }
+    case ExpressionKind::Index: {
+      //    { { e[i] :: C, E, F} :: S, H}
+      // -> { { e :: [][i] :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(exp->u.index.aggregate), frame->todo);
+      act->pos++;
+      break;
+    }
+    case ExpressionKind::Tuple: {
+      if (exp->u.tuple.fields->size() > 0) {
+        //    { {(f1=e1,...) :: C, E, F} :: S, H}
+        // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H}
+        Expression* e1 = (*exp->u.tuple.fields)[0].second;
+        frame->todo = MakeCons(MakeExpAct(e1), frame->todo);
+        act->pos++;
+      } else {
+        CreateTuple(frame, act, exp);
+      }
+      break;
+    }
+    case ExpressionKind::GetField: {
+      //    { { e.f :: C, E, F} :: S, H}
+      // -> { { e :: [].f :: C, E, F} :: S, H}
+      frame->todo =
+          MakeCons(MakeLvalAct(exp->u.get_field.aggregate), frame->todo);
+      act->pos++;
+      break;
+    }
+    case ExpressionKind::Variable: {
+      // { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H}
+      Address a = Lookup(exp->line_num, CurrentEnv(state),
+                         *(exp->u.variable.name), PrintErrorString);
+      Value* v = state->heap[a];
+      frame->todo = MakeCons(MakeValAct(v), frame->todo->next);
+      break;
+    }
+    case ExpressionKind::Integer:
+      // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
+      frame->todo =
+          MakeCons(MakeValAct(MakeIntVal(exp->u.integer)), frame->todo->next);
+      break;
+    case ExpressionKind::Boolean:
+      // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
+      frame->todo =
+          MakeCons(MakeValAct(MakeBoolVal(exp->u.boolean)), frame->todo->next);
+      break;
+    case ExpressionKind::PrimitiveOp:
+      if (exp->u.primitive_op.arguments->size() > 0) {
+        //    { {op(e :: es) :: C, E, F} :: S, H}
+        // -> { e :: op([] :: es) :: C, E, F} :: S, H}
+        frame->todo = MakeCons(
+            MakeExpAct(exp->u.primitive_op.arguments->front()), frame->todo);
+        act->pos++;
+      } else {
+        //    { {v :: op(]) :: C, E, F} :: S, H}
+        // -> { {eval_prim(op, ()) :: C, E, F} :: S, H}
+        Value* v =
+            EvalPrim(exp->u.primitive_op.op, act->results, exp->line_num);
+        frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next);
+      }
+      break;
+    case ExpressionKind::Call:
+      //    { {e1(e2) :: C, E, F} :: S, H}
+      // -> { {e1 :: [](e2) :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(exp->u.call.function), frame->todo);
+      act->pos++;
+      break;
+    case ExpressionKind::IntT: {
+      Value* v = MakeIntTypeVal();
+      frame->todo = MakeCons(MakeValAct(v), frame->todo->next);
+      break;
+    }
+    case ExpressionKind::BoolT: {
+      Value* v = MakeBoolTypeVal();
+      frame->todo = MakeCons(MakeValAct(v), frame->todo->next);
+      break;
+    }
+    case ExpressionKind::AutoT: {
+      Value* v = MakeAutoTypeVal();
+      frame->todo = MakeCons(MakeValAct(v), frame->todo->next);
+      break;
+    }
+    case ExpressionKind::TypeT: {
+      Value* v = MakeTypeTypeVal();
+      frame->todo = MakeCons(MakeValAct(v), frame->todo->next);
+      break;
+    }
+    case ExpressionKind::FunctionT: {
+      frame->todo =
+          MakeCons(MakeExpAct(exp->u.function_type.parameter), frame->todo);
+      act->pos++;
+      break;
+    }
+  }  // switch (exp->tag)
+}
+
+/***** state transitions for statements *****/
+
+auto IsWhileAct(Action* act) -> bool {
+  switch (act->tag) {
+    case ActionKind::StatementAction:
+      switch (act->u.stmt->tag) {
+        case StatementKind::While:
+          return true;
+        default:
+          return false;
+      }
+    default:
+      return false;
+  }
+}
+
+auto IsBlockAct(Action* act) -> bool {
+  switch (act->tag) {
+    case ActionKind::StatementAction:
+      switch (act->u.stmt->tag) {
+        case StatementKind::Block:
+          return true;
+        default:
+          return false;
+      }
+    default:
+      return false;
+  }
+}
+
+void StepStmt() {
+  Frame* frame = state->stack->curr;
+  Action* act = frame->todo->curr;
+  Statement* stmt = act->u.stmt;
+  std::cout << "--- step stmt ";
+  PrintStatement(stmt, 1);
+  std::cout << " --->" << std::endl;
+  switch (stmt->tag) {
+    case StatementKind::Match:
+      //    { { (match (e) ...) :: C, E, F} :: S, H}
+      // -> { { e :: (match ([]) ...) :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(stmt->u.match_stmt.exp), frame->todo);
+      act->pos++;
+      break;
+    case StatementKind::While:
+      //    { { (while (e) s) :: C, E, F} :: S, H}
+      // -> { { e :: (while ([]) s) :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(stmt->u.while_stmt.cond), frame->todo);
+      act->pos++;
+      break;
+    case StatementKind::Break:
+      //    { { break; :: ... :: (while (e) s) :: C, E, F} :: S, H}
+      // -> { { C, E', F} :: S, H}
+      frame->todo = frame->todo->next;
+      while (frame->todo && !IsWhileAct(frame->todo->curr)) {
+        if (IsBlockAct(frame->todo->curr)) {
+          KillScope(stmt->line_num, frame->scopes->curr);
+          frame->scopes = frame->scopes->next;
+        }
+        frame->todo = frame->todo->next;
+      }
+      frame->todo = frame->todo->next;
+      break;
+    case StatementKind::Continue:
+      //    { { continue; :: ... :: (while (e) s) :: C, E, F} :: S, H}
+      // -> { { (while (e) s) :: C, E', F} :: S, H}
+      frame->todo = frame->todo->next;
+      while (frame->todo && !IsWhileAct(frame->todo->curr)) {
+        if (IsBlockAct(frame->todo->curr)) {
+          KillScope(stmt->line_num, frame->scopes->curr);
+          frame->scopes = frame->scopes->next;
+        }
+        frame->todo = frame->todo->next;
+      }
+      break;
+    case StatementKind::Block: {
+      if (act->pos == -1) {
+        auto* scope = new Scope(CurrentEnv(state), std::list<std::string>());
+        frame->scopes = MakeCons(scope, frame->scopes);
+        frame->todo = MakeCons(MakeStmtAct(stmt->u.block.stmt), frame->todo);
+        act->pos++;
+      } else {
+        Scope* scope = frame->scopes->curr;
+        KillScope(stmt->line_num, scope);
+        frame->scopes = frame->scopes->next;
+        frame->todo = frame->todo->next;
+      }
+      break;
+    }
+    case StatementKind::VariableDefinition:
+      //    { {(var x = e) :: C, E, F} :: S, H}
+      // -> { {e :: (var x = []) :: C, E, F} :: S, H}
+      frame->todo =
+          MakeCons(MakeExpAct(stmt->u.variable_definition.init), frame->todo);
+      act->pos++;
+      break;
+    case StatementKind::ExpressionStatement:
+      //    { {e :: C, E, F} :: S, H}
+      // -> { {e :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(stmt->u.exp), frame->todo);
+      break;
+    case StatementKind::Assign:
+      //    { {(lv = e) :: C, E, F} :: S, H}
+      // -> { {lv :: ([] = e) :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeLvalAct(stmt->u.assign.lhs), frame->todo);
+      act->pos++;
+      break;
+    case StatementKind::If:
+      //    { {(if (e) then_stmt else else_stmt) :: C, E, F} :: S, H}
+      // -> { { e :: (if ([]) then_stmt else else_stmt) :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(stmt->u.if_stmt.cond), frame->todo);
+      act->pos++;
+      break;
+    case StatementKind::Return:
+      //    { {return e :: C, E, F} :: S, H}
+      // -> { {e :: return [] :: C, E, F} :: S, H}
+      frame->todo = MakeCons(MakeExpAct(stmt->u.return_stmt), frame->todo);
+      act->pos++;
+      break;
+    case StatementKind::Sequence:
+      //    { { (s1,s2) :: C, E, F} :: S, H}
+      // -> { { s1 :: s2 :: C, E, F} :: S, H}
+      Cons<Action*>* todo = frame->todo->next;
+      if (stmt->u.sequence.next) {
+        todo = MakeCons(MakeStmtAct(stmt->u.sequence.next), todo);
+      }
+      frame->todo = MakeCons(MakeStmtAct(stmt->u.sequence.stmt), todo);
+      break;
+  }
+}
+
+auto GetMember(Address a, const std::string& f) -> Address {
+  Value* v = state->heap[a];
+  switch (v->tag) {
+    case ValKind::StructV: {
+      auto a = FindField(f, *v->u.struct_val.inits->u.tuple.elts);
+      if (a == std::nullopt) {
+        std::cerr << "runtime error, member " << f << " not in ";
+        PrintValue(v, std::cerr);
+        std::cerr << std::endl;
+        exit(-1);
+      }
+      return *a;
+    }
+    case ValKind::TupleV: {
+      auto a = FindField(f, *v->u.tuple.elts);
+      if (a == std::nullopt) {
+        std::cerr << "field " << f << " not in ";
+        PrintValue(v, std::cerr);
+        std::cerr << std::endl;
+        exit(-1);
+      }
+      return *a;
+    }
+    case ValKind::ChoiceTV: {
+      if (FindInVarValues(f, v->u.choice_type.alternatives) == nullptr) {
+        std::cerr << "alternative " << f << " not in ";
+        PrintValue(v, std::cerr);
+        std::cerr << std::endl;
+        exit(-1);
+      }
+      auto ac = MakeAltCons(f, *v->u.choice_type.name);
+      return AllocateValue(ac);
+    }
+    default:
+      std::cerr << "field access not allowed for value ";
+      PrintValue(v, std::cerr);
+      std::cerr << std::endl;
+      exit(-1);
+  }
+}
+
+auto InsertDelete(Action* del, Cons<Action*>* todo) -> Cons<Action*>* {
+  if (todo) {
+    switch (todo->curr->tag) {
+      case ActionKind::StatementAction: {
+        // This places the delete before the enclosing statement.
+        // Not sure if that is OK. Conceptually it should go after
+        // but that is tricky for some statements, like 'return'. -Jeremy
+        return MakeCons(del, todo);
+      }
+      case ActionKind::LValAction:
+      case ActionKind::ExpressionAction:
+      case ActionKind::ValAction:
+      case ActionKind::ExpToLValAction:
+      case ActionKind::DeleteTmpAction:
+        return MakeCons(todo->curr, InsertDelete(del, todo->next));
+    }
+  } else {
+    return MakeCons(del, todo);
+  }
+}
+
+/***** State transition for handling a value *****/
+
+void HandleValue() {
+  Frame* frame = state->stack->curr;
+  Action* val_act = frame->todo->curr;
+  Action* act = frame->todo->next->curr;
+  act->results.push_back(val_act->u.val);
+  act->pos++;
+
+  std::cout << "--- handle value ";
+  PrintValue(val_act->u.val, std::cout);
+  std::cout << " with ";
+  PrintAct(act, std::cout);
+  std::cout << " --->" << std::endl;
+
+  switch (act->tag) {
+    case ActionKind::DeleteTmpAction: {
+      KillValue(state->heap[act->u.delete_tmp]);
+      frame->todo = MakeCons(val_act, frame->todo->next->next);
+      break;
+    }
+    case ActionKind::ExpToLValAction: {
+      Address a = AllocateValue(act->results[0]);
+      auto del = MakeDeleteAct(a);
+      frame->todo = MakeCons(MakeValAct(MakePtrVal(a)),
+                             InsertDelete(del, frame->todo->next->next));
+      break;
+    }
+    case ActionKind::LValAction: {
+      Expression* exp = act->u.exp;
+      switch (exp->tag) {
+        case ExpressionKind::GetField: {
+          //    { v :: [].f :: C, E, F} :: S, H}
+          // -> { { &v.f :: C, E, F} :: S, H }
+          Value* str = act->results[0];
+          Address a =
+              GetMember(ValToPtr(str, exp->line_num), *exp->u.get_field.field);
+          frame->todo =
+              MakeCons(MakeValAct(MakePtrVal(a)), frame->todo->next->next);
+          break;
+        }
+        case ExpressionKind::Index: {
+          if (act->pos == 1) {
+            frame->todo =
+                MakeCons(MakeExpAct(exp->u.index.offset), frame->todo->next);
+          } else if (act->pos == 2) {
+            //    { v :: [][i] :: C, E, F} :: S, H}
+            // -> { { &v[i] :: C, E, F} :: S, H }
+            Value* tuple = act->results[0];
+            std::string f = std::to_string(ToInteger(act->results[1]));
+            auto a = FindField(f, *tuple->u.tuple.elts);
+            if (a == std::nullopt) {
+              std::cerr << "runtime error: field " << f << "not in ";
+              PrintValue(tuple, std::cerr);
+              std::cerr << std::endl;
+              exit(-1);
+            }
+            frame->todo =
+                MakeCons(MakeValAct(MakePtrVal(*a)), frame->todo->next->next);
+          }
+          break;
+        }
+        case ExpressionKind::Tuple: {
+          if (act->pos != static_cast<int>(exp->u.tuple.fields->size())) {
+            //    { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S,
+            //    H}
+            // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
+            // H}
+            Expression* elt = (*exp->u.tuple.fields)[act->pos].second;
+            frame->todo = MakeCons(MakeLvalAct(elt), frame->todo->next);
+          } else {
+            frame->todo = frame->todo->next;
+            CreateTuple(frame, act, exp);
+          }
+          break;
+        }
+        default:
+          std::cerr << "internal error in handle_value, LValAction"
+                    << std::endl;
+          exit(-1);
+      }
+      break;
+    }
+    case ActionKind::ExpressionAction: {
+      Expression* exp = act->u.exp;
+      switch (exp->tag) {
+        case ExpressionKind::PatternVariable: {
+          auto v =
+              MakeVarPatVal(*exp->u.pattern_variable.name, act->results[0]);
+          frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next);
+          break;
+        }
+        case ExpressionKind::Tuple: {
+          if (act->pos != static_cast<int>(exp->u.tuple.fields->size())) {
+            //    { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S,
+            //    H}
+            // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
+            // H}
+            Expression* elt = (*exp->u.tuple.fields)[act->pos].second;
+            frame->todo = MakeCons(MakeExpAct(elt), frame->todo->next);
+          } else {
+            frame->todo = frame->todo->next;
+            CreateTuple(frame, act, exp);
+          }
+          break;
+        }
+        case ExpressionKind::Index: {
+          if (act->pos == 1) {
+            frame->todo =
+                MakeCons(MakeExpAct(exp->u.index.offset), frame->todo->next);
+          } else if (act->pos == 2) {
+            auto tuple = act->results[0];
+            switch (tuple->tag) {
+              case ValKind::TupleV: {
+                //    { { v :: [][i] :: C, E, F} :: S, H}
+                // -> { { v_i :: C, E, F} : S, H}
+                std::string f = std::to_string(ToInteger(act->results[1]));
+                auto a = FindField(f, *tuple->u.tuple.elts);
+                if (a == std::nullopt) {
+                  std::cerr << "runtime error, field " << f << " not in ";
+                  PrintValue(tuple, std::cerr);
+                  std::cerr << std::endl;
+                  exit(-1);
+                }
+                frame->todo = MakeCons(MakeValAct(state->heap[*a]),
+                                       frame->todo->next->next);
+                break;
+              }
+              default:
+                std::cerr
+                    << "runtime type error, expected a tuple in field access, "
+                       "not ";
+                PrintValue(tuple, std::cerr);
+                exit(-1);
+            }
+          }
+          break;
+        }
+        case ExpressionKind::GetField: {
+          //    { { v :: [].f :: C, E, F} :: S, H}
+          // -> { { v_f :: C, E, F} : S, H}
+          auto a = GetMember(ValToPtr(act->results[0], exp->line_num),
+                             *exp->u.get_field.field);
+          frame->todo =
+              MakeCons(MakeValAct(state->heap[a]), frame->todo->next->next);
+          break;
+        }
+        case ExpressionKind::PrimitiveOp: {
+          if (act->pos !=
+              static_cast<int>(exp->u.primitive_op.arguments->size())) {
+            //    { {v :: op(vs,[],e,es) :: C, E, F} :: S, H}
+            // -> { {e :: op(vs,v,[],es) :: C, E, F} :: S, H}
+            Expression* arg = (*exp->u.primitive_op.arguments)[act->pos];
+            frame->todo = MakeCons(MakeExpAct(arg), frame->todo->next);
+          } else {
+            //    { {v :: op(vs,[]) :: C, E, F} :: S, H}
+            // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H}
+            Value* v =
+                EvalPrim(exp->u.primitive_op.op, act->results, exp->line_num);
+            frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next);
+          }
+          break;
+        }
+        case ExpressionKind::Call: {
+          if (act->pos == 1) {
+            //    { { v :: [](e) :: C, E, F} :: S, H}
+            // -> { { e :: v([]) :: C, E, F} :: S, H}
+            frame->todo =
+                MakeCons(MakeExpAct(exp->u.call.argument), frame->todo->next);
+          } else if (act->pos == 2) {
+            //    { { v2 :: v1([]) :: C, E, F} :: S, H}
+            // -> { {C',E',F'} :: {C, E, F} :: S, H}
+            frame->todo = frame->todo->next->next;
+            CallFunction(exp->line_num, act->results, state);
+          } else {
+            std::cerr << "internal error in handle_value with Call"
+                      << std::endl;
+            exit(-1);
+          }
+          break;
+        }
+        case ExpressionKind::FunctionT: {
+          if (act->pos == 2) {
+            //    { { rt :: fn pt -> [] :: C, E, F} :: S, H}
+            // -> { fn pt -> rt :: {C, E, F} :: S, H}
+            Value* v = MakeFunTypeVal(act->results[0], act->results[1]);
+            frame->todo = MakeCons(MakeValAct(v), frame->todo->next->next);
+          } else {
+            //    { { pt :: fn [] -> e :: C, E, F} :: S, H}
+            // -> { { e :: fn pt -> []) :: C, E, F} :: S, H}
+            frame->todo = MakeCons(MakeExpAct(exp->u.function_type.return_type),
+                                   frame->todo->next);
+          }
+          break;
+        }
+        case ExpressionKind::Variable:
+        case ExpressionKind::Integer:
+        case ExpressionKind::Boolean:
+        case ExpressionKind::IntT:
+        case ExpressionKind::BoolT:
+        case ExpressionKind::TypeT:
+        case ExpressionKind::AutoT:
+          std::cerr << "internal error, bad expression context in handle_value"
+                    << std::endl;
+          exit(-1);
+      }
+      break;
+    }
+    case ActionKind::StatementAction: {
+      Statement* stmt = act->u.stmt;
+      switch (stmt->tag) {
+        case StatementKind::ExpressionStatement:
+          frame->todo = frame->todo->next->next;
+          break;
+        case StatementKind::VariableDefinition: {
+          if (act->pos == 1) {
+            frame->todo = MakeCons(MakeExpAct(stmt->u.variable_definition.pat),
+                                   frame->todo->next);
+          } else if (act->pos == 2) {
+            //    { { v :: (x = []) :: C, E, F} :: S, H}
+            // -> { { C, E(x := a), F} :: S, H(a := copy(v))}
+            Value* v = act->results[0];
+            Value* p = act->results[1];
+            // Address a = AllocateValue(CopyVal(v));
+            frame->scopes->curr->env =
+                PatternMatch(p, v, frame->scopes->curr->env,
+                             &frame->scopes->curr->locals, stmt->line_num);
+            if (!frame->scopes->curr->env) {
+              std::cerr
+                  << stmt->line_num
+                  << ": internal error in variable definition, match failed"
+                  << std::endl;
+              exit(-1);
+            }
+            frame->todo = frame->todo->next->next;
+          }
+          break;
+        }
+        case StatementKind::Assign:
+          if (act->pos == 1) {
+            //    { { a :: ([] = e) :: C, E, F} :: S, H}
+            // -> { { e :: (a = []) :: C, E, F} :: S, H}
+            frame->todo =
+                MakeCons(MakeExpAct(stmt->u.assign.rhs), frame->todo->next);
+          } else if (act->pos == 2) {
+            //    { { v :: (a = []) :: C, E, F} :: S, H}
+            // -> { { C, E, F} :: S, H(a := v)}
+            auto pat = act->results[0];
+            auto val = act->results[1];
+            PatternAssignment(pat, val, stmt->line_num);
+            frame->todo = frame->todo->next->next;
+          }
+          break;
+        case StatementKind::If:
+          if (ValToBool(act->results[0], stmt->line_num)) {
+            //    { {true :: if ([]) then_stmt else else_stmt :: C, E, F} ::
+            //      S, H}
+            // -> { { then_stmt :: C, E, F } :: S, H}
+            frame->todo = MakeCons(MakeStmtAct(stmt->u.if_stmt.then_stmt),
+                                   frame->todo->next->next);
+          } else {
+            //    { {false :: if ([]) then_stmt else else_stmt :: C, E, F} ::
+            //      S, H}
+            // -> { { else_stmt :: C, E, F } :: S, H}
+            frame->todo = MakeCons(MakeStmtAct(stmt->u.if_stmt.else_stmt),
+                                   frame->todo->next->next);
+          }
+          break;
+        case StatementKind::While:
+          if (ValToBool(act->results[0], stmt->line_num)) {
+            //    { {true :: (while ([]) s) :: C, E, F} :: S, H}
+            // -> { { s :: (while (e) s) :: C, E, F } :: S, H}
+            frame->todo->next->curr->pos = -1;
+            frame->todo->next->curr->results.clear();
+            frame->todo = MakeCons(MakeStmtAct(stmt->u.while_stmt.body),
+                                   frame->todo->next);
+          } else {
+            //    { {false :: (while ([]) s) :: C, E, F} :: S, H}
+            // -> { { C, E, F } :: S, H}
+            frame->todo->next->curr->pos = -1;
+            frame->todo->next->curr->results.clear();
+            frame->todo = frame->todo->next->next;
+          }
+          break;
+        case StatementKind::Match: {
+          // Regarding act->pos:
+          // * odd: start interpreting the pattern of a clause
+          // * even: finished interpreting the pattern, now try to match
+          //
+          // Regarding act->results:
+          // * 0: the value that we're matching
+          // * 1: the pattern for clause 0
+          // * 2: the pattern for clause 1
+          // * ...
+          auto clause_num = (act->pos - 1) / 2;
+          if (clause_num >=
+              static_cast<int>(stmt->u.match_stmt.clauses->size())) {
+            frame->todo = frame->todo->next->next;
+            break;
+          }
+          auto c = stmt->u.match_stmt.clauses->begin();
+          std::advance(c, clause_num);
+
+          if (act->pos % 2 == 1) {
+            // start interpreting the pattern of the clause
+            //    { {v :: (match ([]) ...) :: C, E, F} :: S, H}
+            // -> { {pi :: (match ([]) ...) :: C, E, F} :: S, H}
+            frame->todo = MakeCons(MakeExpAct(c->first), frame->todo->next);
+          } else {  // try to match
+            auto v = act->results[0];
+            auto pat = act->results[clause_num + 1];
+            auto env = CurrentEnv(state);
+            std::list<std::string> vars;
+            Env* new_env = PatternMatch(pat, v, env, &vars, stmt->line_num);
+            if (new_env) {  // we have a match, start the body
+              auto* new_scope = new Scope(new_env, vars);
+              frame->scopes = MakeCons(new_scope, frame->scopes);
+              Statement* body_block = MakeBlock(stmt->line_num, c->second);
+              Action* body_act = MakeStmtAct(body_block);
+              body_act->pos = 0;
+              frame->todo =
+                  MakeCons(MakeStmtAct(c->second),
+                           MakeCons(body_act, frame->todo->next->next));
+            } else {
+              act->pos++;
+              clause_num = (act->pos - 1) / 2;
+              if (clause_num <
+                  static_cast<int>(stmt->u.match_stmt.clauses->size())) {
+                // move on to the next clause
+                c = stmt->u.match_stmt.clauses->begin();
+                std::advance(c, clause_num);
+                frame->todo = MakeCons(MakeExpAct(c->first), frame->todo->next);
+              } else {  // No more clauses in match
+                frame->todo = frame->todo->next->next;
+              }
+            }
+          }
+          break;
+        }
+        case StatementKind::Return: {
+          //    { {v :: return [] :: C, E, F} :: {C', E', F'} :: S, H}
+          // -> { {v :: C', E', F'} :: S, H}
+          Value* ret_val = CopyVal(val_act->u.val, stmt->line_num);
+          KillLocals(stmt->line_num, frame);
+          state->stack = state->stack->next;
+          frame = state->stack->curr;
+          frame->todo = MakeCons(MakeValAct(ret_val), frame->todo);
+          break;
+        }
+        case StatementKind::Block:
+        case StatementKind::Sequence:
+        case StatementKind::Break:
+        case StatementKind::Continue:
+          std::cerr << "internal error in handle_value, unhandled statement ";
+          PrintStatement(stmt, 1);
+          std::cerr << std::endl;
+          exit(-1);
+      }  // switch stmt
+      break;
+    }
+    case ActionKind::ValAction:
+      std::cerr << "internal error, ValAction in handle_value" << std::endl;
+      exit(-1);
+  }  // switch act
+}
+
+// State transition.
+void Step() {
+  Frame* frame = state->stack->curr;
+  if (!frame->todo) {
+    std::cerr << "runtime error: fell off end of function " << frame->name
+              << " without `return`" << std::endl;
+    exit(-1);
+  }
+
+  Action* act = frame->todo->curr;
+  switch (act->tag) {
+    case ActionKind::DeleteTmpAction:
+      std::cerr << "internal error in step, did not expect DeleteTmpAction"
+                << std::endl;
+      break;
+    case ActionKind::ExpToLValAction:
+      std::cerr << "internal error in step, did not expect ExpToLValAction"
+                << std::endl;
+      break;
+    case ActionKind::ValAction:
+      HandleValue();
+      break;
+    case ActionKind::LValAction:
+      StepLvalue();
+      break;
+    case ActionKind::ExpressionAction:
+      StepExp();
+      break;
+    case ActionKind::StatementAction:
+      StepStmt();
+      break;
+  }  // switch
+}
+
+// Interpret the whole porogram.
+auto InterpProgram(std::list<Declaration*>* fs) -> int {
+  state = new State();  // Runtime state.
+  std::cout << "********** initializing globals **********" << std::endl;
+  InitGlobals(fs);
+
+  Expression* arg =
+      MakeTuple(0, new std::vector<std::pair<std::string, Expression*>>());
+  Expression* call_main = MakeCall(0, MakeVar(0, "main"), arg);
+  Cons<Action*>* todo = MakeCons(MakeExpAct(call_main));
+  auto* scope = new Scope(globals, std::list<std::string>());
+  auto* frame = new Frame("top", MakeCons(scope), todo);
+  state->stack = MakeCons(frame);
+
+  std::cout << "********** calling main function **********" << std::endl;
+  PrintState(std::cout);
+
+  while (Length(state->stack) > 1 || Length(state->stack->curr->todo) > 1 ||
+         state->stack->curr->todo->curr->tag != ActionKind::ValAction) {
+    Step();
+    PrintState(std::cout);
+  }
+  Value* v = state->stack->curr->todo->curr->u.val;
+  return ValToInt(v, 0);
+}
+
+// Interpret an expression at compile-time.
+auto InterpExp(Env* env, Expression* e) -> Value* {
+  Cons<Action*>* todo = MakeCons(MakeExpAct(e));
+  auto* scope = new Scope(env, std::list<std::string>());
+  auto* frame = new Frame("InterpExp", MakeCons(scope), todo);
+  state->stack = MakeCons(frame);
+
+  while (Length(state->stack) > 1 || Length(state->stack->curr->todo) > 1 ||
+         state->stack->curr->todo->curr->tag != ActionKind::ValAction) {
+    Step();
+  }
+  Value* v = state->stack->curr->todo->curr->u.val;
+  return v;
+}
+
+}  // namespace Carbon

+ 60 - 0
executable_semantics/interpreter/interpreter.h

@@ -0,0 +1,60 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_INTERPRETER_H_
+#define EXECUTABLE_SEMANTICS_INTERPRETER_INTERPRETER_H_
+
+#include <list>
+#include <utility>
+#include <vector>
+
+#include "executable_semantics/ast/declaration.h"
+#include "executable_semantics/interpreter/action.h"
+#include "executable_semantics/interpreter/assoc_list.h"
+#include "executable_semantics/interpreter/cons_list.h"
+#include "executable_semantics/interpreter/value.h"
+
+namespace Carbon {
+
+using Env = AssocList<std::string, Address>;
+
+/***** Scopes *****/
+
+struct Scope {
+  Scope(Env* e, std::list<std::string> l) : env(e), locals(std::move(l)) {}
+  Env* env;
+  std::list<std::string> locals;
+};
+
+/***** Frames and State *****/
+
+struct Frame {
+  std::string name;
+  Cons<Scope*>* scopes;
+  Cons<Action*>* todo;
+
+  Frame(std::string n, Cons<Scope*>* s, Cons<Action*>* c)
+      : name(std::move(std::move(n))), scopes(s), todo(c) {}
+};
+
+struct State {
+  Cons<Frame*>* stack;
+  std::vector<Value*> heap;
+};
+
+extern State* state;
+
+void PrintEnv(Env* env);
+auto AllocateValue(Value* v) -> Address;
+auto CopyVal(Value* val, int line_num) -> Value*;
+auto ToInteger(Value* v) -> int;
+
+/***** Interpreters *****/
+
+auto InterpProgram(std::list<Declaration*>* fs) -> int;
+auto InterpExp(Env* env, Expression* e) -> Value*;
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_INTERPRETER_INTERPRETER_H_

+ 680 - 0
executable_semantics/interpreter/typecheck.cpp

@@ -0,0 +1,680 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/interpreter/typecheck.h"
+
+#include <iostream>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "executable_semantics/ast/function_definition.h"
+#include "executable_semantics/interpreter/cons_list.h"
+#include "executable_semantics/interpreter/interpreter.h"
+
+namespace Carbon {
+
+auto Find(const std::string& s, Cons<std::string>* ls, int n) -> int {
+  if (ls) {
+    if (ls->curr == s) {
+      return n;
+    } else {
+      return Find(s, ls->next, n + 1);
+    }
+  } else {
+    std::cerr << "could not find " << s << std::endl;
+    exit(-1);
+  }
+}
+
+void ExpectType(int line_num, const std::string& context, Value* expected,
+                Value* actual) {
+  if (!TypeEqual(expected, actual)) {
+    std::cerr << line_num << ": type error in " << context << std::endl;
+    std::cerr << "expected: ";
+    PrintValue(expected, std::cerr);
+    std::cerr << std::endl << "actual: ";
+    PrintValue(actual, std::cerr);
+    std::cerr << std::endl;
+    exit(-1);
+  }
+}
+
+void PrintErrorString(const std::string& s) { std::cerr << s; }
+
+void PrintTypeEnv(TypeEnv* env, std::ostream& out) {
+  if (env) {
+    out << env->key << ": ";
+    PrintValue(env->value, out);
+    out << ", ";
+    PrintTypeEnv(env->next, out);
+  }
+}
+
+// Convert tuples to tuple types.
+auto ToType(int line_num, Value* val) -> Value* {
+  switch (val->tag) {
+    case ValKind::TupleV: {
+      auto fields = new VarValues();
+      for (auto& elt : *val->u.tuple.elts) {
+        Value* ty = ToType(line_num, state->heap[elt.second]);
+        fields->push_back(std::make_pair(elt.first, ty));
+      }
+      return MakeTupleTypeVal(fields);
+    }
+    case ValKind::TupleTV: {
+      auto fields = new VarValues();
+      for (auto& field : *val->u.tuple_type.fields) {
+        Value* ty = ToType(line_num, field.second);
+        fields->push_back(std::make_pair(field.first, ty));
+      }
+      return MakeTupleTypeVal(fields);
+    }
+    case ValKind::PointerTV: {
+      return MakePtrTypeVal(ToType(line_num, val->u.ptr_type.type));
+    }
+    case ValKind::FunctionTV: {
+      return MakeFunTypeVal(ToType(line_num, val->u.fun_type.param),
+                            ToType(line_num, val->u.fun_type.ret));
+    }
+    case ValKind::VarPatV: {
+      return MakeVarPatVal(*val->u.var_pat.name,
+                           ToType(line_num, val->u.var_pat.type));
+    }
+    case ValKind::ChoiceTV:
+    case ValKind::StructTV:
+    case ValKind::TypeTV:
+    case ValKind::VarTV:
+    case ValKind::BoolTV:
+    case ValKind::IntTV:
+    case ValKind::AutoTV:
+      return val;
+    default:
+      std::cerr << line_num << ": in ToType, expected a type, not ";
+      PrintValue(val, std::cerr);
+      std::cerr << std::endl;
+      exit(-1);
+  }
+}
+
+// Reify type to type expression.
+auto ReifyType(Value* t, int line_num) -> Expression* {
+  switch (t->tag) {
+    case ValKind::VarTV:
+      return MakeVar(0, *t->u.var_type);
+    case ValKind::IntTV:
+      return MakeIntType(0);
+    case ValKind::BoolTV:
+      return MakeBoolType(0);
+    case ValKind::TypeTV:
+      return MakeTypeType(0);
+    case ValKind::FunctionTV:
+      return MakeFunType(0, ReifyType(t->u.fun_type.param, line_num),
+                         ReifyType(t->u.fun_type.ret, line_num));
+    case ValKind::TupleTV: {
+      auto args = new std::vector<std::pair<std::string, Expression*>>();
+      for (auto& field : *t->u.tuple_type.fields) {
+        args->push_back(
+            make_pair(field.first, ReifyType(field.second, line_num)));
+      }
+      return MakeTuple(0, args);
+    }
+    case ValKind::StructTV:
+      return MakeVar(0, *t->u.struct_type.name);
+    case ValKind::ChoiceTV:
+      return MakeVar(0, *t->u.choice_type.name);
+    default:
+      std::cerr << line_num << ": expected a type, not ";
+      PrintValue(t, std::cerr);
+      std::cerr << std::endl;
+      exit(-1);
+  }
+}
+
+auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected,
+                  TCContext context)
+    -> TCResult {  //                   expected can be null
+  switch (e->tag) {
+    case ExpressionKind::PatternVariable: {
+      if (context != TCContext::PatternContext) {
+        std::cerr
+            << e->line_num
+            << ": compilation error, pattern variables are only allowed in "
+               "pattern context"
+            << std::endl;
+      }
+      auto t =
+          ToType(e->line_num, InterpExp(ct_env, e->u.pattern_variable.type));
+      if (t->tag == ValKind::AutoTV) {
+        if (expected == nullptr) {
+          std::cerr << e->line_num
+                    << ": compilation error, auto not allowed here"
+                    << std::endl;
+          exit(-1);
+        } else {
+          t = expected;
+        }
+      }
+      auto new_e = MakeVarPat(e->line_num, *e->u.pattern_variable.name,
+                              ReifyType(t, e->line_num));
+      return TCResult(new_e, t,
+                      new TypeEnv(*e->u.pattern_variable.name, t, env));
+    }
+    case ExpressionKind::Index: {
+      auto res = TypeCheckExp(e->u.get_field.aggregate, env, ct_env, nullptr,
+                              TCContext::ValueContext);
+      auto t = res.type;
+      switch (t->tag) {
+        case ValKind::TupleTV: {
+          auto i = ToInteger(InterpExp(ct_env, e->u.index.offset));
+          std::string f = std::to_string(i);
+          auto field_t = FindInVarValues(f, t->u.tuple_type.fields);
+          if (field_t == nullptr) {
+            std::cerr << e->line_num << ": compilation error, field " << f
+                      << " is not in the tuple ";
+            PrintValue(t, std::cerr);
+            std::cerr << std::endl;
+            exit(-1);
+          }
+          auto new_e = MakeIndex(e->line_num, res.exp, MakeInt(e->line_num, i));
+          return TCResult(new_e, field_t, res.env);
+        }
+        default:
+          std::cerr << e->line_num << ": compilation error, expected a tuple"
+                    << std::endl;
+          exit(-1);
+      }
+    }
+    case ExpressionKind::Tuple: {
+      auto new_args = new std::vector<std::pair<std::string, Expression*>>();
+      auto arg_types = new VarValues();
+      auto new_env = env;
+      int i = 0;
+      for (auto arg = e->u.tuple.fields->begin();
+           arg != e->u.tuple.fields->end(); ++arg, ++i) {
+        Value* arg_expected = nullptr;
+        if (expected && expected->tag == ValKind::TupleTV) {
+          arg_expected =
+              FindInVarValues(arg->first, expected->u.tuple_type.fields);
+          if (arg_expected == nullptr) {
+            std::cerr << e->line_num << ": compilation error, missing field "
+                      << arg->first << std::endl;
+            exit(-1);
+          }
+        }
+        auto arg_res =
+            TypeCheckExp(arg->second, new_env, ct_env, arg_expected, context);
+        new_env = arg_res.env;
+        new_args->push_back(std::make_pair(arg->first, arg_res.exp));
+        arg_types->push_back(std::make_pair(arg->first, arg_res.type));
+      }
+      auto tuple_e = MakeTuple(e->line_num, new_args);
+      auto tuple_t = MakeTupleTypeVal(arg_types);
+      return TCResult(tuple_e, tuple_t, new_env);
+    }
+    case ExpressionKind::GetField: {
+      auto res = TypeCheckExp(e->u.get_field.aggregate, env, ct_env, nullptr,
+                              TCContext::ValueContext);
+      auto t = res.type;
+      switch (t->tag) {
+        case ValKind::StructTV:
+          // Search for a field
+          for (auto& field : *t->u.struct_type.fields) {
+            if (*e->u.get_field.field == field.first) {
+              Expression* new_e =
+                  MakeGetField(e->line_num, res.exp, *e->u.get_field.field);
+              return TCResult(new_e, field.second, res.env);
+            }
+          }
+          // Search for a method
+          for (auto& method : *t->u.struct_type.methods) {
+            if (*e->u.get_field.field == method.first) {
+              Expression* new_e =
+                  MakeGetField(e->line_num, res.exp, *e->u.get_field.field);
+              return TCResult(new_e, method.second, res.env);
+            }
+          }
+          std::cerr << e->line_num << ": compilation error, struct "
+                    << *t->u.struct_type.name << " does not have a field named "
+                    << *e->u.get_field.field << std::endl;
+          exit(-1);
+        case ValKind::TupleTV:
+          for (auto& field : *t->u.tuple_type.fields) {
+            if (*e->u.get_field.field == field.first) {
+              auto new_e =
+                  MakeGetField(e->line_num, res.exp, *e->u.get_field.field);
+              return TCResult(new_e, field.second, res.env);
+            }
+          }
+          std::cerr << e->line_num << ": compilation error, struct "
+                    << *t->u.struct_type.name << " does not have a field named "
+                    << *e->u.get_field.field << std::endl;
+          exit(-1);
+        case ValKind::ChoiceTV:
+          for (auto vt = t->u.choice_type.alternatives->begin();
+               vt != t->u.choice_type.alternatives->end(); ++vt) {
+            if (*e->u.get_field.field == vt->first) {
+              Expression* new_e =
+                  MakeGetField(e->line_num, res.exp, *e->u.get_field.field);
+              auto fun_ty = MakeFunTypeVal(vt->second, t);
+              return TCResult(new_e, fun_ty, res.env);
+            }
+          }
+          std::cerr << e->line_num << ": compilation error, struct "
+                    << *t->u.struct_type.name << " does not have a field named "
+                    << *e->u.get_field.field << std::endl;
+          exit(-1);
+
+        default:
+          std::cerr << e->line_num
+                    << ": compilation error in field access, expected a struct"
+                    << std::endl;
+          PrintExp(e);
+          std::cerr << std::endl;
+          exit(-1);
+      }
+    }
+    case ExpressionKind::Variable: {
+      auto t =
+          Lookup(e->line_num, env, *(e->u.variable.name), PrintErrorString);
+      return TCResult(e, t, env);
+    }
+    case ExpressionKind::Integer:
+      return TCResult(e, MakeIntTypeVal(), env);
+    case ExpressionKind::Boolean:
+      return TCResult(e, MakeBoolTypeVal(), env);
+    case ExpressionKind::PrimitiveOp: {
+      auto es = new std::vector<Expression*>();
+      std::vector<Value*> ts;
+      auto new_env = env;
+      for (auto& argument : *e->u.primitive_op.arguments) {
+        auto res = TypeCheckExp(argument, env, ct_env, nullptr,
+                                TCContext::ValueContext);
+        new_env = res.env;
+        es->push_back(res.exp);
+        ts.push_back(res.type);
+      }
+      auto new_e = MakeOp(e->line_num, e->u.primitive_op.op, es);
+      switch (e->u.primitive_op.op) {
+        case Operator::Neg:
+          ExpectType(e->line_num, "negation", MakeIntTypeVal(), ts[0]);
+          return TCResult(new_e, MakeIntTypeVal(), new_env);
+        case Operator::Add:
+        case Operator::Sub:
+          ExpectType(e->line_num, "subtraction(1)", MakeIntTypeVal(), ts[0]);
+          ExpectType(e->line_num, "substration(2)", MakeIntTypeVal(), ts[1]);
+          return TCResult(new_e, MakeIntTypeVal(), new_env);
+        case Operator::And:
+          ExpectType(e->line_num, "&&(1)", MakeBoolTypeVal(), ts[0]);
+          ExpectType(e->line_num, "&&(2)", MakeBoolTypeVal(), ts[1]);
+          return TCResult(new_e, MakeBoolTypeVal(), new_env);
+        case Operator::Or:
+          ExpectType(e->line_num, "||(1)", MakeBoolTypeVal(), ts[0]);
+          ExpectType(e->line_num, "||(2)", MakeBoolTypeVal(), ts[1]);
+          return TCResult(new_e, MakeBoolTypeVal(), new_env);
+        case Operator::Not:
+          ExpectType(e->line_num, "!", MakeBoolTypeVal(), ts[0]);
+          return TCResult(new_e, MakeBoolTypeVal(), new_env);
+        case Operator::Eq:
+          ExpectType(e->line_num, "==(1)", MakeIntTypeVal(), ts[0]);
+          ExpectType(e->line_num, "==(2)", MakeIntTypeVal(), ts[1]);
+          return TCResult(new_e, MakeBoolTypeVal(), new_env);
+      }
+      break;
+    }
+    case ExpressionKind::Call: {
+      auto fun_res = TypeCheckExp(e->u.call.function, env, ct_env, nullptr,
+                                  TCContext::ValueContext);
+      switch (fun_res.type->tag) {
+        case ValKind::FunctionTV: {
+          auto fun_t = fun_res.type;
+          auto arg_res =
+              TypeCheckExp(e->u.call.argument, fun_res.env, ct_env,
+                           fun_t->u.fun_type.param, TCContext::ValueContext);
+          ExpectType(e->line_num, "call", fun_t->u.fun_type.param,
+                     arg_res.type);
+          auto new_e = MakeCall(e->line_num, fun_res.exp, arg_res.exp);
+          return TCResult(new_e, fun_t->u.fun_type.ret, arg_res.env);
+        }
+        default: {
+          std::cerr << e->line_num
+                    << ": compilation error in call, expected a function"
+                    << std::endl;
+          PrintExp(e);
+          std::cerr << std::endl;
+          exit(-1);
+        }
+      }
+      break;
+    }
+    case ExpressionKind::FunctionT: {
+      switch (context) {
+        case TCContext::ValueContext:
+        case TCContext::TypeContext: {
+          auto pt = ToType(e->line_num,
+                           InterpExp(ct_env, e->u.function_type.parameter));
+          auto rt = ToType(e->line_num,
+                           InterpExp(ct_env, e->u.function_type.return_type));
+          auto new_e = MakeFunType(e->line_num, ReifyType(pt, e->line_num),
+                                   ReifyType(rt, e->line_num));
+          return TCResult(new_e, MakeTypeTypeVal(), env);
+        }
+        case TCContext::PatternContext: {
+          auto param_res = TypeCheckExp(e->u.function_type.parameter, env,
+                                        ct_env, nullptr, context);
+          auto ret_res = TypeCheckExp(e->u.function_type.return_type,
+                                      param_res.env, ct_env, nullptr, context);
+          auto new_e =
+              MakeFunType(e->line_num, ReifyType(param_res.type, e->line_num),
+                          ReifyType(ret_res.type, e->line_num));
+          return TCResult(new_e, MakeTypeTypeVal(), ret_res.env);
+        }
+      }
+    }
+    case ExpressionKind::IntT:
+    case ExpressionKind::BoolT:
+    case ExpressionKind::TypeT:
+    case ExpressionKind::AutoT:
+      return TCResult(e, MakeTypeTypeVal(), env);
+  }
+}
+
+auto TypecheckCase(Value* expected, Expression* pat, Statement* body,
+                   TypeEnv* env, Env* ct_env, Value* ret_type)
+    -> std::pair<Expression*, Statement*> {
+  auto pat_res =
+      TypeCheckExp(pat, env, ct_env, expected, TCContext::PatternContext);
+  auto res = TypeCheckStmt(body, pat_res.env, ct_env, ret_type);
+  return std::make_pair(pat, res.stmt);
+}
+
+auto TypeCheckStmt(Statement* s, TypeEnv* env, Env* ct_env, Value* ret_type)
+    -> TCStatement {
+  if (!s) {
+    return TCStatement(s, env);
+  }
+  switch (s->tag) {
+    case StatementKind::Match: {
+      auto res = TypeCheckExp(s->u.match_stmt.exp, env, ct_env, nullptr,
+                              TCContext::ValueContext);
+      auto res_type = res.type;
+      auto new_clauses = new std::list<std::pair<Expression*, Statement*>>();
+      for (auto& clause : *s->u.match_stmt.clauses) {
+        new_clauses->push_back(TypecheckCase(
+            res_type, clause.first, clause.second, env, ct_env, ret_type));
+      }
+      Statement* new_s = MakeMatch(s->line_num, res.exp, new_clauses);
+      return TCStatement(new_s, env);
+    }
+    case StatementKind::While: {
+      auto cnd_res = TypeCheckExp(s->u.while_stmt.cond, env, ct_env, nullptr,
+                                  TCContext::ValueContext);
+      ExpectType(s->line_num, "condition of `while`", MakeBoolTypeVal(),
+                 cnd_res.type);
+      auto body_res =
+          TypeCheckStmt(s->u.while_stmt.body, env, ct_env, ret_type);
+      auto new_s = MakeWhile(s->line_num, cnd_res.exp, body_res.stmt);
+      return TCStatement(new_s, env);
+    }
+    case StatementKind::Break:
+    case StatementKind::Continue:
+      return TCStatement(s, env);
+    case StatementKind::Block: {
+      auto stmt_res = TypeCheckStmt(s->u.block.stmt, env, ct_env, ret_type);
+      return TCStatement(MakeBlock(s->line_num, stmt_res.stmt), env);
+    }
+    case StatementKind::VariableDefinition: {
+      auto res = TypeCheckExp(s->u.variable_definition.init, env, ct_env,
+                              nullptr, TCContext::ValueContext);
+      Value* rhs_ty = res.type;
+      auto lhs_res = TypeCheckExp(s->u.variable_definition.pat, env, ct_env,
+                                  rhs_ty, TCContext::PatternContext);
+      Statement* new_s =
+          MakeVarDef(s->line_num, s->u.variable_definition.pat, res.exp);
+      return TCStatement(new_s, lhs_res.env);
+    }
+    case StatementKind::Sequence: {
+      auto stmt_res = TypeCheckStmt(s->u.sequence.stmt, env, ct_env, ret_type);
+      auto env2 = stmt_res.env;
+      auto next_res = TypeCheckStmt(s->u.sequence.next, env2, ct_env, ret_type);
+      auto env3 = next_res.env;
+      return TCStatement(MakeSeq(s->line_num, stmt_res.stmt, next_res.stmt),
+                         env3);
+    }
+    case StatementKind::Assign: {
+      auto rhs_res = TypeCheckExp(s->u.assign.rhs, env, ct_env, nullptr,
+                                  TCContext::ValueContext);
+      auto rhs_t = rhs_res.type;
+      auto lhs_res = TypeCheckExp(s->u.assign.lhs, env, ct_env, rhs_t,
+                                  TCContext::ValueContext);
+      auto lhs_t = lhs_res.type;
+      ExpectType(s->line_num, "assign", lhs_t, rhs_t);
+      auto new_s = MakeAssign(s->line_num, lhs_res.exp, rhs_res.exp);
+      return TCStatement(new_s, lhs_res.env);
+    }
+    case StatementKind::ExpressionStatement: {
+      auto res =
+          TypeCheckExp(s->u.exp, env, ct_env, nullptr, TCContext::ValueContext);
+      auto new_s = MakeExpStmt(s->line_num, res.exp);
+      return TCStatement(new_s, env);
+    }
+    case StatementKind::If: {
+      auto cnd_res = TypeCheckExp(s->u.if_stmt.cond, env, ct_env, nullptr,
+                                  TCContext::ValueContext);
+      ExpectType(s->line_num, "condition of `if`", MakeBoolTypeVal(),
+                 cnd_res.type);
+      auto thn_res =
+          TypeCheckStmt(s->u.if_stmt.then_stmt, env, ct_env, ret_type);
+      auto els_res =
+          TypeCheckStmt(s->u.if_stmt.else_stmt, env, ct_env, ret_type);
+      auto new_s = MakeIf(s->line_num, cnd_res.exp, thn_res.stmt, els_res.stmt);
+      return TCStatement(new_s, env);
+    }
+    case StatementKind::Return: {
+      auto res = TypeCheckExp(s->u.return_stmt, env, ct_env, nullptr,
+                              TCContext::ValueContext);
+      if (ret_type->tag == ValKind::AutoTV) {
+        // The following infers the return type from the first 'return'
+        // statement. This will get more difficult with subtyping, when we
+        // should infer the least-upper bound of all the 'return' statements.
+        *ret_type = *res.type;
+      } else {
+        ExpectType(s->line_num, "return", ret_type, res.type);
+      }
+      return TCStatement(MakeReturn(s->line_num, res.exp), env);
+    }
+  }
+}
+
+auto CheckOrEnsureReturn(Statement* stmt, bool void_return, int line_num)
+    -> Statement* {
+  if (!stmt) {
+    if (void_return) {
+      auto args = new std::vector<std::pair<std::string, Expression*>>();
+      return MakeReturn(line_num, MakeTuple(line_num, args));
+    } else {
+      std::cerr
+          << "control-flow reaches end of non-void function without a return"
+          << std::endl;
+      exit(-1);
+    }
+  }
+  switch (stmt->tag) {
+    case StatementKind::Match: {
+      auto new_clauses = new std::list<std::pair<Expression*, Statement*>>();
+      for (auto i = stmt->u.match_stmt.clauses->begin();
+           i != stmt->u.match_stmt.clauses->end(); ++i) {
+        auto s = CheckOrEnsureReturn(i->second, void_return, stmt->line_num);
+        new_clauses->push_back(std::make_pair(i->first, s));
+      }
+      return MakeMatch(stmt->line_num, stmt->u.match_stmt.exp, new_clauses);
+    }
+    case StatementKind::Block:
+      return MakeBlock(
+          stmt->line_num,
+          CheckOrEnsureReturn(stmt->u.block.stmt, void_return, stmt->line_num));
+    case StatementKind::If:
+      return MakeIf(stmt->line_num, stmt->u.if_stmt.cond,
+                    CheckOrEnsureReturn(stmt->u.if_stmt.then_stmt, void_return,
+                                        stmt->line_num),
+                    CheckOrEnsureReturn(stmt->u.if_stmt.else_stmt, void_return,
+                                        stmt->line_num));
+    case StatementKind::Return:
+      return stmt;
+    case StatementKind::Sequence:
+      if (stmt->u.sequence.next) {
+        return MakeSeq(stmt->line_num, stmt->u.sequence.stmt,
+                       CheckOrEnsureReturn(stmt->u.sequence.next, void_return,
+                                           stmt->line_num));
+      } else {
+        return CheckOrEnsureReturn(stmt->u.sequence.stmt, void_return,
+                                   stmt->line_num);
+      }
+    case StatementKind::Assign:
+    case StatementKind::ExpressionStatement:
+    case StatementKind::While:
+    case StatementKind::Break:
+    case StatementKind::Continue:
+    case StatementKind::VariableDefinition:
+      if (void_return) {
+        auto args = new std::vector<std::pair<std::string, Expression*>>();
+        return MakeSeq(
+            stmt->line_num, stmt,
+            MakeReturn(stmt->line_num, MakeTuple(stmt->line_num, args)));
+      } else {
+        std::cerr
+            << stmt->line_num
+            << ": control-flow reaches end of non-void function without a "
+               "return"
+            << std::endl;
+        exit(-1);
+      }
+  }
+}
+
+auto TypeCheckFunDef(struct FunctionDefinition* f, TypeEnv* env, Env* ct_env)
+    -> struct FunctionDefinition* {
+  auto param_res = TypeCheckExp(f->param_pattern, env, ct_env, nullptr,
+                                TCContext::PatternContext);
+  auto return_type = ToType(f->line_num, InterpExp(ct_env, f->return_type));
+  if (f->name == "main") {
+    ExpectType(f->line_num, "return type of `main`", MakeIntTypeVal(),
+               return_type);
+    // TODO: Check that main doesn't have any parameters.
+  }
+  auto res = TypeCheckStmt(f->body, param_res.env, ct_env, return_type);
+  bool void_return = TypeEqual(return_type, MakeVoidTypeVal());
+  auto body = CheckOrEnsureReturn(res.stmt, void_return, f->line_num);
+  return MakeFunDef(f->line_num, f->name, ReifyType(return_type, f->line_num),
+                    f->param_pattern, body);
+}
+
+auto TypeOfFunDef(TypeEnv* env, Env* ct_env, struct FunctionDefinition* fun_def)
+    -> Value* {
+  auto param_res = TypeCheckExp(fun_def->param_pattern, env, ct_env, nullptr,
+                                TCContext::PatternContext);
+  auto param_type = ToType(fun_def->line_num, param_res.type);
+  auto ret = InterpExp(ct_env, fun_def->return_type);
+  if (ret->tag == ValKind::AutoTV) {
+    auto f = TypeCheckFunDef(fun_def, env, ct_env);
+    ret = InterpExp(ct_env, f->return_type);
+  }
+  return MakeFunTypeVal(param_type, ret);
+}
+
+auto TypeOfStructDef(struct StructDefinition* sd, TypeEnv* /*env*/, Env* ct_top)
+    -> Value* {
+  auto fields = new VarValues();
+  auto methods = new VarValues();
+  for (auto m = sd->members->begin(); m != sd->members->end(); ++m) {
+    if ((*m)->tag == MemberKind::FieldMember) {
+      auto t = ToType(sd->line_num, InterpExp(ct_top, (*m)->u.field.type));
+      fields->push_back(std::make_pair(*(*m)->u.field.name, t));
+    }
+  }
+  return MakeStructTypeVal(*sd->name, fields, methods);
+}
+
+auto NameOfDecl(Declaration* d) -> std::string {
+  switch (d->tag) {
+    case DeclarationKind::FunctionDeclaration:
+      return d->u.fun_def->name;
+    case DeclarationKind::StructDeclaration:
+      return *d->u.struct_def->name;
+    case DeclarationKind::ChoiceDeclaration:
+      return *d->u.choice_def.name;
+  }
+}
+
+auto TypeCheckDecl(Declaration* d, TypeEnv* env, Env* ct_env) -> Declaration* {
+  switch (d->tag) {
+    case DeclarationKind::StructDeclaration: {
+      auto members = new std::list<Member*>();
+      for (auto& member : *d->u.struct_def->members) {
+        switch (member->tag) {
+          case MemberKind::FieldMember: {
+            // TODO: Interpret the type expression and store the result.
+            members->push_back(member);
+            break;
+          }
+        }
+      }
+      return MakeStructDecl(d->u.struct_def->line_num, *d->u.struct_def->name,
+                            members);
+    }
+    case DeclarationKind::FunctionDeclaration:
+      return MakeFunDecl(TypeCheckFunDef(d->u.fun_def, env, ct_env));
+    case DeclarationKind::ChoiceDeclaration:
+      return d;  // TODO.
+  }
+}
+
+auto TopLevel(std::list<Declaration*>* fs) -> std::pair<TypeEnv*, Env*> {
+  TypeEnv* top = nullptr;
+  Env* ct_top = nullptr;
+  bool found_main = false;
+  for (auto d : *fs) {
+    if (NameOfDecl(d) == "main") {
+      found_main = true;
+    }
+    switch (d->tag) {
+      case DeclarationKind::FunctionDeclaration: {
+        auto t = TypeOfFunDef(top, ct_top, d->u.fun_def);
+        top = new TypeEnv(NameOfDecl(d), t, top);
+        break;
+      }
+      case DeclarationKind::StructDeclaration: {
+        auto st = TypeOfStructDef(d->u.struct_def, top, ct_top);
+        Address a = AllocateValue(st);
+        ct_top = new Env(NameOfDecl(d), a, ct_top);  // Is this obsolete?
+        auto params = MakeTupleTypeVal(st->u.struct_type.fields);
+        auto fun_ty = MakeFunTypeVal(params, st);
+        top = new TypeEnv(NameOfDecl(d), fun_ty, top);
+        break;
+      }
+      case DeclarationKind::ChoiceDeclaration: {
+        auto alts = new VarValues();
+        for (auto i = d->u.choice_def.alternatives->begin();
+             i != d->u.choice_def.alternatives->end(); ++i) {
+          auto t =
+              ToType(d->u.choice_def.line_num, InterpExp(ct_top, i->second));
+          alts->push_back(std::make_pair(i->first, t));
+        }
+        auto ct = MakeChoiceTypeVal(d->u.choice_def.name, alts);
+        Address a = AllocateValue(ct);
+        ct_top = new Env(NameOfDecl(d), a, ct_top);  // Is this obsolete?
+        top = new TypeEnv(NameOfDecl(d), ct, top);
+        break;
+      }
+    }  // switch (d->tag)
+  }    // for
+  if (found_main == false) {
+    std::cerr << "error, program must contain a function named `main`"
+              << std::endl;
+    exit(-1);
+  }
+  return make_pair(top, ct_top);
+}
+
+}  // namespace Carbon

+ 56 - 0
executable_semantics/interpreter/typecheck.h

@@ -0,0 +1,56 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_TYPECHECK_H_
+#define EXECUTABLE_SEMANTICS_INTERPRETER_TYPECHECK_H_
+
+#include <set>
+
+#include "executable_semantics/ast/expression.h"
+#include "executable_semantics/ast/statement.h"
+#include "executable_semantics/interpreter/assoc_list.h"
+#include "executable_semantics/interpreter/interpreter.h"
+
+namespace Carbon {
+
+using TypeEnv = AssocList<std::string, Value*>;
+
+void PrintTypeEnv(TypeEnv* env);
+
+enum class TCContext { ValueContext, PatternContext, TypeContext };
+
+struct TCResult {
+  TCResult(Expression* e, Value* t, TypeEnv* env) : exp(e), type(t), env(env) {}
+
+  Expression* exp;
+  Value* type;
+  TypeEnv* env;
+};
+
+struct TCStatement {
+  TCStatement(Statement* s, TypeEnv* e) : stmt(s), env(e) {}
+
+  Statement* stmt;
+  TypeEnv* env;
+};
+
+auto ToType(int line_num, Value* val) -> Value*;
+
+auto TypeCheckExp(Expression* e, TypeEnv* env, Env* ct_env, Value* expected,
+                  TCContext context) -> TCResult;
+
+auto TypeCheckStmt(Statement*, TypeEnv*, Env*, Value*) -> TCStatement;
+
+auto TypeCheckFunDef(struct FunctionDefinition*, TypeEnv*)
+    -> struct FunctionDefinition*;
+
+auto TypeCheckDecl(Declaration* d, TypeEnv* env, Env* ct_env) -> Declaration*;
+
+auto TopLevel(std::list<Declaration*>* fs) -> std::pair<TypeEnv*, Env*>;
+
+void PrintErrorString(const std::string& s);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_INTERPRETER_TYPECHECK_H_

+ 402 - 0
executable_semantics/interpreter/value.cpp

@@ -0,0 +1,402 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/interpreter/value.h"
+
+#include <iostream>
+
+#include "executable_semantics/interpreter/interpreter.h"
+
+namespace Carbon {
+
+auto FindInVarValues(const std::string& field, VarValues* inits) -> Value* {
+  for (auto& i : *inits) {
+    if (i.first == field) {
+      return i.second;
+    }
+  }
+  return nullptr;
+}
+
+auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool {
+  if (ts1->size() == ts2->size()) {
+    for (auto& iter1 : *ts1) {
+      auto t2 = FindInVarValues(iter1.first, ts2);
+      if (t2 == nullptr) {
+        return false;
+      }
+      if (!TypeEqual(iter1.second, t2)) {
+        return false;
+      }
+    }
+    return true;
+  } else {
+    return false;
+  }
+}
+
+auto MakeIntVal(int i) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::IntV;
+  v->u.integer = i;
+  return v;
+}
+
+auto MakeBoolVal(bool b) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::BoolV;
+  v->u.boolean = b;
+  return v;
+}
+
+auto MakeFunVal(std::string name, Value* param, Statement* body) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::FunV;
+  v->u.fun.name = new std::string(std::move(name));
+  v->u.fun.param = param;
+  v->u.fun.body = body;
+  return v;
+}
+
+auto MakePtrVal(Address addr) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::PtrV;
+  v->u.ptr = addr;
+  return v;
+}
+
+auto MakeStructVal(Value* type, Value* inits) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::StructV;
+  v->u.struct_val.type = type;
+  v->u.struct_val.inits = inits;
+  return v;
+}
+
+auto MakeTupleVal(std::vector<std::pair<std::string, Address>>* elts)
+    -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::TupleV;
+  v->u.tuple.elts = elts;
+  return v;
+}
+
+auto MakeAltVal(std::string alt_name, std::string choice_name, Value* arg)
+    -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::AltV;
+  v->u.alt.alt_name = new std::string(std::move(alt_name));
+  v->u.alt.choice_name = new std::string(std::move(choice_name));
+  v->u.alt.arg = arg;
+  return v;
+}
+
+auto MakeAltCons(std::string alt_name, std::string choice_name) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::AltConsV;
+  v->u.alt.alt_name = new std::string(std::move(alt_name));
+  v->u.alt.choice_name = new std::string(std::move(choice_name));
+  return v;
+}
+
+auto MakeVarPatVal(std::string name, Value* type) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::VarPatV;
+  v->u.var_pat.name = new std::string(std::move(name));
+  v->u.var_pat.type = type;
+  return v;
+}
+
+auto MakeVarTypeVal(std::string name) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::VarTV;
+  v->u.var_type = new std::string(std::move(name));
+  return v;
+}
+
+auto MakeIntTypeVal() -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::IntTV;
+  return v;
+}
+
+auto MakeBoolTypeVal() -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::BoolTV;
+  return v;
+}
+
+auto MakeTypeTypeVal() -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::TypeTV;
+  return v;
+}
+
+auto MakeAutoTypeVal() -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::AutoTV;
+  return v;
+}
+
+auto MakeFunTypeVal(Value* param, Value* ret) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::FunctionTV;
+  v->u.fun_type.param = param;
+  v->u.fun_type.ret = ret;
+  return v;
+}
+
+auto MakePtrTypeVal(Value* type) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::PointerTV;
+  v->u.ptr_type.type = type;
+  return v;
+}
+
+auto MakeStructTypeVal(std::string name, VarValues* fields, VarValues* methods)
+    -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::StructTV;
+  v->u.struct_type.name = new std::string(std::move(name));
+  v->u.struct_type.fields = fields;
+  v->u.struct_type.methods = methods;
+  return v;
+}
+
+auto MakeTupleTypeVal(VarValues* fields) -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::TupleTV;
+  v->u.tuple_type.fields = fields;
+  return v;
+}
+
+auto MakeVoidTypeVal() -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::TupleTV;
+  v->u.tuple_type.fields = new VarValues();
+  return v;
+}
+
+auto MakeChoiceTypeVal(std::string* name,
+                       std::list<std::pair<std::string, Value*>>* alts)
+    -> Value* {
+  auto* v = new Value();
+  v->alive = true;
+  v->tag = ValKind::ChoiceTV;
+  v->u.choice_type.name = name;
+  v->u.choice_type.alternatives = alts;
+  return v;
+}
+
+void PrintValue(Value* val, std::ostream& out) {
+  if (!val->alive) {
+    out << "!!";
+  }
+  switch (val->tag) {
+    case ValKind::AltConsV: {
+      out << *val->u.alt_cons.choice_name << "." << *val->u.alt_cons.alt_name;
+      break;
+    }
+    case ValKind::VarPatV: {
+      PrintValue(val->u.var_pat.type, out);
+      out << ": " << *val->u.var_pat.name;
+      break;
+    }
+    case ValKind::AltV: {
+      out << "alt " << *val->u.alt.choice_name << "." << *val->u.alt.alt_name
+          << " ";
+      PrintValue(val->u.alt.arg, out);
+      break;
+    }
+    case ValKind::StructV: {
+      out << *val->u.struct_val.type->u.struct_type.name;
+      PrintValue(val->u.struct_val.inits, out);
+      break;
+    }
+    case ValKind::TupleV: {
+      out << "(";
+      bool add_commas = false;
+      for (const auto& elt : *val->u.tuple.elts) {
+        if (add_commas) {
+          out << ", ";
+        } else {
+          add_commas = true;
+        }
+
+        out << elt.first << " = ";
+        PrintValue(state->heap[elt.second], out);
+        out << "@" << elt.second;
+      }
+      out << ")";
+      break;
+    }
+    case ValKind::IntV:
+      out << val->u.integer;
+      break;
+    case ValKind::BoolV:
+      out << std::boolalpha << val->u.boolean;
+      break;
+    case ValKind::FunV:
+      out << "fun<" << *val->u.fun.name << ">";
+      break;
+    case ValKind::PtrV:
+      out << "ptr<" << val->u.ptr << ">";
+      break;
+    case ValKind::BoolTV:
+      out << "Bool";
+      break;
+    case ValKind::IntTV:
+      out << "Int";
+      break;
+    case ValKind::TypeTV:
+      out << "Type";
+      break;
+    case ValKind::AutoTV:
+      out << "auto";
+      break;
+    case ValKind::PointerTV:
+      out << "Ptr(";
+      PrintValue(val->u.ptr_type.type, out);
+      out << ")";
+      break;
+    case ValKind::FunctionTV:
+      out << "fn ";
+      PrintValue(val->u.fun_type.param, out);
+      out << " -> ";
+      PrintValue(val->u.fun_type.ret, out);
+      break;
+    case ValKind::VarTV:
+      out << *val->u.var_type;
+      break;
+    case ValKind::TupleTV: {
+      out << "Tuple(";
+      bool add_commas = false;
+      for (const auto& elt : *val->u.tuple_type.fields) {
+        if (add_commas) {
+          out << ", ";
+        } else {
+          add_commas = true;
+        }
+
+        out << elt.first << " = ";
+        PrintValue(elt.second, out);
+      }
+      out << ")";
+      break;
+    }
+    case ValKind::StructTV:
+      out << "struct " << *val->u.struct_type.name;
+      break;
+    case ValKind::ChoiceTV:
+      out << "choice " << *val->u.choice_type.name;
+      break;
+  }
+}
+
+auto TypeEqual(Value* t1, Value* t2) -> bool {
+  if (t1->tag != t2->tag) {
+    return false;
+  }
+  switch (t1->tag) {
+    case ValKind::VarTV:
+      return *t1->u.var_type == *t2->u.var_type;
+    case ValKind::PointerTV:
+      return TypeEqual(t1->u.ptr_type.type, t2->u.ptr_type.type);
+    case ValKind::FunctionTV:
+      return TypeEqual(t1->u.fun_type.param, t2->u.fun_type.param) &&
+             TypeEqual(t1->u.fun_type.ret, t2->u.fun_type.ret);
+    case ValKind::StructTV:
+      return *t1->u.struct_type.name == *t2->u.struct_type.name;
+    case ValKind::ChoiceTV:
+      return *t1->u.choice_type.name == *t2->u.choice_type.name;
+    case ValKind::TupleTV:
+      return FieldsEqual(t1->u.tuple_type.fields, t2->u.tuple_type.fields);
+    case ValKind::IntTV:
+    case ValKind::BoolTV:
+      return true;
+    default:
+      return false;
+  }
+}
+
+static auto FieldsValueEqual(VarValues* ts1, VarValues* ts2, int line_num)
+    -> bool {
+  if (ts1->size() != ts2->size()) {
+    return false;
+  }
+  for (auto& iter1 : *ts1) {
+    auto t2 = FindInVarValues(iter1.first, ts2);
+    if (t2 == nullptr) {
+      return false;
+    }
+    if (!ValueEqual(iter1.second, t2, line_num)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+auto ValueEqual(Value* v1, Value* v2, int line_num) -> bool {
+  CheckAlive(v1, line_num);
+  CheckAlive(v2, line_num);
+  if (v1->tag != v2->tag) {
+    return false;
+  }
+  switch (v1->tag) {
+    case ValKind::IntV:
+      return v1->u.integer == v2->u.integer;
+    case ValKind::BoolV:
+      return v1->u.boolean == v2->u.boolean;
+    case ValKind::PtrV:
+      return v1->u.ptr == v2->u.ptr;
+    case ValKind::FunV:
+      return v1->u.fun.body == v2->u.fun.body;
+    case ValKind::TupleV:
+      return FieldsValueEqual(v1->u.tuple_type.fields, v2->u.tuple_type.fields,
+                              line_num);
+    default:
+      return TypeEqual(v1, v2);
+  }
+}
+
+auto ToInteger(Value* v) -> int {
+  switch (v->tag) {
+    case ValKind::IntV:
+      return v->u.integer;
+    default:
+      std::cerr << "expected an integer, not ";
+      PrintValue(v, std::cerr);
+      exit(-1);
+  }
+}
+
+void CheckAlive(Value* v, int line_num) {
+  if (!v->alive) {
+    std::cerr << line_num << ": undefined behavior: access to dead value ";
+    PrintValue(v, std::cerr);
+    std::cerr << std::endl;
+    exit(-1);
+  }
+}
+
+}  // namespace Carbon

+ 139 - 0
executable_semantics/interpreter/value.h

@@ -0,0 +1,139 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#ifndef EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_
+#define EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_
+
+#include <list>
+#include <vector>
+
+#include "executable_semantics/ast/statement.h"
+
+namespace Carbon {
+
+struct Value;
+using Address = unsigned int;
+using VarValues = std::list<std::pair<std::string, Value*>>;
+
+auto FindInVarValues(const std::string& field, VarValues* inits) -> Value*;
+auto FieldsEqual(VarValues* ts1, VarValues* ts2) -> bool;
+
+enum class ValKind {
+  IntV,
+  FunV,
+  PtrV,
+  BoolV,
+  StructV,
+  AltV,
+  TupleV,
+  VarTV,
+  IntTV,
+  BoolTV,
+  TypeTV,
+  FunctionTV,
+  PointerTV,
+  AutoTV,
+  TupleTV,
+  StructTV,
+  ChoiceTV,
+  VarPatV,
+  AltConsV
+};
+
+struct Value {
+  ValKind tag;
+  bool alive;
+  union {
+    int integer;
+    bool boolean;
+    struct {
+      std::string* name;
+      Value* param;
+      Statement* body;
+    } fun;
+    struct {
+      Value* type;
+      Value* inits;
+    } struct_val;
+    struct {
+      std::string* alt_name;
+      std::string* choice_name;
+    } alt_cons;
+    struct {
+      std::string* alt_name;
+      std::string* choice_name;
+      Value* arg;
+    } alt;
+    struct {
+      std::vector<std::pair<std::string, Address>>* elts;
+    } tuple;
+    Address ptr;
+    std::string* var_type;
+    struct {
+      std::string* name;
+      Value* type;
+    } var_pat;
+    struct {
+      Value* param;
+      Value* ret;
+    } fun_type;
+    struct {
+      Value* type;
+    } ptr_type;
+    struct {
+      std::string* name;
+      VarValues* fields;
+      VarValues* methods;
+    } struct_type;
+    struct {
+      std::string* name;
+      VarValues* fields;
+    } tuple_type;
+    struct {
+      std::string* name;
+      VarValues* alternatives;
+    } choice_type;
+    struct {
+      std::list<std::string*>* params;
+      Value* type;
+    } implicit;
+  } u;
+};
+
+auto MakeIntVal(int i) -> Value*;
+auto MakeBoolVal(bool b) -> Value*;
+auto MakeFunVal(std::string name, Value* param, Statement* body) -> Value*;
+auto MakePtrVal(Address addr) -> Value*;
+auto MakeStructVal(Value* type, Value* inits) -> Value*;
+auto MakeTupleVal(std::vector<std::pair<std::string, Address>>* elts) -> Value*;
+auto MakeAltVal(std::string alt_name, std::string choice_name, Value* arg)
+    -> Value*;
+auto MakeAltCons(std::string alt_name, std::string choice_name) -> Value*;
+
+auto MakeVarPatVal(std::string name, Value* type) -> Value*;
+
+auto MakeVarTypeVal(std::string name) -> Value*;
+auto MakeIntTypeVal() -> Value*;
+auto MakeAutoTypeVal() -> Value*;
+auto MakeBoolTypeVal() -> Value*;
+auto MakeTypeTypeVal() -> Value*;
+auto MakeFunTypeVal(Value* param, Value* ret) -> Value*;
+auto MakePtrTypeVal(Value* type) -> Value*;
+auto MakeStructTypeVal(std::string name, VarValues* fields, VarValues* methods)
+    -> Value*;
+auto MakeTupleTypeVal(VarValues* fields) -> Value*;
+auto MakeVoidTypeVal() -> Value*;
+auto MakeChoiceTypeVal(std::string* name, VarValues* alts) -> Value*;
+
+void PrintValue(Value* val, std::ostream& out);
+
+auto TypeEqual(Value* t1, Value* t2) -> bool;
+auto ValueEqual(Value* v1, Value* v2, int line_num) -> bool;
+
+auto ToInteger(Value* v) -> int;
+void CheckAlive(Value* v, int line_num);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_INTERPRETER_VALUE_H_

+ 27 - 0
executable_semantics/main.cpp

@@ -0,0 +1,27 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+
+#include "executable_semantics/syntax_helpers.h"
+
+extern FILE* yyin;
+extern auto yyparse() -> int;  // NOLINT(readability-identifier-naming)
+
+int main(int argc, char* argv[]) {
+  // yydebug = 1;
+
+  if (argc > 1) {
+    Carbon::input_filename = argv[1];
+    yyin = fopen(argv[1], "r");
+    if (yyin == nullptr) {
+      std::cerr << "Error opening '" << argv[1] << "': " << strerror(errno)
+                << std::endl;
+      return 1;
+    }
+  }
+  return yyparse();
+}

+ 90 - 0
executable_semantics/syntax.lpp

@@ -0,0 +1,90 @@
+/*
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+*/
+
+%{
+#include <cstdlib>
+#include "executable_semantics/syntax.tab.h"
+%}
+%option yylineno
+
+AND      "and"
+ARROW    "->"
+AUTO     "auto"
+BOOL     "Bool"
+BREAK    "break"
+CASE     "case"
+CHOICE   "choice"
+COMMENT  \/\/[^\n]*\n
+CONTINUE "continue"
+DBLARROW "=>"
+DEFAULT  "default"
+ELSE     "else"
+EQUAL    "=="
+FALSE    "false"
+FN       "fn"
+FNTY     "fnty"
+IF       "if"
+INT      "Int"
+MATCH    "match"
+NOT      "not"
+OR       "or"
+RETURN   "return"
+STRUCT   "struct"
+TRUE     "true"
+TYPE     "Type"
+VAR      "var"
+WHILE    "while"
+
+identifier    [A-Za-z_][A-Za-z0-9_]*
+integer_literal   [0-9]+
+
+%%
+
+{AND}      { return AND; }
+{ARROW}    { return ARROW; }
+{AUTO}     { return AUTO; }
+{BOOL}     { return BOOL; }
+{BREAK}    { return BREAK; }
+{CASE}     { return CASE; }
+{CHOICE}   { return CHOICE; }
+{COMMENT}  ;
+{CONTINUE} { return CONTINUE; }
+{DBLARROW} { return DBLARROW; }
+{DEFAULT}  { return DEFAULT; }
+{ELSE}     { return ELSE; }
+{EQUAL}    { return EQUAL; }
+{FALSE}    { return FALSE; }
+{FN}       { return FN; }
+{FNTY}     { return FNTY; }
+{IF}       { return IF; }
+{INT}      { return INT; }
+{MATCH}    { return MATCH; }
+{NOT}      { return NOT; }
+{OR}       { return OR; }
+{RETURN}   { return RETURN; }
+{STRUCT}   { return STRUCT; }
+{TRUE}     { return TRUE; }
+{TYPE}     { return TYPE; }
+{VAR}      { return VAR; }
+{WHILE}    { return WHILE; }
+
+{identifier} {
+  int n = strlen(yytext);
+  yylval.str = reinterpret_cast<char*>(malloc((n + 1) * sizeof(char)));
+  strncpy(yylval.str, yytext, n + 1);
+  return identifier;
+}
+{integer_literal} {
+  yylval.num = atof(yytext);
+  return integer_literal;
+}
+
+[ \t\n]+ ;
+. { return yytext[0]; }
+
+%%
+
+int yywrap()  { return 1; }

+ 314 - 0
executable_semantics/syntax.ypp

@@ -0,0 +1,314 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+%code top {
+#include <algorithm>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <iostream>
+#include <list>
+
+#include "executable_semantics/syntax_helpers.h"
+}
+
+%code requires {
+#include "executable_semantics/ast/declaration.h"
+#include "executable_semantics/ast/expression_or_field_list.h"
+#include "executable_semantics/ast/function_definition.h"
+}
+
+%code {
+extern int yylineno;
+extern int yylex();
+
+void yyerror(char* error) {
+  Carbon::PrintSyntaxError(error, yylineno);
+}
+// void yyerror(char* error, ...);
+}
+
+%union {
+   char* str;
+   int num;
+   Carbon::Expression* expression;
+   std::list<std::pair<std::string, Carbon::Expression*>>* field_types;
+   Carbon::Statement* statement;
+   Carbon::Statement* statement_list;
+   Carbon::FunctionDefinition* function_definition;
+   Carbon::Declaration* declaration;
+   std::list<Carbon::Declaration*>* declaration_list;
+   Carbon::Member* member;
+   std::list<Carbon::Member*>* member_list;
+   Carbon::ExpOrFieldList* field_list;
+   std::pair<std::string, Carbon::Expression*>* alternative;
+   std::list<std::pair<std::string, Carbon::Expression*>>* alternative_list;
+   std::pair<Carbon::Expression*, Carbon::Statement*>* clause;
+   std::list<std::pair<Carbon::Expression*, Carbon::Statement*>>* clause_list;
+   Carbon::Expression* fun_type;
+};
+
+%token <num> integer_literal
+%token <str> identifier
+%type <str> designator
+%type <declaration> declaration
+%type <function_definition> function_declaration
+%type <function_definition> function_definition
+%type <declaration_list> declaration_list
+%type <statement> statement
+%type <statement_list> statement_list
+%type <expression> expression
+%type <expression> pattern
+%type <expression> return_type
+%type <expression> tuple
+%type <member> member
+%type <member_list> member_list
+%type <field_list> field
+%type <field_list> field_list
+%type <alternative> alternative
+%type <alternative_list> alternative_list
+%type <clause> clause
+%type <clause_list> clause_list
+%token AND
+%token OR
+%token NOT
+%token INT
+%token BOOL
+%token TYPE
+%token FN
+%token FNTY
+%token ARROW
+%token VAR
+%token EQUAL
+%token IF
+%token ELSE
+%token WHILE
+%token BREAK
+%token CONTINUE
+%token RETURN
+%token TRUE
+%token FALSE
+%token STRUCT
+%token CHOICE
+%token MATCH
+%token CASE
+%token DBLARROW
+%token DEFAULT
+%token AUTO
+%nonassoc '{' '}'
+%nonassoc ':' ',' DBLARROW
+%left OR AND
+%nonassoc EQUAL NOT
+%left '+' '-'
+%left '.' ARROW
+%nonassoc '(' ')' '[' ']'
+%start input
+%locations
+%%
+input: declaration_list
+    { Carbon::ExecProgram($1); }
+;
+pattern:
+  expression
+    { $$ = $1; }
+;
+expression:
+  identifier
+    { $$ = Carbon::MakeVar(yylineno, $1); }
+| expression designator
+    { $$ = Carbon::MakeGetField(yylineno, $1, $2); }
+| expression '[' expression ']'
+    { $$ = Carbon::MakeIndex(yylineno, $1, $3); }
+| expression ':' identifier
+    { $$ = Carbon::MakeVarPat(yylineno, $3, $1); }
+| integer_literal
+    { $$ = Carbon::MakeInt(yylineno, $1); }
+| TRUE
+    { $$ = Carbon::MakeBool(yylineno, true); }
+| FALSE
+    { $$ = Carbon::MakeBool(yylineno, false); }
+| INT
+    { $$ = Carbon::MakeIntType(yylineno); }
+| BOOL
+    { $$ = Carbon::MakeBoolType(yylineno); }
+| TYPE
+    { $$ = Carbon::MakeTypeType(yylineno); }
+| AUTO
+    { $$ = Carbon::MakeAutoType(yylineno); }
+| tuple { $$ = $1; }
+| expression EQUAL expression
+    { $$ = Carbon::MakeBinOp(yylineno, Carbon::Operator::Eq, $1, $3); }
+| expression '+' expression
+    { $$ = Carbon::MakeBinOp(yylineno, Carbon::Operator::Add, $1, $3); }
+| expression '-' expression
+    { $$ = Carbon::MakeBinOp(yylineno, Carbon::Operator::Sub, $1, $3); }
+| expression AND expression
+    { $$ = Carbon::MakeBinOp(yylineno, Carbon::Operator::And, $1, $3); }
+| expression OR expression
+    { $$ = Carbon::MakeBinOp(yylineno, Carbon::Operator::Or, $1, $3); }
+| NOT expression
+    { $$ = Carbon::MakeUnOp(yylineno, Carbon::Operator::Not, $2); }
+| '-' expression
+    { $$ = Carbon::MakeUnOp(yylineno, Carbon::Operator::Neg, $2); }
+| expression tuple
+    {
+      if ($2->tag == Carbon::ExpressionKind::Tuple) {
+        $$ = Carbon::MakeCall(yylineno, $1, $2);
+      } else {
+        auto vec =
+            new std::vector<std::pair<std::string, Carbon::Expression*>>();
+        vec->push_back(std::make_pair("", $2));
+        $$ = Carbon::MakeCall(yylineno, $1, Carbon::MakeTuple(yylineno, vec));
+      }
+    }
+| FNTY tuple return_type
+    { $$ = Carbon::MakeFunType(yylineno, $2, $3); }
+;
+designator: '.' identifier { $$ = $2; }
+;
+tuple: '(' field_list ')'
+    {
+      switch ($2->tag) {
+      case Carbon::ExpOrFieldListKind::Exp:
+        $$ = $2->u.exp;
+        break;
+      case Carbon::ExpOrFieldListKind::FieldList:
+        auto vec = new std::vector<std::pair<std::string,Carbon::Expression*>>(
+            $2->u.fields->begin(), $2->u.fields->end());
+        $$ = Carbon::MakeTuple(yylineno, vec);
+        break;
+      }
+    }
+;
+field:
+  pattern
+    { $$ = Carbon::MakeExp($1); }
+| designator '=' pattern
+    {
+      auto fields =
+          new std::list<std::pair<std::string, Carbon::Expression*>>();
+      fields->push_back(std::make_pair($1, $3));
+      $$ = Carbon::MakeFieldList(fields);
+    }
+;
+field_list:
+  // Empty
+    {
+      $$ = Carbon::MakeFieldList(
+          new std::list<std::pair<std::string, Carbon::Expression*>>());
+    }
+| field
+    { $$ = $1; }
+| field ',' field_list
+    { $$ = Carbon::MakeConsField($1, $3); }
+;
+clause:
+  CASE pattern DBLARROW statement
+    { $$ = new std::pair<Carbon::Expression*, Carbon::Statement*>($2, $4); }
+| DEFAULT DBLARROW statement
+    {
+      auto vp = Carbon::MakeVarPat(yylineno, "_",
+                                   Carbon::MakeAutoType(yylineno));
+      $$ = new std::pair<Carbon::Expression*, Carbon::Statement*>(vp, $3);
+    }
+;
+clause_list:
+  // Empty
+    {
+      $$ = new std::list<std::pair<Carbon::Expression*, Carbon::Statement*>>();
+    }
+| clause clause_list
+    { $$ = $2; $$->push_front(*$1); }
+;
+statement:
+  expression '=' expression ';'
+    { $$ = Carbon::MakeAssign(yylineno, $1, $3); }
+| VAR pattern '=' expression ';'
+    { $$ = Carbon::MakeVarDef(yylineno, $2, $4); }
+| expression ';'
+    { $$ = Carbon::MakeExpStmt(yylineno, $1); }
+| IF '(' expression ')' statement ELSE statement
+    { $$ = Carbon::MakeIf(yylineno, $3, $5, $7); }
+| WHILE '(' expression ')' statement
+    { $$ = Carbon::MakeWhile(yylineno, $3, $5); }
+| BREAK ';'
+    { $$ = Carbon::MakeBreak(yylineno); }
+| CONTINUE ';'
+    { $$ = Carbon::MakeContinue(yylineno); }
+| RETURN expression ';'
+    { $$ = Carbon::MakeReturn(yylineno, $2); }
+| '{' statement_list '}'
+    { $$ = Carbon::MakeBlock(yylineno, $2); }
+| MATCH '(' expression ')' '{' clause_list '}'
+    { $$ = Carbon::MakeMatch(yylineno, $3, $6); }
+;
+statement_list:
+  // Empty
+    { $$ = 0; }
+| statement statement_list
+    { $$ = Carbon::MakeSeq(yylineno, $1, $2); }
+;
+return_type:
+  // Empty
+    {
+      $$ = Carbon::MakeTuple(
+          yylineno,
+          new std::vector<std::pair<std::string, Carbon::Expression*>>());
+    }
+| ARROW expression
+    { $$ = $2; }
+;
+function_definition:
+  FN identifier tuple return_type '{' statement_list '}'
+    { $$ = MakeFunDef(yylineno, $2, $4, $3, $6); }
+| FN identifier tuple DBLARROW expression ';'
+    {
+      $$ = Carbon::MakeFunDef(yylineno, $2, Carbon::MakeAutoType(yylineno), $3,
+                              Carbon::MakeReturn(yylineno, $5));
+    }
+;
+function_declaration:
+  FN identifier tuple return_type ';'
+    { $$ = MakeFunDef(yylineno, $2, $4, $3, 0); }
+;
+member:
+  VAR expression ':' identifier ';'
+    { $$ = MakeField(yylineno, $4, $2); }
+;
+member_list:
+  // Empty
+    { $$ = new std::list<Carbon::Member*>(); }
+| member member_list
+    { $$ = $2; $$->push_front($1); }
+;
+alternative:
+  identifier tuple ';'
+    { $$ = new std::pair<std::string, Carbon::Expression*>($1, $2); }
+;
+alternative_list:
+  // Empty
+    { $$ = new std::list<std::pair<std::string, Carbon::Expression*>>(); }
+| alternative alternative_list
+    { $$ = $2; $$->push_front(*$1); }
+;
+declaration:
+  function_definition
+    { $$ = Carbon::MakeFunDecl($1); }
+| function_declaration
+    { $$ = Carbon::MakeFunDecl($1); }
+| STRUCT identifier '{' member_list '}'
+    { $$ = Carbon::MakeStructDecl(yylineno, $2, $4); }
+| CHOICE identifier '{' alternative_list '}'
+    { $$ = Carbon::MakeChoiceDecl(yylineno, $2, $4); }
+;
+declaration_list:
+  // Empty
+    { $$ = new std::list<Carbon::Declaration*>(); }
+| declaration declaration_list
+    {
+      $$ = $2;
+      $$->push_front($1);
+    }
+;
+%%

+ 45 - 0
executable_semantics/syntax_helpers.cpp

@@ -0,0 +1,45 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "executable_semantics/syntax_helpers.h"
+
+#include <iostream>
+
+#include "executable_semantics/interpreter/interpreter.h"
+#include "executable_semantics/interpreter/typecheck.h"
+
+namespace Carbon {
+
+char* input_filename = nullptr;
+
+void PrintSyntaxError(char* error, int line_num) {
+  std::cerr << input_filename << ":" << line_num << ": " << error << std::endl;
+  exit(-1);
+}
+
+void ExecProgram(std::list<Declaration*>* fs) {
+  std::cout << "********** source program **********" << std::endl;
+  for (const auto& decl : *fs) {
+    PrintDecl(decl);
+  }
+  std::cout << "********** type checking **********" << std::endl;
+  state = new State();  // Compile-time state.
+  std::pair<TypeEnv*, Env*> p = TopLevel(fs);
+  TypeEnv* top = p.first;
+  Env* ct_top = p.second;
+  std::list<Declaration*> new_decls;
+  for (const auto& i : *fs) {
+    new_decls.push_back(TypeCheckDecl(i, top, ct_top));
+  }
+  std::cout << std::endl;
+  std::cout << "********** type checking complete **********" << std::endl;
+  for (const auto& decl : new_decls) {
+    PrintDecl(decl);
+  }
+  std::cout << "********** starting execution **********" << std::endl;
+  int result = InterpProgram(&new_decls);
+  std::cout << "result: " << result << std::endl;
+}
+
+}  // namespace Carbon

+ 29 - 0
executable_semantics/syntax_helpers.h

@@ -0,0 +1,29 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Helpers should be added here when logic in syntax.ypp is more than a single
+// statement. The intent is to minimize the amount of C++ in the .ypp file, to
+// improve ease of maintenance.
+
+#ifndef EXECUTABLE_SEMANTICS_EXEC_H_
+#define EXECUTABLE_SEMANTICS_EXEC_H_
+
+#include <list>
+
+#include "executable_semantics/ast/declaration.h"
+
+namespace Carbon {
+
+// Initialized by main(), and used when printing errors.
+extern char* input_filename;
+
+// Prints errors.
+void PrintSyntaxError(char* error, int line_num);
+
+// Runs the top-level declaration list.
+void ExecProgram(std::list<Declaration*>* fs);
+
+}  // namespace Carbon
+
+#endif  // EXECUTABLE_SEMANTICS_EXEC_H_

+ 11 - 0
executable_semantics/testdata/block1.6c

@@ -0,0 +1,11 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var Int: x = 0;
+  {
+    var Int: x = 1;
+  }
+  return x;
+}

+ 265 - 0
executable_semantics/testdata/block1.golden

@@ -0,0 +1,265 @@
+********** source program **********
+fn main () -> Int {
+var Int: x = 0;
+{
+var Int: x = 1;
+
+}
+
+return x;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn main () -> Int {
+var Int: x = 0;
+{
+var Int: x = 1;
+
+}
+
+return x;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 0; ...  --->
+{
+stack: main{var Int: x = 0;<-1> :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 0; --->
+{
+stack: main{0<-1> :: var Int: x = 0;<0> :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: var Int: x = 0;<0> :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 0 with var Int: x = 0;<1>(0,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int: x --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int with Int: x<1>(Int,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: {
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int: x with var Int: x = 0;<2>(0,Int: x,) --->
+pattern_match(Int: x, 0)
+{
+stack: main{{
+ ... 
+}
+ ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ ...  --->
+{
+stack: main{{
+ ... 
+}
+<-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{var Int: x = 1;<-1> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt var Int: x = 1; --->
+{
+stack: main{var Int: x = 1;<-1> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt var Int: x = 1; --->
+{
+stack: main{1<-1> :: var Int: x = 1;<0> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: var Int: x = 1;<0> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 1 with var Int: x = 1;<1>(1,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 1;<1>(1,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp Int: x --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 1;<1>(1,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 1;<1>(1,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value Int with Int: x<1>(Int,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 1;<1>(1,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value Int: x with var Int: x = 1;<2>(1,Int: x,) --->
+pattern_match(Int: x, 1)
+{
+stack: main{{
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: x: 1, x: 0, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{return x;<-1>} :: top{}
+heap: fun<main>, 0, !!1, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt return x; --->
+{
+stack: main{x<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, !!1, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, !!1, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with return x;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!0, !!1, 
+env: main: fun<main>, 
+}
+result: 0

+ 14 - 0
executable_semantics/testdata/break1.6c

@@ -0,0 +1,14 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var Int: x = 2;
+  while (true) {
+    if (x == 0)
+      break;
+    else
+      x = x - 1;
+  }
+  return x;
+}

+ 821 - 0
executable_semantics/testdata/break1.golden

@@ -0,0 +1,821 @@
+MakeBlock
+********** source program **********
+fn main () -> Int {
+var Int: x = 2;
+while (true)
+{
+if ((x == 0))
+break;
+else
+x = (x - 1);
+
+}
+
+return x;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn main () -> Int {
+var Int: x = 2;
+while (true)
+{
+if ((x == 0))
+break;
+else
+x = (x - 1);
+
+}
+
+return x;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var Int: x = 2; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 2; ...  --->
+{
+stack: main{var Int: x = 2;<-1> :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 2; --->
+{
+stack: main{2<-1> :: var Int: x = 2;<0> :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: var Int: x = 2;<0> :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 2 with var Int: x = 2;<1>(2,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 2;<1>(2,) :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int: x --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 2;<1>(2,) :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 2;<1>(2,) :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int with Int: x<1>(Int,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 2;<1>(2,) :: while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int: x with var Int: x = 2;<2>(2,Int: x,) --->
+pattern_match(Int: x, 2)
+{
+stack: main{while (true)
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt while (true)
+ ...  ...  --->
+{
+stack: main{while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt while (true)
+ ...  --->
+{
+stack: main{true<-1> :: while (true)
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp true --->
+{
+stack: main{true<-1> :: while (true)
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value true with while (true)
+ ... <1>(true,) --->
+{
+stack: main{{
+ ... 
+}
+<-1> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{if ((x == 0))
+ ... 
+else
+ ... <-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt if ((x == 0))
+ ... 
+else
+ ...  --->
+{
+stack: main{if ((x == 0))
+ ... 
+else
+ ... <-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt if ((x == 0))
+ ... 
+else
+ ...  --->
+{
+stack: main{(x == 0)<-1> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (x == 0)<0> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 2 with (x == 0)<1>(2,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(2,) :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(2,) :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(2,0,) --->
+{
+stack: main{false<-1> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value false with if ((x == 0))
+ ... 
+else
+ ... <1>(false,) --->
+{
+stack: main{x = (x - 1);<-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: x = (x - 1);<0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value ptr<1> with x = (x - 1);<1>(ptr<1>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 2 with (x - 1)<1>(2,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(2,) :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(2,) :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(2,1,) --->
+{
+stack: main{1<-1> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 1 with x = (x - 1);<2>(ptr<1>,1,) --->
+{
+stack: main{{
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt while (true)
+ ...  --->
+{
+stack: main{true<-1> :: while (true)
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp true --->
+{
+stack: main{true<-1> :: while (true)
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value true with while (true)
+ ... <1>(true,) --->
+{
+stack: main{{
+ ... 
+}
+<-1> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{if ((x == 0))
+ ... 
+else
+ ... <-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt if ((x == 0))
+ ... 
+else
+ ...  --->
+{
+stack: main{if ((x == 0))
+ ... 
+else
+ ... <-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt if ((x == 0))
+ ... 
+else
+ ...  --->
+{
+stack: main{(x == 0)<-1> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x == 0)<0> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x == 0)<1>(1,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(1,) :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(1,) :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(1,0,) --->
+{
+stack: main{false<-1> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value false with if ((x == 0))
+ ... 
+else
+ ... <1>(false,) --->
+{
+stack: main{x = (x - 1);<-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: x = (x - 1);<0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value ptr<1> with x = (x - 1);<1>(ptr<1>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: x = (x - 1);<1>(ptr<1>,) :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 0 with x = (x - 1);<2>(ptr<1>,0,) --->
+{
+stack: main{{
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt while (true)
+ ...  --->
+{
+stack: main{true<-1> :: while (true)
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp true --->
+{
+stack: main{true<-1> :: while (true)
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value true with while (true)
+ ... <1>(true,) --->
+{
+stack: main{{
+ ... 
+}
+<-1> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{if ((x == 0))
+ ... 
+else
+ ... <-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt if ((x == 0))
+ ... 
+else
+ ...  --->
+{
+stack: main{if ((x == 0))
+ ... 
+else
+ ... <-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt if ((x == 0))
+ ... 
+else
+ ...  --->
+{
+stack: main{(x == 0)<-1> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: (x == 0)<0> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<1>(0,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(0,) :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(0,) :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(0,0,) --->
+{
+stack: main{true<-1> :: if ((x == 0))
+ ... 
+else
+ ... <0> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value true with if ((x == 0))
+ ... 
+else
+ ... <1>(true,) --->
+{
+stack: main{break;<-1> :: {
+ ... 
+}
+<0> :: while (true)
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt break; --->
+{
+stack: main{return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt return x; --->
+{
+stack: main{x<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with return x;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!0, 
+env: main: fun<main>, 
+}
+result: 0

+ 32 - 0
executable_semantics/testdata/choice1.6c

@@ -0,0 +1,32 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+choice Ints {
+  None();
+  One(Int);
+  Two(Int,Int);
+}
+
+fn main() -> Int {
+  var auto: x = Ints.None();
+  var auto: y = Ints.One(42);
+  var auto: n = 0;
+  match (y) {
+    case Ints.None() =>
+      n = n + 2;
+    case Ints.One(auto: x) =>
+      n = x + 1 - 42;
+    case Ints.Two(auto: a, auto: b) =>
+      n = 2;
+  }
+  match (x) {
+    case Ints.One(auto: x) =>
+      n = x + 2;
+    case Ints.None() =>
+      n = n - 1;
+    case Ints.Two(auto: x, auto: y) =>
+      n = 5;
+  }
+  return n;
+}

+ 43 - 0
executable_semantics/testdata/choice1.golden

@@ -0,0 +1,43 @@
+********** source program **********
+choice Ints {
+alt None ();
+alt One Int;
+alt Two (0 = Int, 1 = Int);
+}
+fn main () -> Int {
+var auto: x = Ints.None();
+var auto: y = Ints.One(0 = 42);
+var auto: n = 0;
+match (y) {
+case Ints.None() =>
+n = (n + 2);
+case Ints.One(0 = auto: x) =>
+n = ((x + 1) - 42);
+case Ints.Two(0 = auto: a, 1 = auto: b) =>
+n = 2;
+}
+match (x) {
+case Ints.One(0 = auto: x) =>
+n = (x + 2);
+case Ints.None() =>
+n = (n - 1);
+case Ints.Two(0 = auto: x, 1 = auto: y) =>
+n = 5;
+}
+return n;
+
+}
+********** type checking **********
+--- step exp () --->
+--- step exp Int --->
+--- step exp (0 = Int, 1 = Int) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+13: type error in call
+expected: Int
+actual: Tuple(0 = Int)

+ 13 - 0
executable_semantics/testdata/continue1.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: x = 2;
+  while (not (x == 0)) {
+    x = x - 1;
+    continue;
+    x = x + 1;
+  }
+  return x;
+}

+ 616 - 0
executable_semantics/testdata/continue1.golden

@@ -0,0 +1,616 @@
+********** source program **********
+fn main () -> Int {
+var auto: x = 2;
+while ((! (x == 0)))
+{
+x = (x - 1);
+continue;
+x = (x + 1);
+
+}
+
+return x;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: x = 2;
+while ((! (x == 0)))
+{
+x = (x - 1);
+continue;
+x = (x + 1);
+
+}
+
+return x;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: x = 2; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: x = 2; ...  --->
+{
+stack: main{var auto: x = 2;<-1> :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: x = 2; --->
+{
+stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 2 with var auto: x = 2;<1>(2,) --->
+{
+stack: main{auto: x<-1> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto: x --->
+{
+stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: x<1>(auto,) --->
+{
+stack: main{auto: x<-1> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto: x with var auto: x = 2;<2>(2,auto: x,) --->
+pattern_match(auto: x, 2)
+{
+stack: main{while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  ...  --->
+{
+stack: main{while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  --->
+{
+stack: main{(! (x == 0))<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (! (x == 0)) --->
+{
+stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 2 with (x == 0)<1>(2,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(2,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(2,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(2,0,) --->
+{
+stack: main{false<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value false with (! (x == 0))<1>(false,) --->
+{
+stack: main{true<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value true with while ((! (x == 0)))
+ ... <1>(true,) --->
+{
+stack: main{{
+ ... 
+}
+<-1> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{x = (x - 1); ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt x = (x - 1); ...  --->
+{
+stack: main{x = (x - 1);<-1> :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: x = (x - 1);<0> :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value ptr<1> with x = (x - 1);<1>(ptr<1>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 2 with (x - 1)<1>(2,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(2,) :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(2,) :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(2,1,) --->
+{
+stack: main{1<-1> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 1 with x = (x - 1);<2>(ptr<1>,1,) --->
+{
+stack: main{continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt continue; ...  --->
+{
+stack: main{continue;<-1> :: x = (x + 1);<-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt continue; --->
+{
+stack: main{while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  --->
+{
+stack: main{(! (x == 0))<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (! (x == 0)) --->
+{
+stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x == 0)<1>(1,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(1,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(1,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(1,0,) --->
+{
+stack: main{false<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value false with (! (x == 0))<1>(false,) --->
+{
+stack: main{true<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value true with while ((! (x == 0)))
+ ... <1>(true,) --->
+{
+stack: main{{
+ ... 
+}
+<-1> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{x = (x - 1); ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt x = (x - 1); ...  --->
+{
+stack: main{x = (x - 1);<-1> :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: x = (x - 1);<0> :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value ptr<1> with x = (x - 1);<1>(ptr<1>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: x = (x - 1);<1>(ptr<1>,) :: continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 0 with x = (x - 1);<2>(ptr<1>,0,) --->
+{
+stack: main{continue; ... <-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt continue; ...  --->
+{
+stack: main{continue;<-1> :: x = (x + 1);<-1> :: {
+ ... 
+}
+<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt continue; --->
+{
+stack: main{while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  --->
+{
+stack: main{(! (x == 0))<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp (! (x == 0)) --->
+{
+stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<1>(0,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(0,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(0,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(0,0,) --->
+{
+stack: main{true<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value true with (! (x == 0))<1>(true,) --->
+{
+stack: main{false<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value false with while ((! (x == 0)))
+ ... <1>(false,) --->
+{
+stack: main{return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt return x; --->
+{
+stack: main{x<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with return x;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!0, 
+env: main: fun<main>, 
+}
+result: 0

+ 11 - 0
executable_semantics/testdata/fun1.6c

@@ -0,0 +1,11 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn f(Int: x) -> Int {
+  return x - 1;
+}
+
+fn main() -> Int {
+  return f(1);
+}

+ 19 - 0
executable_semantics/testdata/fun1.golden

@@ -0,0 +1,19 @@
+********** source program **********
+fn f Int: x -> Int {
+return (x - 1);
+
+}
+fn main () -> Int {
+return f(0 = 1);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+10: type error in call
+expected: Int
+actual: Tuple(0 = Int)

+ 18 - 0
executable_semantics/testdata/fun2.6c

@@ -0,0 +1,18 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// This tests the call-by-value aspect of parameter passing.
+// This makes sure that when the value in `x` dies,
+// it does not cause the value in `a` to also die.
+
+fn f(Int: x) -> Int {
+  return 0;
+}
+
+fn main() -> Int {
+  var Int: a = 0; var Int: b = 1;
+  f(a);
+  b = a;
+  return b;
+}

+ 25 - 0
executable_semantics/testdata/fun2.golden

@@ -0,0 +1,25 @@
+********** source program **********
+fn f Int: x -> Int {
+return 0;
+
+}
+fn main () -> Int {
+var Int: a = 0;
+var Int: b = 1;
+f(0 = a);
+b = a;
+return b;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+15: type error in call
+expected: Int
+actual: Tuple(0 = Int)

+ 12 - 0
executable_semantics/testdata/fun3.6c

@@ -0,0 +1,12 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Test multiple arguments
+fn f(Int: x, Int: y) -> Int {
+  return x + y;
+}
+
+fn main() -> Int {
+  return f(2,3) - 5;
+}

+ 211 - 0
executable_semantics/testdata/fun3.golden

@@ -0,0 +1,211 @@
+********** source program **********
+fn f (0 = Int: x, 1 = Int: y) -> Int {
+return (x + y);
+
+}
+fn main () -> Int {
+return (f(0 = 2, 1 = 3) - 5);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn f (0 = Int: x, 1 = Int: y) -> Int {
+return (x + y);
+}
+fn main () -> Int {
+return (f(0 = 2, 1 = 3) - 5);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp (0 = Int: x, 1 = Int: y) --->
+--- step exp Int: x --->
+--- step exp Int --->
+--- handle value Int with Int: x<1>(Int,) --->
+--- handle value Int: x with (0 = Int: x, 1 = Int: y)<1>(Int: x,) --->
+--- step exp Int: y --->
+--- step exp Int --->
+--- handle value Int with Int: y<1>(Int,) --->
+--- handle value Int: y with (0 = Int: x, 1 = Int: y)<2>(Int: x,Int: y,) --->
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{return (f(0 = 2, 1 = 3) - 5);<-1>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step stmt return (f(0 = 2, 1 = 3) - 5); --->
+{
+stack: main{(f(0 = 2, 1 = 3) - 5)<-1> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp (f(0 = 2, 1 = 3) - 5) --->
+{
+stack: main{f(0 = 2, 1 = 3)<-1> :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp f(0 = 2, 1 = 3) --->
+{
+stack: main{f<-1> :: f(0 = 2, 1 = 3)<0> :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp f --->
+{
+stack: main{fun<f><-1> :: f(0 = 2, 1 = 3)<0> :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value fun<f> with f(0 = 2, 1 = 3)<1>(fun<f>,) --->
+{
+stack: main{(0 = 2, 1 = 3)<-1> :: f(0 = 2, 1 = 3)<1>(fun<f>,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp (0 = 2, 1 = 3) --->
+{
+stack: main{2<-1> :: (0 = 2, 1 = 3)<0> :: f(0 = 2, 1 = 3)<1>(fun<f>,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (0 = 2, 1 = 3)<0> :: f(0 = 2, 1 = 3)<1>(fun<f>,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value 2 with (0 = 2, 1 = 3)<1>(2,) --->
+{
+stack: main{3<-1> :: (0 = 2, 1 = 3)<1>(2,) :: f(0 = 2, 1 = 3)<1>(fun<f>,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: (0 = 2, 1 = 3)<1>(2,) :: f(0 = 2, 1 = 3)<1>(fun<f>,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value 3 with (0 = 2, 1 = 3)<2>(2,3,) --->
+{
+stack: main{(0 = 2@4, 1 = 3@5)<-1> :: f(0 = 2, 1 = 3)<1>(fun<f>,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value (0 = 2@4, 1 = 3@5) with f(0 = 2, 1 = 3)<2>(fun<f>,(0 = 2@4, 1 = 3@5),) --->
+pattern_match((0 = Int: x@0, 1 = Int: y@1), (0 = 2@4, 1 = 3@5))
+pattern_match(Int: x, 2)
+pattern_match(Int: y, 3)
+{
+stack: f{return (x + y);<-1>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- step stmt return (x + y); --->
+{
+stack: f{(x + y)<-1> :: return (x + y);<0>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- step exp (x + y) --->
+{
+stack: f{x<-1> :: (x + y)<0> :: return (x + y);<0>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- step exp x --->
+{
+stack: f{2<-1> :: (x + y)<0> :: return (x + y);<0>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- handle value 2 with (x + y)<1>(2,) --->
+{
+stack: f{y<-1> :: (x + y)<1>(2,) :: return (x + y);<0>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- step exp y --->
+{
+stack: f{3<-1> :: (x + y)<1>(2,) :: return (x + y);<0>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- handle value 3 with (x + y)<2>(2,3,) --->
+{
+stack: f{5<-1> :: return (x + y);<0>} :: main{(f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, f: fun<f>, 
+}
+--- handle value 5 with return (x + y);<1>(5,) --->
+{
+stack: main{5<-1> :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, !!2, !!3, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value 5 with (f(0 = 2, 1 = 3) - 5)<1>(5,) --->
+{
+stack: main{5<-1> :: (f(0 = 2, 1 = 3) - 5)<1>(5,) :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, !!2, !!3, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (f(0 = 2, 1 = 3) - 5)<1>(5,) :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, !!2, !!3, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value 5 with (f(0 = 2, 1 = 3) - 5)<2>(5,5,) --->
+{
+stack: main{0<-1> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, !!2, !!3, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value 0 with return (f(0 = 2, 1 = 3) - 5);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: Int: x, Int: y, fun<f>, fun<main>, 2, 3, !!2, !!3, 
+env: main: fun<main>, f: fun<f>, 
+}
+result: 0

+ 11 - 0
executable_semantics/testdata/fun4.6c

@@ -0,0 +1,11 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Test empty parameters and return type
+fn f() { }
+
+fn main() -> Int {
+  f();
+  return 0;
+}

+ 148 - 0
executable_semantics/testdata/fun4.golden

@@ -0,0 +1,148 @@
+********** source program **********
+fn f () -> ();
+fn main () -> Int {
+f();
+return 0;
+
+}
+********** type checking **********
+--- step exp () --->
+--- step exp Int --->
+--- step exp () --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn f () -> () {
+return ();
+}
+fn main () -> Int {
+f();
+return 0;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{f(); ... <-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step stmt f(); ...  --->
+{
+stack: main{f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step stmt f(); --->
+{
+stack: main{f()<-1> :: f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp f() --->
+{
+stack: main{f<-1> :: f()<0> :: f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp f --->
+{
+stack: main{fun<f><-1> :: f()<0> :: f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value fun<f> with f()<1>(fun<f>,) --->
+{
+stack: main{()<-1> :: f()<1>(fun<f>,) :: f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp () --->
+{
+stack: main{()<-1> :: f()<1>(fun<f>,) :: f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value () with f()<2>(fun<f>,(),) --->
+pattern_match((), ())
+{
+stack: f{return ();<-1>} :: main{f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step stmt return (); --->
+{
+stack: f{()<-1> :: return ();<0>} :: main{f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp () --->
+{
+stack: f{()<-1> :: return ();<0>} :: main{f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value () with return ();<1>((),) --->
+{
+stack: main{()<-1> :: f();<-1> :: return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value () with f();<0>((),) --->
+{
+stack: main{return 0;<-1>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step stmt return 0; --->
+{
+stack: main{0<-1> :: return 0;<0>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: return 0;<0>} :: top{}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+--- handle value 0 with return 0;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<f>, fun<main>, 
+env: main: fun<main>, f: fun<f>, 
+}
+result: 0

+ 9 - 0
executable_semantics/testdata/fun5.6c

@@ -0,0 +1,9 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn add(Int: x, Int: y) => x + y;
+
+fn main() -> Int {
+  return add(1, 2) - 3;
+}

+ 214 - 0
executable_semantics/testdata/fun5.golden

@@ -0,0 +1,214 @@
+********** source program **********
+fn add (0 = Int: x, 1 = Int: y) -> auto {
+return (x + y);
+}
+fn main () -> Int {
+return (add(0 = 1, 1 = 2) - 3);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn add (0 = Int: x, 1 = Int: y) -> Int {
+return (x + y);
+}
+fn main () -> Int {
+return (add(0 = 1, 1 = 2) - 3);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp (0 = Int: x, 1 = Int: y) --->
+--- step exp Int: x --->
+--- step exp Int --->
+--- handle value Int with Int: x<1>(Int,) --->
+--- handle value Int: x with (0 = Int: x, 1 = Int: y)<1>(Int: x,) --->
+--- step exp Int: y --->
+--- step exp Int --->
+--- handle value Int with Int: y<1>(Int,) --->
+--- handle value Int: y with (0 = Int: x, 1 = Int: y)<2>(Int: x,Int: y,) --->
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{return (add(0 = 1, 1 = 2) - 3);<-1>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step stmt return (add(0 = 1, 1 = 2) - 3); --->
+{
+stack: main{(add(0 = 1, 1 = 2) - 3)<-1> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp (add(0 = 1, 1 = 2) - 3) --->
+{
+stack: main{add(0 = 1, 1 = 2)<-1> :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp add(0 = 1, 1 = 2) --->
+{
+stack: main{add<-1> :: add(0 = 1, 1 = 2)<0> :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp add --->
+{
+stack: main{fun<add><-1> :: add(0 = 1, 1 = 2)<0> :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value fun<add> with add(0 = 1, 1 = 2)<1>(fun<add>,) --->
+{
+stack: main{(0 = 1, 1 = 2)<-1> :: add(0 = 1, 1 = 2)<1>(fun<add>,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp (0 = 1, 1 = 2) --->
+{
+stack: main{1<-1> :: (0 = 1, 1 = 2)<0> :: add(0 = 1, 1 = 2)<1>(fun<add>,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (0 = 1, 1 = 2)<0> :: add(0 = 1, 1 = 2)<1>(fun<add>,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value 1 with (0 = 1, 1 = 2)<1>(1,) --->
+{
+stack: main{2<-1> :: (0 = 1, 1 = 2)<1>(1,) :: add(0 = 1, 1 = 2)<1>(fun<add>,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (0 = 1, 1 = 2)<1>(1,) :: add(0 = 1, 1 = 2)<1>(fun<add>,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value 2 with (0 = 1, 1 = 2)<2>(1,2,) --->
+{
+stack: main{(0 = 1@4, 1 = 2@5)<-1> :: add(0 = 1, 1 = 2)<1>(fun<add>,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value (0 = 1@4, 1 = 2@5) with add(0 = 1, 1 = 2)<2>(fun<add>,(0 = 1@4, 1 = 2@5),) --->
+pattern_match((0 = Int: x@0, 1 = Int: y@1), (0 = 1@4, 1 = 2@5))
+pattern_match(Int: x, 1)
+pattern_match(Int: y, 2)
+{
+stack: add{return (x + y);<-1>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- step stmt return (x + y); --->
+{
+stack: add{(x + y)<-1> :: return (x + y);<0>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- step exp (x + y) --->
+{
+stack: add{x<-1> :: (x + y)<0> :: return (x + y);<0>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- step exp x --->
+{
+stack: add{1<-1> :: (x + y)<0> :: return (x + y);<0>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- handle value 1 with (x + y)<1>(1,) --->
+{
+stack: add{y<-1> :: (x + y)<1>(1,) :: return (x + y);<0>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- step exp y --->
+{
+stack: add{2<-1> :: (x + y)<1>(1,) :: return (x + y);<0>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- handle value 2 with (x + y)<2>(1,2,) --->
+{
+stack: add{3<-1> :: return (x + y);<0>} :: main{(add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, 1, 2, 
+env: y: 2, x: 1, main: fun<main>, add: fun<add>, 
+}
+--- handle value 3 with return (x + y);<1>(3,) --->
+{
+stack: main{3<-1> :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, !!1, !!2, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value 3 with (add(0 = 1, 1 = 2) - 3)<1>(3,) --->
+{
+stack: main{3<-1> :: (add(0 = 1, 1 = 2) - 3)<1>(3,) :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, !!1, !!2, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: (add(0 = 1, 1 = 2) - 3)<1>(3,) :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, !!1, !!2, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value 3 with (add(0 = 1, 1 = 2) - 3)<2>(3,3,) --->
+{
+stack: main{0<-1> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, !!1, !!2, 
+env: main: fun<main>, add: fun<add>, 
+}
+--- handle value 0 with return (add(0 = 1, 1 = 2) - 3);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: Int: x, Int: y, fun<add>, fun<main>, 1, 2, !!1, !!2, 
+env: main: fun<main>, add: fun<add>, 
+}
+result: 0

+ 11 - 0
executable_semantics/testdata/fun6_fail_type.6c

@@ -0,0 +1,11 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn f(Int: x, Int: y) -> Int { return x + y; }
+
+fn main() -> Int {
+  var (Int, Int): xy = (1, 2);
+  // should fail to type-check
+  return f(xy);
+}

+ 27 - 0
executable_semantics/testdata/fun6_fail_type.golden

@@ -0,0 +1,27 @@
+********** source program **********
+fn f (0 = Int: x, 1 = Int: y) -> Int {
+return (x + y);
+
+}
+fn main () -> Int {
+var (0 = Int, 1 = Int): xy = (0 = 1, 1 = 2);
+return f(0 = xy);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp (0 = Int, 1 = Int) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+10: type error in call
+expected: Tuple(0 = Int, 1 = Int)
+actual: Tuple(0 = Tuple(0 = Int, 1 = Int))

+ 14 - 0
executable_semantics/testdata/fun_recur.6c

@@ -0,0 +1,14 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn f(Int: x) -> Int {
+  if (x == 0)
+    return x;
+  else
+    return f(x - 1);
+}
+
+fn main() -> Int {
+  return f(2);
+}

+ 21 - 0
executable_semantics/testdata/fun_recur.golden

@@ -0,0 +1,21 @@
+********** source program **********
+fn f Int: x -> Int {
+if ((x == 0))
+return x;
+else
+return f(0 = (x - 1));
+
+}
+fn main () -> Int {
+return f(0 = 2);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+9: type error in call
+expected: Int
+actual: Tuple(0 = Int)

+ 12 - 0
executable_semantics/testdata/funptr1.6c

@@ -0,0 +1,12 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn add1(Int: x) -> Int {
+  return x + 1;
+}
+
+fn main() -> Int {
+  var fnty(Int)->Int: f = add1;
+  return f(-1);
+}

+ 25 - 0
executable_semantics/testdata/funptr1.golden

@@ -0,0 +1,25 @@
+********** source program **********
+fn add1 Int: x -> Int {
+return (x + 1);
+
+}
+fn main () -> Int {
+var fn Int -> Int: f = add1;
+return f(0 = (- 1));
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp fn Int -> Int --->
+--- step exp Int --->
+--- handle value Int with fn Int -> Int<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with fn Int -> Int<2>(Int,Int,) --->
+11: type error in call
+expected: Int
+actual: Tuple(0 = Int)

+ 13 - 0
executable_semantics/testdata/match_int.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: t = 5;
+  match (t) {
+    case 5 =>
+      return 0;
+    default =>
+      return 1;
+  }
+}

+ 175 - 0
executable_semantics/testdata/match_int.golden

@@ -0,0 +1,175 @@
+********** source program **********
+fn main () -> Int {
+var auto: t = 5;
+match (t) {
+case 5 =>
+return 0;
+case auto: _ =>
+return 1;
+}
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: t = 5;
+match (t) {
+case 5 =>
+return 0;
+case auto: _ =>
+return 1;
+}
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: t = 5; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = 5; ...  --->
+{
+stack: main{var auto: t = 5;<-1> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = 5; --->
+{
+stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 5 with var auto: t = 5;<1>(5,) --->
+{
+stack: main{auto: t<-1> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto: t --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: t<1>(auto,) --->
+{
+stack: main{auto: t<-1> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto: t with var auto: t = 5;<2>(5,auto: t,) --->
+pattern_match(auto: t, 5)
+{
+stack: main{match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step stmt match (t) {...} --->
+{
+stack: main{t<-1> :: match (t) {...}<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp t --->
+{
+stack: main{5<-1> :: match (t) {...}<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value 5 with match (t) {...}<1>(5,) --->
+{
+stack: main{5<-1> :: match (t) {...}<1>(5,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: match (t) {...}<1>(5,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value 5 with match (t) {...}<2>(5,5,) --->
+pattern_match(5, 5)
+{
+stack: main{return 0;<-1> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step stmt return 0; --->
+{
+stack: main{0<-1> :: return 0;<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: return 0;<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value 0 with return 0;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 5, 
+env: main: fun<main>, 
+}
+result: 0

+ 15 - 0
executable_semantics/testdata/match_int_default.6c

@@ -0,0 +1,15 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: t = 5;
+  match (t) {
+    case 3 =>
+      return -1;
+    case 4 =>
+      return -1;
+    default =>
+      return 0;
+  }
+}

+ 217 - 0
executable_semantics/testdata/match_int_default.golden

@@ -0,0 +1,217 @@
+********** source program **********
+fn main () -> Int {
+var auto: t = 5;
+match (t) {
+case 3 =>
+return (- 1);
+case 4 =>
+return (- 1);
+case auto: _ =>
+return 0;
+}
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: t = 5;
+match (t) {
+case 3 =>
+return (- 1);
+case 4 =>
+return (- 1);
+case auto: _ =>
+return 0;
+}
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: t = 5; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = 5; ...  --->
+{
+stack: main{var auto: t = 5;<-1> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = 5; --->
+{
+stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 5 with var auto: t = 5;<1>(5,) --->
+{
+stack: main{auto: t<-1> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto: t --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: t<1>(auto,) --->
+{
+stack: main{auto: t<-1> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto: t with var auto: t = 5;<2>(5,auto: t,) --->
+pattern_match(auto: t, 5)
+{
+stack: main{match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step stmt match (t) {...} --->
+{
+stack: main{t<-1> :: match (t) {...}<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp t --->
+{
+stack: main{5<-1> :: match (t) {...}<0>} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value 5 with match (t) {...}<1>(5,) --->
+{
+stack: main{3<-1> :: match (t) {...}<1>(5,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: match (t) {...}<1>(5,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value 3 with match (t) {...}<2>(5,3,) --->
+pattern_match(3, 5)
+{
+stack: main{4<-1> :: match (t) {...}<3>(5,3,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp 4 --->
+{
+stack: main{4<-1> :: match (t) {...}<3>(5,3,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value 4 with match (t) {...}<4>(5,3,4,) --->
+pattern_match(4, 5)
+{
+stack: main{auto: _<-1> :: match (t) {...}<5>(5,3,4,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp auto: _ --->
+{
+stack: main{auto<-1> :: auto: _<0> :: match (t) {...}<5>(5,3,4,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: _<0> :: match (t) {...}<5>(5,3,4,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value auto with auto: _<1>(auto,) --->
+{
+stack: main{auto: _<-1> :: match (t) {...}<5>(5,3,4,)} :: top{}
+heap: fun<main>, 5, 
+env: t: 5, main: fun<main>, 
+}
+--- handle value auto: _ with match (t) {...}<6>(5,3,4,auto: _,) --->
+pattern_match(auto: _, 5)
+{
+stack: main{return 0;<-1> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 5, 
+env: _: 5, t: 5, main: fun<main>, 
+}
+--- step stmt return 0; --->
+{
+stack: main{0<-1> :: return 0;<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 5, 
+env: _: 5, t: 5, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: return 0;<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 5, 
+env: _: 5, t: 5, main: fun<main>, 
+}
+--- handle value 0 with return 0;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 5, !!5, 
+env: main: fun<main>, 
+}
+result: 0

+ 21 - 0
executable_semantics/testdata/match_type.6c

@@ -0,0 +1,21 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: t = fnty (Int,Int);
+  var Int: x = 0;
+//  match (t) {
+//    case fnty(Int: x, Int: y): z =>
+//      x = x - 1;
+//  }
+  match (t) {
+    case fnty(Int,Int): z =>
+      x = x + 1;
+  }
+  match (t) {
+    case fnty(Type: a,Type: b) =>
+      x = x - 1;
+  }
+  return x;
+}

+ 653 - 0
executable_semantics/testdata/match_type.golden

@@ -0,0 +1,653 @@
+********** source program **********
+fn main () -> Int {
+var auto: t = fn (0 = Int, 1 = Int) -> ();
+var Int: x = 0;
+match (t) {
+case fn (0 = Int, 1 = Int) -> (): z =>
+x = (x + 1);
+}
+match (t) {
+case fn (0 = Type: a, 1 = Type: b) -> () =>
+x = (x - 1);
+}
+return x;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp (0 = Int, 1 = Int) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+--- step exp () --->
+--- step exp auto --->
+--- step exp Int --->
+--- step exp fn (0 = Int, 1 = Int) -> () --->
+--- step exp (0 = Int, 1 = Int) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+--- handle value (0 = Int@2, 1 = Int@3) with fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@2, 1 = Int@3),) --->
+--- step exp () --->
+--- handle value () with fn (0 = Int, 1 = Int) -> ()<2>((0 = Int@2, 1 = Int@3),(),) --->
+--- step exp Type --->
+--- step exp Type --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: t = fn (0 = Int, 1 = Int) -> ();
+var Int: x = 0;
+match (t) {
+case fn (0 = Int, 1 = Int) -> (): z =>
+x = (x + 1);
+}
+match (t) {
+case fn (0 = Type: a, 1 = Type: b) -> () =>
+x = (x - 1);
+}
+return x;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: t = fn (0 = Int, 1 = Int) -> (); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = fn (0 = Int, 1 = Int) -> (); ...  --->
+{
+stack: main{var auto: t = fn (0 = Int, 1 = Int) -> ();<-1> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = fn (0 = Int, 1 = Int) -> (); --->
+{
+stack: main{fn (0 = Int, 1 = Int) -> ()<-1> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp fn (0 = Int, 1 = Int) -> () --->
+{
+stack: main{(0 = Int, 1 = Int)<-1> :: fn (0 = Int, 1 = Int) -> ()<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp (0 = Int, 1 = Int) --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<0> :: fn (0 = Int, 1 = Int) -> ()<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<0> :: fn (0 = Int, 1 = Int) -> ()<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<1>(Int,) :: fn (0 = Int, 1 = Int) -> ()<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<1>(Int,) :: fn (0 = Int, 1 = Int) -> ()<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+{
+stack: main{(0 = Int@1, 1 = Int@2)<-1> :: fn (0 = Int, 1 = Int) -> ()<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value (0 = Int@1, 1 = Int@2) with fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@1, 1 = Int@2),) --->
+{
+stack: main{()<-1> :: fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@1, 1 = Int@2),) :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: main{()<-1> :: fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@1, 1 = Int@2),) :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value () with fn (0 = Int, 1 = Int) -> ()<2>((0 = Int@1, 1 = Int@2),(),) --->
+{
+stack: main{fn (0 = Int@1, 1 = Int@2) -> ()<-1> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<0> :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value fn (0 = Int@1, 1 = Int@2) -> () with var auto: t = fn (0 = Int, 1 = Int) -> ();<1>(fn (0 = Int@1, 1 = Int@2) -> (),) --->
+{
+stack: main{auto: t<-1> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<1>(fn (0 = Int@1, 1 = Int@2) -> (),) :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- step exp auto: t --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<1>(fn (0 = Int@1, 1 = Int@2) -> (),) :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<1>(fn (0 = Int@1, 1 = Int@2) -> (),) :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: t<1>(auto,) --->
+{
+stack: main{auto: t<-1> :: var auto: t = fn (0 = Int, 1 = Int) -> ();<1>(fn (0 = Int@1, 1 = Int@2) -> (),) :: var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value auto: t with var auto: t = fn (0 = Int, 1 = Int) -> ();<2>(fn (0 = Int@1, 1 = Int@2) -> (),auto: t,) --->
+pattern_match(auto: t, fn (0 = Int@1, 1 = Int@2) -> ())
+{
+stack: main{var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt var Int: x = 0; ...  --->
+{
+stack: main{var Int: x = 0;<-1> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt var Int: x = 0; --->
+{
+stack: main{0<-1> :: var Int: x = 0;<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: var Int: x = 0;<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 0 with var Int: x = 0;<1>(0,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Int: x --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Int with Int: x<1>(Int,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 
+env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Int: x with var Int: x = 0;<2>(0,Int: x,) --->
+pattern_match(Int: x, 0)
+{
+stack: main{match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt match (t) {...} ...  --->
+{
+stack: main{match (t) {...}<-1> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt match (t) {...} --->
+{
+stack: main{t<-1> :: match (t) {...}<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp t --->
+{
+stack: main{fn (0 = Int@3, 1 = Int@4) -> ()<-1> :: match (t) {...}<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value fn (0 = Int@3, 1 = Int@4) -> () with match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) --->
+{
+stack: main{fn (0 = Int, 1 = Int) -> (): z<-1> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp fn (0 = Int, 1 = Int) -> (): z --->
+{
+stack: main{fn (0 = Int, 1 = Int) -> ()<-1> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp fn (0 = Int, 1 = Int) -> () --->
+{
+stack: main{(0 = Int, 1 = Int)<-1> :: fn (0 = Int, 1 = Int) -> ()<0> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp (0 = Int, 1 = Int) --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<0> :: fn (0 = Int, 1 = Int) -> ()<0> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<0> :: fn (0 = Int, 1 = Int) -> ()<0> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<1>(Int,) :: fn (0 = Int, 1 = Int) -> ()<0> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<1>(Int,) :: fn (0 = Int, 1 = Int) -> ()<0> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+{
+stack: main{(0 = Int@7, 1 = Int@8)<-1> :: fn (0 = Int, 1 = Int) -> ()<0> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value (0 = Int@7, 1 = Int@8) with fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@7, 1 = Int@8),) --->
+{
+stack: main{()<-1> :: fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@7, 1 = Int@8),) :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: main{()<-1> :: fn (0 = Int, 1 = Int) -> ()<1>((0 = Int@7, 1 = Int@8),) :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value () with fn (0 = Int, 1 = Int) -> ()<2>((0 = Int@7, 1 = Int@8),(),) --->
+{
+stack: main{fn (0 = Int@7, 1 = Int@8) -> ()<-1> :: fn (0 = Int, 1 = Int) -> (): z<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value fn (0 = Int@7, 1 = Int@8) -> () with fn (0 = Int, 1 = Int) -> (): z<1>(fn (0 = Int@7, 1 = Int@8) -> (),) --->
+{
+stack: main{fn (0 = Int@7, 1 = Int@8) -> (): z<-1> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value fn (0 = Int@7, 1 = Int@8) -> (): z with match (t) {...}<2>(fn (0 = Int@3, 1 = Int@4) -> (),fn (0 = Int@7, 1 = Int@8) -> (): z,) --->
+pattern_match(fn (0 = Int@7, 1 = Int@8) -> (): z, fn (0 = Int@3, 1 = Int@4) -> ())
+{
+stack: main{x = (x + 1);<-1> :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt x = (x + 1); --->
+{
+stack: main{x<-1> :: x = (x + 1);<0> :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<6><-1> :: x = (x + 1);<0> :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value ptr<6> with x = (x + 1);<1>(ptr<6>,) --->
+{
+stack: main{(x + 1)<-1> :: x = (x + 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp (x + 1) --->
+{
+stack: main{x<-1> :: (x + 1)<0> :: x = (x + 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: (x + 1)<0> :: x = (x + 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 0 with (x + 1)<1>(0,) --->
+{
+stack: main{1<-1> :: (x + 1)<1>(0,) :: x = (x + 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x + 1)<1>(0,) :: x = (x + 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 1 with (x + 1)<2>(0,1,) --->
+{
+stack: main{1<-1> :: x = (x + 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 1 with x = (x + 1);<2>(ptr<6>,1,) --->
+{
+stack: main{{
+ ... 
+}
+<0> :: match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, fn (0 = Int@9, 1 = Int@10) -> (), 
+env: z: fn (0 = Int@9, 1 = Int@10) -> (), x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{match (t) {...} ... <-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt match (t) {...} ...  --->
+{
+stack: main{match (t) {...}<-1> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt match (t) {...} --->
+{
+stack: main{t<-1> :: match (t) {...}<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp t --->
+{
+stack: main{fn (0 = Int@3, 1 = Int@4) -> ()<-1> :: match (t) {...}<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value fn (0 = Int@3, 1 = Int@4) -> () with match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) --->
+{
+stack: main{fn (0 = Type: a, 1 = Type: b) -> ()<-1> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp fn (0 = Type: a, 1 = Type: b) -> () --->
+{
+stack: main{(0 = Type: a, 1 = Type: b)<-1> :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp (0 = Type: a, 1 = Type: b) --->
+{
+stack: main{Type: a<-1> :: (0 = Type: a, 1 = Type: b)<0> :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Type: a --->
+{
+stack: main{Type<-1> :: Type: a<0> :: (0 = Type: a, 1 = Type: b)<0> :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Type --->
+{
+stack: main{Type<-1> :: Type: a<0> :: (0 = Type: a, 1 = Type: b)<0> :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Type with Type: a<1>(Type,) --->
+{
+stack: main{Type: a<-1> :: (0 = Type: a, 1 = Type: b)<0> :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Type: a with (0 = Type: a, 1 = Type: b)<1>(Type: a,) --->
+{
+stack: main{Type: b<-1> :: (0 = Type: a, 1 = Type: b)<1>(Type: a,) :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Type: b --->
+{
+stack: main{Type<-1> :: Type: b<0> :: (0 = Type: a, 1 = Type: b)<1>(Type: a,) :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp Type --->
+{
+stack: main{Type<-1> :: Type: b<0> :: (0 = Type: a, 1 = Type: b)<1>(Type: a,) :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Type with Type: b<1>(Type,) --->
+{
+stack: main{Type: b<-1> :: (0 = Type: a, 1 = Type: b)<1>(Type: a,) :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value Type: b with (0 = Type: a, 1 = Type: b)<2>(Type: a,Type: b,) --->
+{
+stack: main{(0 = Type: a@12, 1 = Type: b@13)<-1> :: fn (0 = Type: a, 1 = Type: b) -> ()<0> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value (0 = Type: a@12, 1 = Type: b@13) with fn (0 = Type: a, 1 = Type: b) -> ()<1>((0 = Type: a@12, 1 = Type: b@13),) --->
+{
+stack: main{()<-1> :: fn (0 = Type: a, 1 = Type: b) -> ()<1>((0 = Type: a@12, 1 = Type: b@13),) :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: main{()<-1> :: fn (0 = Type: a, 1 = Type: b) -> ()<1>((0 = Type: a@12, 1 = Type: b@13),) :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value () with fn (0 = Type: a, 1 = Type: b) -> ()<2>((0 = Type: a@12, 1 = Type: b@13),(),) --->
+{
+stack: main{fn (0 = Type: a@12, 1 = Type: b@13) -> ()<-1> :: match (t) {...}<1>(fn (0 = Int@3, 1 = Int@4) -> (),) :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, 
+env: x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value fn (0 = Type: a@12, 1 = Type: b@13) -> () with match (t) {...}<2>(fn (0 = Int@3, 1 = Int@4) -> (),fn (0 = Type: a@12, 1 = Type: b@13) -> (),) --->
+pattern_match(fn (0 = Type: a@12, 1 = Type: b@13) -> (), fn (0 = Int@3, 1 = Int@4) -> ())
+pattern_match((0 = Type: a@12, 1 = Type: b@13), (0 = Int@3, 1 = Int@4))
+pattern_match(Type: a, Int)
+pattern_match(Type: b, Int)
+pattern_match((), ())
+{
+stack: main{x = (x - 1);<-1> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<6><-1> :: x = (x - 1);<0> :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value ptr<6> with x = (x - 1);<1>(ptr<6>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: x = (x - 1);<1>(ptr<6>,) :: {
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 1, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 1, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 0 with x = (x - 1);<2>(ptr<6>,0,) --->
+{
+stack: main{{
+ ... 
+}
+<0> :: return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, Int, Int, 
+env: b: Int, a: Int, x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt {
+ ... 
+}
+ --->
+{
+stack: main{return x;<-1>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, !!Int, !!Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step stmt return x; --->
+{
+stack: main{x<-1> :: return x;<0>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, !!Int, !!Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: return x;<0>} :: top{}
+heap: fun<main>, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), 0, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, !!Int, !!Int, 
+env: x: 0, t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun<main>, 
+}
+--- handle value 0 with return x;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, Int, Int, Int, Int, !!fn (0 = Int@3, 1 = Int@4) -> (), !!0, Int, Int, Int, Int, !!fn (0 = Int@9, 1 = Int@10) -> (), Type: a, Type: b, !!Int, !!Int, 
+env: main: fun<main>, 
+}
+result: 0

+ 9 - 0
executable_semantics/testdata/next.6c

@@ -0,0 +1,9 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main () -> Int
+{
+  var Int: x = 0;
+  return x;
+}

+ 124 - 0
executable_semantics/testdata/next.golden

@@ -0,0 +1,124 @@
+********** source program **********
+fn main () -> Int {
+var Int: x = 0;
+return x;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn main () -> Int {
+var Int: x = 0;
+return x;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var Int: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 0; ...  --->
+{
+stack: main{var Int: x = 0;<-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 0; --->
+{
+stack: main{0<-1> :: var Int: x = 0;<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: var Int: x = 0;<0> :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 0 with var Int: x = 0;<1>(0,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int: x --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int with Int: x<1>(Int,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: return x;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int: x with var Int: x = 0;<2>(0,Int: x,) --->
+pattern_match(Int: x, 0)
+{
+stack: main{return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt return x; --->
+{
+stack: main{x<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with return x;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!0, 
+env: main: fun<main>, 
+}
+result: 0

+ 8 - 0
executable_semantics/testdata/pattern_init.6c

@@ -0,0 +1,8 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var (auto: x, auto: y) = (2, 3);
+  return y - x - 1;
+}

+ 235 - 0
executable_semantics/testdata/pattern_init.golden

@@ -0,0 +1,235 @@
+********** source program **********
+fn main () -> Int {
+var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);
+return ((y - x) - 1);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);
+return ((y - x) - 1);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3); ...  --->
+{
+stack: main{var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<-1> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3); --->
+{
+stack: main{(0 = 2, 1 = 3)<-1> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<0> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp (0 = 2, 1 = 3) --->
+{
+stack: main{2<-1> :: (0 = 2, 1 = 3)<0> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<0> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (0 = 2, 1 = 3)<0> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<0> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 2 with (0 = 2, 1 = 3)<1>(2,) --->
+{
+stack: main{3<-1> :: (0 = 2, 1 = 3)<1>(2,) :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<0> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: (0 = 2, 1 = 3)<1>(2,) :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<0> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 3 with (0 = 2, 1 = 3)<2>(2,3,) --->
+{
+stack: main{(0 = 2@1, 1 = 3@2)<-1> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<0> :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- handle value (0 = 2@1, 1 = 3@2) with var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) --->
+{
+stack: main{(0 = auto: x, 1 = auto: y)<-1> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- step exp (0 = auto: x, 1 = auto: y) --->
+{
+stack: main{auto: x<-1> :: (0 = auto: x, 1 = auto: y)<0> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- step exp auto: x --->
+{
+stack: main{auto<-1> :: auto: x<0> :: (0 = auto: x, 1 = auto: y)<0> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: x<0> :: (0 = auto: x, 1 = auto: y)<0> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: x<1>(auto,) --->
+{
+stack: main{auto: x<-1> :: (0 = auto: x, 1 = auto: y)<0> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- handle value auto: x with (0 = auto: x, 1 = auto: y)<1>(auto: x,) --->
+{
+stack: main{auto: y<-1> :: (0 = auto: x, 1 = auto: y)<1>(auto: x,) :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- step exp auto: y --->
+{
+stack: main{auto<-1> :: auto: y<0> :: (0 = auto: x, 1 = auto: y)<1>(auto: x,) :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: y<0> :: (0 = auto: x, 1 = auto: y)<1>(auto: x,) :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: y<1>(auto,) --->
+{
+stack: main{auto: y<-1> :: (0 = auto: x, 1 = auto: y)<1>(auto: x,) :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, 
+env: main: fun<main>, 
+}
+--- handle value auto: y with (0 = auto: x, 1 = auto: y)<2>(auto: x,auto: y,) --->
+{
+stack: main{(0 = auto: x@3, 1 = auto: y@4)<-1> :: var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<1>((0 = 2@1, 1 = 3@2),) :: return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 
+env: main: fun<main>, 
+}
+--- handle value (0 = auto: x@3, 1 = auto: y@4) with var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3);<2>((0 = 2@1, 1 = 3@2),(0 = auto: x@3, 1 = auto: y@4),) --->
+pattern_match((0 = auto: x@3, 1 = auto: y@4), (0 = 2@1, 1 = 3@2))
+pattern_match(auto: x, 2)
+pattern_match(auto: y, 3)
+{
+stack: main{return ((y - x) - 1);<-1>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- step stmt return ((y - x) - 1); --->
+{
+stack: main{((y - x) - 1)<-1> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- step exp ((y - x) - 1) --->
+{
+stack: main{(y - x)<-1> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- step exp (y - x) --->
+{
+stack: main{y<-1> :: (y - x)<0> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- step exp y --->
+{
+stack: main{3<-1> :: (y - x)<0> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- handle value 3 with (y - x)<1>(3,) --->
+{
+stack: main{x<-1> :: (y - x)<1>(3,) :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (y - x)<1>(3,) :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- handle value 2 with (y - x)<2>(3,2,) --->
+{
+stack: main{1<-1> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- handle value 1 with ((y - x) - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: ((y - x) - 1)<1>(1,) :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: ((y - x) - 1)<1>(1,) :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- handle value 1 with ((y - x) - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: return ((y - x) - 1);<0>} :: top{}
+heap: fun<main>, 2, 3, auto: x, auto: y, 2, 3, 
+env: y: 3, x: 2, main: fun<main>, 
+}
+--- handle value 0 with return ((y - x) - 1);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 2, 3, auto: x, auto: y, !!2, !!3, 
+env: main: fun<main>, 
+}
+result: 0

+ 9 - 0
executable_semantics/testdata/record1.6c

@@ -0,0 +1,9 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var (.x = Int, .y = Int): t2 = (.y = 5, .x = 2);
+  t2.y = 3;
+  return t2.y - t2.x - 1; // 3 - 2 - 1
+}

+ 298 - 0
executable_semantics/testdata/record1.golden

@@ -0,0 +1,298 @@
+********** source program **********
+fn main () -> Int {
+var (x = Int, y = Int): t2 = (y = 5, x = 2);
+t2.y = 3;
+return ((t2.y - t2.x) - 1);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp (x = Int, y = Int) --->
+--- step exp Int --->
+--- handle value Int with (x = Int, y = Int)<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with (x = Int, y = Int)<2>(Int,Int,) --->
+
+********** type checking complete **********
+fn main () -> Int {
+var (x = Int, y = Int): t2 = (y = 5, x = 2);
+t2.y = 3;
+return ((t2.y - t2.x) - 1);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var (x = Int, y = Int): t2 = (y = 5, x = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var (x = Int, y = Int): t2 = (y = 5, x = 2); ...  --->
+{
+stack: main{var (x = Int, y = Int): t2 = (y = 5, x = 2);<-1> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var (x = Int, y = Int): t2 = (y = 5, x = 2); --->
+{
+stack: main{(y = 5, x = 2)<-1> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<0> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp (y = 5, x = 2) --->
+{
+stack: main{5<-1> :: (y = 5, x = 2)<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<0> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (y = 5, x = 2)<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<0> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 5 with (y = 5, x = 2)<1>(5,) --->
+{
+stack: main{2<-1> :: (y = 5, x = 2)<1>(5,) :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<0> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (y = 5, x = 2)<1>(5,) :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<0> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 2 with (y = 5, x = 2)<2>(5,2,) --->
+{
+stack: main{(y = 5@1, x = 2@2)<-1> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<0> :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- handle value (y = 5@1, x = 2@2) with var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) --->
+{
+stack: main{(x = Int, y = Int): t2<-1> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- step exp (x = Int, y = Int): t2 --->
+{
+stack: main{(x = Int, y = Int)<-1> :: (x = Int, y = Int): t2<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- step exp (x = Int, y = Int) --->
+{
+stack: main{Int<-1> :: (x = Int, y = Int)<0> :: (x = Int, y = Int): t2<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (x = Int, y = Int)<0> :: (x = Int, y = Int): t2<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- handle value Int with (x = Int, y = Int)<1>(Int,) --->
+{
+stack: main{Int<-1> :: (x = Int, y = Int)<1>(Int,) :: (x = Int, y = Int): t2<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (x = Int, y = Int)<1>(Int,) :: (x = Int, y = Int): t2<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- handle value Int with (x = Int, y = Int)<2>(Int,Int,) --->
+{
+stack: main{(x = Int@3, y = Int@4)<-1> :: (x = Int, y = Int): t2<0> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value (x = Int@3, y = Int@4) with (x = Int, y = Int): t2<1>((x = Int@3, y = Int@4),) --->
+{
+stack: main{(x = Int@3, y = Int@4): t2<-1> :: var (x = Int, y = Int): t2 = (y = 5, x = 2);<1>((y = 5@1, x = 2@2),) :: t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 
+env: main: fun<main>, 
+}
+--- handle value (x = Int@3, y = Int@4): t2 with var (x = Int, y = Int): t2 = (y = 5, x = 2);<2>((y = 5@1, x = 2@2),(x = Int@3, y = Int@4): t2,) --->
+pattern_match((x = Int@3, y = Int@4): t2, (y = 5@1, x = 2@2))
+{
+stack: main{t2.y = 3; ... <-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- step stmt t2.y = 3; ...  --->
+{
+stack: main{t2.y = 3;<-1> :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- step stmt t2.y = 3; --->
+{
+stack: main{t2.y<-1> :: t2.y = 3;<0> :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- step lvalue t2.y --->
+{
+stack: main{t2<-1> :: t2.y<0> :: t2.y = 3;<0> :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- step lvalue t2 --->
+{
+stack: main{ptr<7><-1> :: t2.y<0> :: t2.y = 3;<0> :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- handle value ptr<7> with t2.y<1>(ptr<7>,) --->
+{
+stack: main{ptr<5><-1> :: t2.y = 3;<0> :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- handle value ptr<5> with t2.y = 3;<1>(ptr<5>,) --->
+{
+stack: main{3<-1> :: t2.y = 3;<1>(ptr<5>,) :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: t2.y = 3;<1>(ptr<5>,) :: return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), 
+env: t2: (y = 5@5, x = 2@6), main: fun<main>, 
+}
+--- handle value 3 with t2.y = 3;<2>(ptr<5>,3,) --->
+{
+stack: main{return ((t2.y - t2.x) - 1);<-1>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step stmt return ((t2.y - t2.x) - 1); --->
+{
+stack: main{((t2.y - t2.x) - 1)<-1> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step exp ((t2.y - t2.x) - 1) --->
+{
+stack: main{(t2.y - t2.x)<-1> :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step exp (t2.y - t2.x) --->
+{
+stack: main{t2.y<-1> :: (t2.y - t2.x)<0> :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step exp t2.y --->
+{
+stack: main{t2<-1> :: t2.y<0> :: (t2.y - t2.x)<0> :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step lvalue t2 --->
+{
+stack: main{ptr<7><-1> :: t2.y<0> :: (t2.y - t2.x)<0> :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value ptr<7> with t2.y<1>(ptr<7>,) --->
+{
+stack: main{3<-1> :: (t2.y - t2.x)<0> :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value 3 with (t2.y - t2.x)<1>(3,) --->
+{
+stack: main{t2.x<-1> :: (t2.y - t2.x)<1>(3,) :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step exp t2.x --->
+{
+stack: main{t2<-1> :: t2.x<0> :: (t2.y - t2.x)<1>(3,) :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step lvalue t2 --->
+{
+stack: main{ptr<7><-1> :: t2.x<0> :: (t2.y - t2.x)<1>(3,) :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value ptr<7> with t2.x<1>(ptr<7>,) --->
+{
+stack: main{2<-1> :: (t2.y - t2.x)<1>(3,) :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value 2 with (t2.y - t2.x)<2>(3,2,) --->
+{
+stack: main{1<-1> :: ((t2.y - t2.x) - 1)<0> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value 1 with ((t2.y - t2.x) - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: ((t2.y - t2.x) - 1)<1>(1,) :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: ((t2.y - t2.x) - 1)<1>(1,) :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value 1 with ((t2.y - t2.x) - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: return ((t2.y - t2.x) - 1);<0>} :: top{}
+heap: fun<main>, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), 
+env: t2: (y = 3@5, x = 2@6), main: fun<main>, 
+}
+--- handle value 0 with return ((t2.y - t2.x) - 1);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 5, 2, Int, Int, !!3, !!2, !!(y = !!3@5, x = !!2@6), 
+env: main: fun<main>, 
+}
+result: 0

+ 13 - 0
executable_semantics/testdata/struct1.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+struct Point {
+  var Int: x;
+  var Int: y;
+}
+
+fn main() -> Int {
+  var auto: p = Point(.x = 1, .y = 2);
+  return p.y - p.x - 1;
+}

+ 256 - 0
executable_semantics/testdata/struct1.golden

@@ -0,0 +1,256 @@
+********** source program **********
+struct Point {
+var x : Int;
+var y : Int;
+}
+fn main () -> Int {
+var auto: p = Point(x = 1, y = 2);
+return ((p.y - p.x) - 1);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+
+********** type checking complete **********
+struct Point {
+var x : Int;
+var y : Int;
+}
+fn main () -> Int {
+var auto: p = Point(x = 1, y = 2);
+return ((p.y - p.x) - 1);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: p = Point(x = 1, y = 2); ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step stmt var auto: p = Point(x = 1, y = 2); ...  --->
+{
+stack: main{var auto: p = Point(x = 1, y = 2);<-1> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step stmt var auto: p = Point(x = 1, y = 2); --->
+{
+stack: main{Point(x = 1, y = 2)<-1> :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point(x = 1, y = 2) --->
+{
+stack: main{Point<-1> :: Point(x = 1, y = 2)<0> :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point --->
+{
+stack: main{struct Point<-1> :: Point(x = 1, y = 2)<0> :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value struct Point with Point(x = 1, y = 2)<1>(struct Point,) --->
+{
+stack: main{(x = 1, y = 2)<-1> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp (x = 1, y = 2) --->
+{
+stack: main{1<-1> :: (x = 1, y = 2)<0> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x = 1, y = 2)<0> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (x = 1, y = 2)<1>(1,) --->
+{
+stack: main{2<-1> :: (x = 1, y = 2)<1>(1,) :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (x = 1, y = 2)<1>(1,) :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 2 with (x = 1, y = 2)<2>(1,2,) --->
+{
+stack: main{(x = 1@2, y = 2@3)<-1> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value (x = 1@2, y = 2@3) with Point(x = 1, y = 2)<2>(struct Point,(x = 1@2, y = 2@3),) --->
+{
+stack: main{Point(x = 1@4, y = 2@5)<-1> :: var auto: p = Point(x = 1, y = 2);<0> :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value Point(x = 1@4, y = 2@5) with var auto: p = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) --->
+{
+stack: main{auto: p<-1> :: var auto: p = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp auto: p --->
+{
+stack: main{auto<-1> :: auto: p<0> :: var auto: p = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: p<0> :: var auto: p = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value auto with auto: p<1>(auto,) --->
+{
+stack: main{auto: p<-1> :: var auto: p = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value auto: p with var auto: p = Point(x = 1, y = 2);<2>(Point(x = 1@4, y = 2@5),auto: p,) --->
+pattern_match(auto: p, Point(x = 1@4, y = 2@5))
+{
+stack: main{return ((p.y - p.x) - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step stmt return ((p.y - p.x) - 1); --->
+{
+stack: main{((p.y - p.x) - 1)<-1> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp ((p.y - p.x) - 1) --->
+{
+stack: main{(p.y - p.x)<-1> :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp (p.y - p.x) --->
+{
+stack: main{p.y<-1> :: (p.y - p.x)<0> :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp p.y --->
+{
+stack: main{p<-1> :: p.y<0> :: (p.y - p.x)<0> :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step lvalue p --->
+{
+stack: main{ptr<8><-1> :: p.y<0> :: (p.y - p.x)<0> :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value ptr<8> with p.y<1>(ptr<8>,) --->
+{
+stack: main{2<-1> :: (p.y - p.x)<0> :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 2 with (p.y - p.x)<1>(2,) --->
+{
+stack: main{p.x<-1> :: (p.y - p.x)<1>(2,) :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp p.x --->
+{
+stack: main{p<-1> :: p.x<0> :: (p.y - p.x)<1>(2,) :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step lvalue p --->
+{
+stack: main{ptr<8><-1> :: p.x<0> :: (p.y - p.x)<1>(2,) :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value ptr<8> with p.x<1>(ptr<8>,) --->
+{
+stack: main{1<-1> :: (p.y - p.x)<1>(2,) :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (p.y - p.x)<2>(2,1,) --->
+{
+stack: main{1<-1> :: ((p.y - p.x) - 1)<0> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with ((p.y - p.x) - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: ((p.y - p.x) - 1)<1>(1,) :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: ((p.y - p.x) - 1)<1>(1,) :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with ((p.y - p.x) - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: return ((p.y - p.x) - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 0 with return ((p.y - p.x) - 1);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: struct Point, fun<main>, 1, 2, 1, 2, !!1, !!2, !!Point!!(x = !!1@6, y = !!2@7), 
+env: main: fun<main>, Point: struct Point, 
+}
+result: 0

+ 15 - 0
executable_semantics/testdata/struct2.6c

@@ -0,0 +1,15 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+struct Point {
+  var Int: x;
+  var Int: y;
+}
+
+fn main() -> Int {
+  var auto: p1 = Point(.x = 1, .y = 2);
+  var auto: p2 = p1;
+  p2.x = 3;
+  return p1.x - 1;
+}

+ 322 - 0
executable_semantics/testdata/struct2.golden

@@ -0,0 +1,322 @@
+********** source program **********
+struct Point {
+var x : Int;
+var y : Int;
+}
+fn main () -> Int {
+var auto: p1 = Point(x = 1, y = 2);
+var auto: p2 = p1;
+p2.x = 3;
+return (p1.x - 1);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp auto --->
+
+********** type checking complete **********
+struct Point {
+var x : Int;
+var y : Int;
+}
+fn main () -> Int {
+var auto: p1 = Point(x = 1, y = 2);
+var auto: p2 = p1;
+p2.x = 3;
+return (p1.x - 1);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: p1 = Point(x = 1, y = 2); ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step stmt var auto: p1 = Point(x = 1, y = 2); ...  --->
+{
+stack: main{var auto: p1 = Point(x = 1, y = 2);<-1> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step stmt var auto: p1 = Point(x = 1, y = 2); --->
+{
+stack: main{Point(x = 1, y = 2)<-1> :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point(x = 1, y = 2) --->
+{
+stack: main{Point<-1> :: Point(x = 1, y = 2)<0> :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point --->
+{
+stack: main{struct Point<-1> :: Point(x = 1, y = 2)<0> :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value struct Point with Point(x = 1, y = 2)<1>(struct Point,) --->
+{
+stack: main{(x = 1, y = 2)<-1> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp (x = 1, y = 2) --->
+{
+stack: main{1<-1> :: (x = 1, y = 2)<0> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x = 1, y = 2)<0> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (x = 1, y = 2)<1>(1,) --->
+{
+stack: main{2<-1> :: (x = 1, y = 2)<1>(1,) :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (x = 1, y = 2)<1>(1,) :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 2 with (x = 1, y = 2)<2>(1,2,) --->
+{
+stack: main{(x = 1@2, y = 2@3)<-1> :: Point(x = 1, y = 2)<1>(struct Point,) :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value (x = 1@2, y = 2@3) with Point(x = 1, y = 2)<2>(struct Point,(x = 1@2, y = 2@3),) --->
+{
+stack: main{Point(x = 1@4, y = 2@5)<-1> :: var auto: p1 = Point(x = 1, y = 2);<0> :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value Point(x = 1@4, y = 2@5) with var auto: p1 = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) --->
+{
+stack: main{auto: p1<-1> :: var auto: p1 = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp auto: p1 --->
+{
+stack: main{auto<-1> :: auto: p1<0> :: var auto: p1 = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: p1<0> :: var auto: p1 = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value auto with auto: p1<1>(auto,) --->
+{
+stack: main{auto: p1<-1> :: var auto: p1 = Point(x = 1, y = 2);<1>(Point(x = 1@4, y = 2@5),) :: var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value auto: p1 with var auto: p1 = Point(x = 1, y = 2);<2>(Point(x = 1@4, y = 2@5),auto: p1,) --->
+pattern_match(auto: p1, Point(x = 1@4, y = 2@5))
+{
+stack: main{var auto: p2 = p1; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step stmt var auto: p2 = p1; ...  --->
+{
+stack: main{var auto: p2 = p1;<-1> :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step stmt var auto: p2 = p1; --->
+{
+stack: main{p1<-1> :: var auto: p2 = p1;<0> :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp p1 --->
+{
+stack: main{Point(x = 1@6, y = 2@7)<-1> :: var auto: p2 = p1;<0> :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value Point(x = 1@6, y = 2@7) with var auto: p2 = p1;<1>(Point(x = 1@6, y = 2@7),) --->
+{
+stack: main{auto: p2<-1> :: var auto: p2 = p1;<1>(Point(x = 1@6, y = 2@7),) :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp auto: p2 --->
+{
+stack: main{auto<-1> :: auto: p2<0> :: var auto: p2 = p1;<1>(Point(x = 1@6, y = 2@7),) :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: p2<0> :: var auto: p2 = p1;<1>(Point(x = 1@6, y = 2@7),) :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value auto with auto: p2<1>(auto,) --->
+{
+stack: main{auto: p2<-1> :: var auto: p2 = p1;<1>(Point(x = 1@6, y = 2@7),) :: p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 
+env: p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value auto: p2 with var auto: p2 = p1;<2>(Point(x = 1@6, y = 2@7),auto: p2,) --->
+pattern_match(auto: p2, Point(x = 1@6, y = 2@7))
+{
+stack: main{p2.x = 3; ... <-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step stmt p2.x = 3; ...  --->
+{
+stack: main{p2.x = 3;<-1> :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step stmt p2.x = 3; --->
+{
+stack: main{p2.x<-1> :: p2.x = 3;<0> :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step lvalue p2.x --->
+{
+stack: main{p2<-1> :: p2.x<0> :: p2.x = 3;<0> :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step lvalue p2 --->
+{
+stack: main{ptr<11><-1> :: p2.x<0> :: p2.x = 3;<0> :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value ptr<11> with p2.x<1>(ptr<11>,) --->
+{
+stack: main{ptr<9><-1> :: p2.x = 3;<0> :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value ptr<9> with p2.x = 3;<1>(ptr<9>,) --->
+{
+stack: main{3<-1> :: p2.x = 3;<1>(ptr<9>,) :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: p2.x = 3;<1>(ptr<9>,) :: return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 1, 2, Point(x = 1@9, y = 2@10), 
+env: p2: Point(x = 1@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 3 with p2.x = 3;<2>(ptr<9>,3,) --->
+{
+stack: main{return (p1.x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step stmt return (p1.x - 1); --->
+{
+stack: main{(p1.x - 1)<-1> :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp (p1.x - 1) --->
+{
+stack: main{p1.x<-1> :: (p1.x - 1)<0> :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp p1.x --->
+{
+stack: main{p1<-1> :: p1.x<0> :: (p1.x - 1)<0> :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step lvalue p1 --->
+{
+stack: main{ptr<8><-1> :: p1.x<0> :: (p1.x - 1)<0> :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value ptr<8> with p1.x<1>(ptr<8>,) --->
+{
+stack: main{1<-1> :: (p1.x - 1)<0> :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (p1.x - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: (p1.x - 1)<1>(1,) :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (p1.x - 1)<1>(1,) :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (p1.x - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: return (p1.x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), 3, 2, Point(x = 3@9, y = 2@10), 
+env: p2: Point(x = 3@9, y = 2@10), p1: Point(x = 1@6, y = 2@7), main: fun<main>, Point: struct Point, 
+}
+--- handle value 0 with return (p1.x - 1);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: struct Point, fun<main>, 1, 2, 1, 2, !!1, !!2, !!Point!!(x = !!1@6, y = !!2@7), !!3, !!2, !!Point!!(x = !!3@9, y = !!2@10), 
+env: main: fun<main>, Point: struct Point, 
+}
+result: 0

+ 12 - 0
executable_semantics/testdata/struct3.6c

@@ -0,0 +1,12 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+struct Point {
+  var Int: x;
+  var Int: y;
+}
+
+fn main() -> Int {
+  return Point(.x = 1, .y = 2).x - 1;
+}

+ 186 - 0
executable_semantics/testdata/struct3.golden

@@ -0,0 +1,186 @@
+********** source program **********
+struct Point {
+var x : Int;
+var y : Int;
+}
+fn main () -> Int {
+return (Point(x = 1, y = 2).x - 1);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+
+********** type checking complete **********
+struct Point {
+var x : Int;
+var y : Int;
+}
+fn main () -> Int {
+return (Point(x = 1, y = 2).x - 1);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{return (Point(x = 1, y = 2).x - 1);<-1>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step stmt return (Point(x = 1, y = 2).x - 1); --->
+{
+stack: main{(Point(x = 1, y = 2).x - 1)<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp (Point(x = 1, y = 2).x - 1) --->
+{
+stack: main{Point(x = 1, y = 2).x<-1> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point(x = 1, y = 2).x --->
+{
+stack: main{Point(x = 1, y = 2)<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step lvalue Point(x = 1, y = 2) --->
+{
+stack: main{Point(x = 1, y = 2)<-1> :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point(x = 1, y = 2) --->
+{
+stack: main{Point<-1> :: Point(x = 1, y = 2)<0> :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp Point --->
+{
+stack: main{struct Point<-1> :: Point(x = 1, y = 2)<0> :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value struct Point with Point(x = 1, y = 2)<1>(struct Point,) --->
+{
+stack: main{(x = 1, y = 2)<-1> :: Point(x = 1, y = 2)<1>(struct Point,) :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp (x = 1, y = 2) --->
+{
+stack: main{1<-1> :: (x = 1, y = 2)<0> :: Point(x = 1, y = 2)<1>(struct Point,) :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x = 1, y = 2)<0> :: Point(x = 1, y = 2)<1>(struct Point,) :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (x = 1, y = 2)<1>(1,) --->
+{
+stack: main{2<-1> :: (x = 1, y = 2)<1>(1,) :: Point(x = 1, y = 2)<1>(struct Point,) :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (x = 1, y = 2)<1>(1,) :: Point(x = 1, y = 2)<1>(struct Point,) :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 2 with (x = 1, y = 2)<2>(1,2,) --->
+{
+stack: main{(x = 1@2, y = 2@3)<-1> :: Point(x = 1, y = 2)<1>(struct Point,) :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value (x = 1@2, y = 2@3) with Point(x = 1, y = 2)<2>(struct Point,(x = 1@2, y = 2@3),) --->
+{
+stack: main{Point(x = 1@4, y = 2@5)<-1> :: exp=>lval<-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value Point(x = 1@4, y = 2@5) with exp=>lval<0>(Point(x = 1@4, y = 2@5),) --->
+{
+stack: main{ptr<6><-1> :: Point(x = 1, y = 2).x<0> :: (Point(x = 1, y = 2).x - 1)<0> :: delete_tmp(6)<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value ptr<6> with Point(x = 1, y = 2).x<1>(ptr<6>,) --->
+{
+stack: main{1<-1> :: (Point(x = 1, y = 2).x - 1)<0> :: delete_tmp(6)<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (Point(x = 1, y = 2).x - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: (Point(x = 1, y = 2).x - 1)<1>(1,) :: delete_tmp(6)<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (Point(x = 1, y = 2).x - 1)<1>(1,) :: delete_tmp(6)<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 1 with (Point(x = 1, y = 2).x - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: delete_tmp(6)<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 0 with delete_tmp(6)<0>(0,) --->
+{
+stack: main{0<-1> :: return (Point(x = 1, y = 2).x - 1);<0>} :: top{}
+heap: struct Point, fun<main>, 1, 2, !!1, !!2, !!Point!!(x = !!1@4, y = !!2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+--- handle value 0 with return (Point(x = 1, y = 2).x - 1);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: struct Point, fun<main>, 1, 2, !!1, !!2, !!Point!!(x = !!1@4, y = !!2@5), 
+env: main: fun<main>, Point: struct Point, 
+}
+result: 0

+ 10 - 0
executable_semantics/testdata/tuple1.6c

@@ -0,0 +1,10 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var Int: x = (1);
+  var (Int,Int): t2 = (5, 2);
+  t2[0] = 3;
+  return t2[0] - t2[1] - x;
+}

+ 389 - 0
executable_semantics/testdata/tuple1.golden

@@ -0,0 +1,389 @@
+********** source program **********
+fn main () -> Int {
+var Int: x = 1;
+var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);
+t2[0] = 3;
+return ((t2[0] - t2[1]) - x);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp Int --->
+--- step exp (0 = Int, 1 = Int) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+--- step exp 0 --->
+--- step exp 0 --->
+--- step exp 1 --->
+
+********** type checking complete **********
+fn main () -> Int {
+var Int: x = 1;
+var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);
+t2[0] = 3;
+return ((t2[0] - t2[1]) - x);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var Int: x = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 1; ...  --->
+{
+stack: main{var Int: x = 1;<-1> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var Int: x = 1; --->
+{
+stack: main{1<-1> :: var Int: x = 1;<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: var Int: x = 1;<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 1 with var Int: x = 1;<1>(1,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 1;<1>(1,) :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int: x --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 1;<1>(1,) :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: Int: x<0> :: var Int: x = 1;<1>(1,) :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int with Int: x<1>(Int,) --->
+{
+stack: main{Int: x<-1> :: var Int: x = 1;<1>(1,) :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value Int: x with var Int: x = 1;<2>(1,Int: x,) --->
+pattern_match(Int: x, 1)
+{
+stack: main{var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); ...  --->
+{
+stack: main{var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<-1> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2); --->
+{
+stack: main{(0 = 5, 1 = 2)<-1> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<0> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (0 = 5, 1 = 2) --->
+{
+stack: main{5<-1> :: (0 = 5, 1 = 2)<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<0> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (0 = 5, 1 = 2)<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<0> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 5 with (0 = 5, 1 = 2)<1>(5,) --->
+{
+stack: main{2<-1> :: (0 = 5, 1 = 2)<1>(5,) :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<0> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (0 = 5, 1 = 2)<1>(5,) :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<0> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 2 with (0 = 5, 1 = 2)<2>(5,2,) --->
+{
+stack: main{(0 = 5@2, 1 = 2@3)<-1> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<0> :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value (0 = 5@2, 1 = 2@3) with var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) --->
+{
+stack: main{(0 = Int, 1 = Int): t2<-1> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (0 = Int, 1 = Int): t2 --->
+{
+stack: main{(0 = Int, 1 = Int)<-1> :: (0 = Int, 1 = Int): t2<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (0 = Int, 1 = Int) --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<0> :: (0 = Int, 1 = Int): t2<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<0> :: (0 = Int, 1 = Int): t2<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value Int with (0 = Int, 1 = Int)<1>(Int,) --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<1>(Int,) :: (0 = Int, 1 = Int): t2<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int, 1 = Int)<1>(Int,) :: (0 = Int, 1 = Int): t2<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value Int with (0 = Int, 1 = Int)<2>(Int,Int,) --->
+{
+stack: main{(0 = Int@4, 1 = Int@5)<-1> :: (0 = Int, 1 = Int): t2<0> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value (0 = Int@4, 1 = Int@5) with (0 = Int, 1 = Int): t2<1>((0 = Int@4, 1 = Int@5),) --->
+{
+stack: main{(0 = Int@4, 1 = Int@5): t2<-1> :: var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<1>((0 = 5@2, 1 = 2@3),) :: t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value (0 = Int@4, 1 = Int@5): t2 with var (0 = Int, 1 = Int): t2 = (0 = 5, 1 = 2);<2>((0 = 5@2, 1 = 2@3),(0 = Int@4, 1 = Int@5): t2,) --->
+pattern_match((0 = Int@4, 1 = Int@5): t2, (0 = 5@2, 1 = 2@3))
+{
+stack: main{t2[0] = 3; ... <-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step stmt t2[0] = 3; ...  --->
+{
+stack: main{t2[0] = 3;<-1> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step stmt t2[0] = 3; --->
+{
+stack: main{t2[0]<-1> :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step lvalue t2[0] --->
+{
+stack: main{t2<-1> :: t2[0]<0> :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp t2 --->
+{
+stack: main{(0 = 5@6, 1 = 2@7)<-1> :: t2[0]<0> :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value (0 = 5@6, 1 = 2@7) with t2[0]<1>((0 = 5@6, 1 = 2@7),) --->
+{
+stack: main{0<-1> :: t2[0]<1>((0 = 5@6, 1 = 2@7),) :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: t2[0]<1>((0 = 5@6, 1 = 2@7),) :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 0 with t2[0]<2>((0 = 5@6, 1 = 2@7),0,) --->
+{
+stack: main{ptr<6><-1> :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value ptr<6> with t2[0] = 3;<1>(ptr<6>,) --->
+{
+stack: main{3<-1> :: t2[0] = 3;<1>(ptr<6>,) :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp 3 --->
+{
+stack: main{3<-1> :: t2[0] = 3;<1>(ptr<6>,) :: return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 5, 2, (0 = 5@6, 1 = 2@7), 
+env: t2: (0 = 5@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 3 with t2[0] = 3;<2>(ptr<6>,3,) --->
+{
+stack: main{return ((t2[0] - t2[1]) - x);<-1>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step stmt return ((t2[0] - t2[1]) - x); --->
+{
+stack: main{((t2[0] - t2[1]) - x)<-1> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp ((t2[0] - t2[1]) - x) --->
+{
+stack: main{(t2[0] - t2[1])<-1> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp (t2[0] - t2[1]) --->
+{
+stack: main{t2[0]<-1> :: (t2[0] - t2[1])<0> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp t2[0] --->
+{
+stack: main{t2<-1> :: t2[0]<0> :: (t2[0] - t2[1])<0> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp t2 --->
+{
+stack: main{(0 = 3@6, 1 = 2@7)<-1> :: t2[0]<0> :: (t2[0] - t2[1])<0> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value (0 = 3@6, 1 = 2@7) with t2[0]<1>((0 = 3@6, 1 = 2@7),) --->
+{
+stack: main{0<-1> :: t2[0]<1>((0 = 3@6, 1 = 2@7),) :: (t2[0] - t2[1])<0> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: t2[0]<1>((0 = 3@6, 1 = 2@7),) :: (t2[0] - t2[1])<0> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 0 with t2[0]<2>((0 = 3@6, 1 = 2@7),0,) --->
+{
+stack: main{3<-1> :: (t2[0] - t2[1])<0> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 3 with (t2[0] - t2[1])<1>(3,) --->
+{
+stack: main{t2[1]<-1> :: (t2[0] - t2[1])<1>(3,) :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp t2[1] --->
+{
+stack: main{t2<-1> :: t2[1]<0> :: (t2[0] - t2[1])<1>(3,) :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp t2 --->
+{
+stack: main{(0 = 3@6, 1 = 2@7)<-1> :: t2[1]<0> :: (t2[0] - t2[1])<1>(3,) :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value (0 = 3@6, 1 = 2@7) with t2[1]<1>((0 = 3@6, 1 = 2@7),) --->
+{
+stack: main{1<-1> :: t2[1]<1>((0 = 3@6, 1 = 2@7),) :: (t2[0] - t2[1])<1>(3,) :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: t2[1]<1>((0 = 3@6, 1 = 2@7),) :: (t2[0] - t2[1])<1>(3,) :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 1 with t2[1]<2>((0 = 3@6, 1 = 2@7),1,) --->
+{
+stack: main{2<-1> :: (t2[0] - t2[1])<1>(3,) :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 2 with (t2[0] - t2[1])<2>(3,2,) --->
+{
+stack: main{1<-1> :: ((t2[0] - t2[1]) - x)<0> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 1 with ((t2[0] - t2[1]) - x)<1>(1,) --->
+{
+stack: main{x<-1> :: ((t2[0] - t2[1]) - x)<1>(1,) :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: ((t2[0] - t2[1]) - x)<1>(1,) :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 1 with ((t2[0] - t2[1]) - x)<2>(1,1,) --->
+{
+stack: main{0<-1> :: return ((t2[0] - t2[1]) - x);<0>} :: top{}
+heap: fun<main>, 1, 5, 2, Int, Int, 3, 2, (0 = 3@6, 1 = 2@7), 
+env: t2: (0 = 3@6, 1 = 2@7), x: 1, main: fun<main>, 
+}
+--- handle value 0 with return ((t2[0] - t2[1]) - x);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!1, 5, 2, Int, Int, !!3, !!2, !!(0 = !!3@6, 1 = !!2@7), 
+env: main: fun<main>, 
+}
+result: 0

+ 8 - 0
executable_semantics/testdata/tuple2.6c

@@ -0,0 +1,8 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var (Int,): t = (5,);
+  return t[0] - 5;
+}

+ 199 - 0
executable_semantics/testdata/tuple2.golden

@@ -0,0 +1,199 @@
+********** source program **********
+fn main () -> Int {
+var (0 = Int): t = (0 = 5);
+return (t[0] - 5);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp (0 = Int) --->
+--- step exp Int --->
+--- handle value Int with (0 = Int)<1>(Int,) --->
+--- step exp 0 --->
+
+********** type checking complete **********
+fn main () -> Int {
+var (0 = Int): t = (0 = 5);
+return (t[0] - 5);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var (0 = Int): t = (0 = 5); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var (0 = Int): t = (0 = 5); ...  --->
+{
+stack: main{var (0 = Int): t = (0 = 5);<-1> :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var (0 = Int): t = (0 = 5); --->
+{
+stack: main{(0 = 5)<-1> :: var (0 = Int): t = (0 = 5);<0> :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp (0 = 5) --->
+{
+stack: main{5<-1> :: (0 = 5)<0> :: var (0 = Int): t = (0 = 5);<0> :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (0 = 5)<0> :: var (0 = Int): t = (0 = 5);<0> :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 5 with (0 = 5)<1>(5,) --->
+{
+stack: main{(0 = 5@1)<-1> :: var (0 = Int): t = (0 = 5);<0> :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, 
+env: main: fun<main>, 
+}
+--- handle value (0 = 5@1) with var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) --->
+{
+stack: main{(0 = Int): t<-1> :: var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, 
+env: main: fun<main>, 
+}
+--- step exp (0 = Int): t --->
+{
+stack: main{(0 = Int)<-1> :: (0 = Int): t<0> :: var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, 
+env: main: fun<main>, 
+}
+--- step exp (0 = Int) --->
+{
+stack: main{Int<-1> :: (0 = Int)<0> :: (0 = Int): t<0> :: var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, 
+env: main: fun<main>, 
+}
+--- step exp Int --->
+{
+stack: main{Int<-1> :: (0 = Int)<0> :: (0 = Int): t<0> :: var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, 
+env: main: fun<main>, 
+}
+--- handle value Int with (0 = Int)<1>(Int,) --->
+{
+stack: main{(0 = Int@2)<-1> :: (0 = Int): t<0> :: var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, Int, 
+env: main: fun<main>, 
+}
+--- handle value (0 = Int@2) with (0 = Int): t<1>((0 = Int@2),) --->
+{
+stack: main{(0 = Int@2): t<-1> :: var (0 = Int): t = (0 = 5);<1>((0 = 5@1),) :: return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, Int, 
+env: main: fun<main>, 
+}
+--- handle value (0 = Int@2): t with var (0 = Int): t = (0 = 5);<2>((0 = 5@1),(0 = Int@2): t,) --->
+pattern_match((0 = Int@2): t, (0 = 5@1))
+{
+stack: main{return (t[0] - 5);<-1>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- step stmt return (t[0] - 5); --->
+{
+stack: main{(t[0] - 5)<-1> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- step exp (t[0] - 5) --->
+{
+stack: main{t[0]<-1> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- step exp t[0] --->
+{
+stack: main{t<-1> :: t[0]<0> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- step exp t --->
+{
+stack: main{(0 = 5@3)<-1> :: t[0]<0> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- handle value (0 = 5@3) with t[0]<1>((0 = 5@3),) --->
+{
+stack: main{0<-1> :: t[0]<1>((0 = 5@3),) :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: t[0]<1>((0 = 5@3),) :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- handle value 0 with t[0]<2>((0 = 5@3),0,) --->
+{
+stack: main{5<-1> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- handle value 5 with (t[0] - 5)<1>(5,) --->
+{
+stack: main{5<-1> :: (t[0] - 5)<1>(5,) :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (t[0] - 5)<1>(5,) :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- handle value 5 with (t[0] - 5)<2>(5,5,) --->
+{
+stack: main{0<-1> :: return (t[0] - 5);<0>} :: top{}
+heap: fun<main>, 5, Int, 5, (0 = 5@3), 
+env: t: (0 = 5@3), main: fun<main>, 
+}
+--- handle value 0 with return (t[0] - 5);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 5, Int, !!5, !!(0 = !!5@3), 
+env: main: fun<main>, 
+}
+result: 0

+ 10 - 0
executable_semantics/testdata/tuple_assign.6c

@@ -0,0 +1,10 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: x = 0;
+  var auto: y = 1;
+  (x, y) = (5, -5);
+  return x + y;
+}

+ 298 - 0
executable_semantics/testdata/tuple_assign.golden

@@ -0,0 +1,298 @@
+********** source program **********
+fn main () -> Int {
+var auto: x = 0;
+var auto: y = 1;
+(0 = x, 1 = y) = (0 = 5, 1 = (- 5));
+return (x + y);
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: x = 0;
+var auto: y = 1;
+(0 = x, 1 = y) = (0 = 5, 1 = (- 5));
+return (x + y);
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: x = 0; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: x = 0; ...  --->
+{
+stack: main{var auto: x = 0;<-1> :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: x = 0; --->
+{
+stack: main{0<-1> :: var auto: x = 0;<0> :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: var auto: x = 0;<0> :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 0 with var auto: x = 0;<1>(0,) --->
+{
+stack: main{auto: x<-1> :: var auto: x = 0;<1>(0,) :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto: x --->
+{
+stack: main{auto<-1> :: auto: x<0> :: var auto: x = 0;<1>(0,) :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: x<0> :: var auto: x = 0;<1>(0,) :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: x<1>(auto,) --->
+{
+stack: main{auto: x<-1> :: var auto: x = 0;<1>(0,) :: var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto: x with var auto: x = 0;<2>(0,auto: x,) --->
+pattern_match(auto: x, 0)
+{
+stack: main{var auto: y = 1; ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt var auto: y = 1; ...  --->
+{
+stack: main{var auto: y = 1;<-1> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt var auto: y = 1; --->
+{
+stack: main{1<-1> :: var auto: y = 1;<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: var auto: y = 1;<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 1 with var auto: y = 1;<1>(1,) --->
+{
+stack: main{auto: y<-1> :: var auto: y = 1;<1>(1,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp auto: y --->
+{
+stack: main{auto<-1> :: auto: y<0> :: var auto: y = 1;<1>(1,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: y<0> :: var auto: y = 1;<1>(1,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value auto with auto: y<1>(auto,) --->
+{
+stack: main{auto: y<-1> :: var auto: y = 1;<1>(1,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value auto: y with var auto: y = 1;<2>(1,auto: y,) --->
+pattern_match(auto: y, 1)
+{
+stack: main{(0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step stmt (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ...  --->
+{
+stack: main{(0 = x, 1 = y) = (0 = 5, 1 = (- 5));<-1> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step stmt (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); --->
+{
+stack: main{(0 = x, 1 = y)<-1> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<0> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step lvalue (0 = x, 1 = y) --->
+{
+stack: main{x<-1> :: (0 = x, 1 = y)<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<0> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: (0 = x, 1 = y)<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<0> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value ptr<1> with (0 = x, 1 = y)<1>(ptr<1>,) --->
+{
+stack: main{y<-1> :: (0 = x, 1 = y)<1>(ptr<1>,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<0> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step lvalue y --->
+{
+stack: main{ptr<2><-1> :: (0 = x, 1 = y)<1>(ptr<1>,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<0> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value ptr<2> with (0 = x, 1 = y)<2>(ptr<1>,ptr<2>,) --->
+{
+stack: main{(0 = ptr<1>@3, 1 = ptr<2>@4)<-1> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<0> :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value (0 = ptr<1>@3, 1 = ptr<2>@4) with (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) --->
+{
+stack: main{(0 = 5, 1 = (- 5))<-1> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step exp (0 = 5, 1 = (- 5)) --->
+{
+stack: main{5<-1> :: (0 = 5, 1 = (- 5))<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (0 = 5, 1 = (- 5))<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value 5 with (0 = 5, 1 = (- 5))<1>(5,) --->
+{
+stack: main{(- 5)<-1> :: (0 = 5, 1 = (- 5))<1>(5,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step exp (- 5) --->
+{
+stack: main{5<-1> :: (- 5)<0> :: (0 = 5, 1 = (- 5))<1>(5,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (- 5)<0> :: (0 = 5, 1 = (- 5))<1>(5,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value 5 with (- 5)<1>(5,) --->
+{
+stack: main{-5<-1> :: (0 = 5, 1 = (- 5))<1>(5,) :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value -5 with (0 = 5, 1 = (- 5))<2>(5,-5,) --->
+{
+stack: main{(0 = 5@5, 1 = -5@6)<-1> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<1>((0 = ptr<1>@3, 1 = ptr<2>@4),) :: return (x + y);<-1>} :: top{}
+heap: fun<main>, 0, 1, ptr<1>, ptr<2>, 5, -5, 
+env: y: 1, x: 0, main: fun<main>, 
+}
+--- handle value (0 = 5@5, 1 = -5@6) with (0 = x, 1 = y) = (0 = 5, 1 = (- 5));<2>((0 = ptr<1>@3, 1 = ptr<2>@4),(0 = 5@5, 1 = -5@6),) --->
+{
+stack: main{return (x + y);<-1>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- step stmt return (x + y); --->
+{
+stack: main{(x + y)<-1> :: return (x + y);<0>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- step exp (x + y) --->
+{
+stack: main{x<-1> :: (x + y)<0> :: return (x + y);<0>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{5<-1> :: (x + y)<0> :: return (x + y);<0>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- handle value 5 with (x + y)<1>(5,) --->
+{
+stack: main{y<-1> :: (x + y)<1>(5,) :: return (x + y);<0>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- step exp y --->
+{
+stack: main{-5<-1> :: (x + y)<1>(5,) :: return (x + y);<0>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- handle value -5 with (x + y)<2>(5,-5,) --->
+{
+stack: main{0<-1> :: return (x + y);<0>} :: top{}
+heap: fun<main>, 5, -5, ptr<1>, ptr<2>, 5, -5, 
+env: y: -5, x: 5, main: fun<main>, 
+}
+--- handle value 0 with return (x + y);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!5, !!-5, ptr<1>, ptr<2>, !!5, !!-5, 
+env: main: fun<main>, 
+}
+result: 0

+ 11 - 0
executable_semantics/testdata/tuple_match.6c

@@ -0,0 +1,11 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: t = (5, 2);
+  match (t) {
+    case (auto: a, auto: b) =>
+      return a + b - 7;
+  }
+}

+ 318 - 0
executable_semantics/testdata/tuple_match.golden

@@ -0,0 +1,318 @@
+********** source program **********
+fn main () -> Int {
+var auto: t = (0 = 5, 1 = 2);
+match (t) {
+case (0 = auto: a, 1 = auto: b) =>
+return ((a + b) - 7);
+}
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+--- step exp auto --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: t = (0 = 5, 1 = 2);
+match (t) {
+case (0 = auto: a, 1 = auto: b) =>
+return ((a + b) - 7);
+}
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: t = (0 = 5, 1 = 2); ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = (0 = 5, 1 = 2); ...  --->
+{
+stack: main{var auto: t = (0 = 5, 1 = 2);<-1> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: t = (0 = 5, 1 = 2); --->
+{
+stack: main{(0 = 5, 1 = 2)<-1> :: var auto: t = (0 = 5, 1 = 2);<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp (0 = 5, 1 = 2) --->
+{
+stack: main{5<-1> :: (0 = 5, 1 = 2)<0> :: var auto: t = (0 = 5, 1 = 2);<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 5 --->
+{
+stack: main{5<-1> :: (0 = 5, 1 = 2)<0> :: var auto: t = (0 = 5, 1 = 2);<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 5 with (0 = 5, 1 = 2)<1>(5,) --->
+{
+stack: main{2<-1> :: (0 = 5, 1 = 2)<1>(5,) :: var auto: t = (0 = 5, 1 = 2);<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: (0 = 5, 1 = 2)<1>(5,) :: var auto: t = (0 = 5, 1 = 2);<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 2 with (0 = 5, 1 = 2)<2>(5,2,) --->
+{
+stack: main{(0 = 5@1, 1 = 2@2)<-1> :: var auto: t = (0 = 5, 1 = 2);<0> :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- handle value (0 = 5@1, 1 = 2@2) with var auto: t = (0 = 5, 1 = 2);<1>((0 = 5@1, 1 = 2@2),) --->
+{
+stack: main{auto: t<-1> :: var auto: t = (0 = 5, 1 = 2);<1>((0 = 5@1, 1 = 2@2),) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- step exp auto: t --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = (0 = 5, 1 = 2);<1>((0 = 5@1, 1 = 2@2),) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: t<0> :: var auto: t = (0 = 5, 1 = 2);<1>((0 = 5@1, 1 = 2@2),) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: t<1>(auto,) --->
+{
+stack: main{auto: t<-1> :: var auto: t = (0 = 5, 1 = 2);<1>((0 = 5@1, 1 = 2@2),) :: match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 2, 
+env: main: fun<main>, 
+}
+--- handle value auto: t with var auto: t = (0 = 5, 1 = 2);<2>((0 = 5@1, 1 = 2@2),auto: t,) --->
+pattern_match(auto: t, (0 = 5@1, 1 = 2@2))
+{
+stack: main{match (t) {...}<-1>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step stmt match (t) {...} --->
+{
+stack: main{t<-1> :: match (t) {...}<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp t --->
+{
+stack: main{(0 = 5@3, 1 = 2@4)<-1> :: match (t) {...}<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value (0 = 5@3, 1 = 2@4) with match (t) {...}<1>((0 = 5@3, 1 = 2@4),) --->
+{
+stack: main{(0 = auto: a, 1 = auto: b)<-1> :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp (0 = auto: a, 1 = auto: b) --->
+{
+stack: main{auto: a<-1> :: (0 = auto: a, 1 = auto: b)<0> :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp auto: a --->
+{
+stack: main{auto<-1> :: auto: a<0> :: (0 = auto: a, 1 = auto: b)<0> :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: a<0> :: (0 = auto: a, 1 = auto: b)<0> :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value auto with auto: a<1>(auto,) --->
+{
+stack: main{auto: a<-1> :: (0 = auto: a, 1 = auto: b)<0> :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value auto: a with (0 = auto: a, 1 = auto: b)<1>(auto: a,) --->
+{
+stack: main{auto: b<-1> :: (0 = auto: a, 1 = auto: b)<1>(auto: a,) :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp auto: b --->
+{
+stack: main{auto<-1> :: auto: b<0> :: (0 = auto: a, 1 = auto: b)<1>(auto: a,) :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: b<0> :: (0 = auto: a, 1 = auto: b)<1>(auto: a,) :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value auto with auto: b<1>(auto,) --->
+{
+stack: main{auto: b<-1> :: (0 = auto: a, 1 = auto: b)<1>(auto: a,) :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value auto: b with (0 = auto: a, 1 = auto: b)<2>(auto: a,auto: b,) --->
+{
+stack: main{(0 = auto: a@6, 1 = auto: b@7)<-1> :: match (t) {...}<1>((0 = 5@3, 1 = 2@4),)} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 
+env: t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value (0 = auto: a@6, 1 = auto: b@7) with match (t) {...}<2>((0 = 5@3, 1 = 2@4),(0 = auto: a@6, 1 = auto: b@7),) --->
+pattern_match((0 = auto: a@6, 1 = auto: b@7), (0 = 5@3, 1 = 2@4))
+pattern_match(auto: a, 5)
+pattern_match(auto: b, 2)
+{
+stack: main{return ((a + b) - 7);<-1> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step stmt return ((a + b) - 7); --->
+{
+stack: main{((a + b) - 7)<-1> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp ((a + b) - 7) --->
+{
+stack: main{(a + b)<-1> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp (a + b) --->
+{
+stack: main{a<-1> :: (a + b)<0> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp a --->
+{
+stack: main{5<-1> :: (a + b)<0> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value 5 with (a + b)<1>(5,) --->
+{
+stack: main{b<-1> :: (a + b)<1>(5,) :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp b --->
+{
+stack: main{2<-1> :: (a + b)<1>(5,) :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value 2 with (a + b)<2>(5,2,) --->
+{
+stack: main{7<-1> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value 7 with ((a + b) - 7)<1>(7,) --->
+{
+stack: main{7<-1> :: ((a + b) - 7)<1>(7,) :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- step exp 7 --->
+{
+stack: main{7<-1> :: ((a + b) - 7)<1>(7,) :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value 7 with ((a + b) - 7)<2>(7,7,) --->
+{
+stack: main{0<-1> :: return ((a + b) - 7);<0> :: {
+ ... 
+}
+<0>} :: top{}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, 5, 2, 
+env: b: 2, a: 5, t: (0 = 5@3, 1 = 2@4), main: fun<main>, 
+}
+--- handle value 0 with return ((a + b) - 7);<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, !!5, !!2, 
+env: main: fun<main>, 
+}
+result: 0

+ 18 - 0
executable_semantics/testdata/undef1.6c

@@ -0,0 +1,18 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// The behavior of this program is undefined because it tries to
+// access a local variable after its lifetime is over.
+
+fn f() -> Int* {
+  var int: x;
+  x = 0;
+  return &x;
+}
+
+fn main() -> int {
+  var Ptr(int): p;
+  p = f();
+  return *p;
+}

+ 1 - 0
executable_semantics/testdata/undef1.golden

@@ -0,0 +1 @@
+executable_semantics/testdata/undef1.6c:8: syntax error

+ 13 - 0
executable_semantics/testdata/undef2.6c

@@ -0,0 +1,13 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+// Use-after-free.
+
+fun main() -> Int {
+  var Ptr(int): p;
+  p = malloc(Int);
+  *p = 0;
+  free(p);
+  return *p;
+}

+ 3 - 0
executable_semantics/testdata/undef2.golden

@@ -0,0 +1,3 @@
+********** source program **********
+********** type checking **********
+error, program must contain a function named `main`

+ 10 - 0
executable_semantics/testdata/while1.6c

@@ -0,0 +1,10 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  var auto: x = 2;
+  while (not (x == 0))
+    x = x - 1;
+  return x;
+}

+ 464 - 0
executable_semantics/testdata/while1.golden

@@ -0,0 +1,464 @@
+********** source program **********
+fn main () -> Int {
+var auto: x = 2;
+while ((! (x == 0)))
+x = (x - 1);
+return x;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+--- step exp auto --->
+
+********** type checking complete **********
+fn main () -> Int {
+var auto: x = 2;
+while ((! (x == 0)))
+x = (x - 1);
+return x;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{var auto: x = 2; ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: x = 2; ...  --->
+{
+stack: main{var auto: x = 2;<-1> :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt var auto: x = 2; --->
+{
+stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 2 --->
+{
+stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 2 with var auto: x = 2;<1>(2,) --->
+{
+stack: main{auto: x<-1> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto: x --->
+{
+stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp auto --->
+{
+stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto with auto: x<1>(auto,) --->
+{
+stack: main{auto: x<-1> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value auto: x with var auto: x = 2;<2>(2,auto: x,) --->
+pattern_match(auto: x, 2)
+{
+stack: main{while ((! (x == 0)))
+ ...  ... <-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  ...  --->
+{
+stack: main{while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  --->
+{
+stack: main{(! (x == 0))<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (! (x == 0)) --->
+{
+stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 2 with (x == 0)<1>(2,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(2,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(2,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(2,0,) --->
+{
+stack: main{false<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value false with (! (x == 0))<1>(false,) --->
+{
+stack: main{true<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value true with while ((! (x == 0)))
+ ... <1>(true,) --->
+{
+stack: main{x = (x - 1);<-1> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: x = (x - 1);<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value ptr<1> with x = (x - 1);<1>(ptr<1>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{2<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 2 with (x - 1)<1>(2,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(2,) :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(2,) :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(2,1,) --->
+{
+stack: main{1<-1> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 2, 
+env: x: 2, main: fun<main>, 
+}
+--- handle value 1 with x = (x - 1);<2>(ptr<1>,1,) --->
+{
+stack: main{while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  --->
+{
+stack: main{(! (x == 0))<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (! (x == 0)) --->
+{
+stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x == 0)<1>(1,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(1,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(1,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(1,0,) --->
+{
+stack: main{false<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value false with (! (x == 0))<1>(false,) --->
+{
+stack: main{true<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value true with while ((! (x == 0)))
+ ... <1>(true,) --->
+{
+stack: main{x = (x - 1);<-1> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step stmt x = (x - 1); --->
+{
+stack: main{x<-1> :: x = (x - 1);<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step lvalue x --->
+{
+stack: main{ptr<1><-1> :: x = (x - 1);<0> :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value ptr<1> with x = (x - 1);<1>(ptr<1>,) --->
+{
+stack: main{(x - 1)<-1> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp (x - 1) --->
+{
+stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{1<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<1>(1,) --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- step exp 1 --->
+{
+stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 1 with (x - 1)<2>(1,1,) --->
+{
+stack: main{0<-1> :: x = (x - 1);<1>(ptr<1>,) :: while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 1, 
+env: x: 1, main: fun<main>, 
+}
+--- handle value 0 with x = (x - 1);<2>(ptr<1>,0,) --->
+{
+stack: main{while ((! (x == 0)))
+ ... <-1> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt while ((! (x == 0)))
+ ...  --->
+{
+stack: main{(! (x == 0))<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp (! (x == 0)) --->
+{
+stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp (x == 0) --->
+{
+stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<1>(0,) --->
+{
+stack: main{0<-1> :: (x == 0)<1>(0,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: (x == 0)<1>(0,) :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with (x == 0)<2>(0,0,) --->
+{
+stack: main{true<-1> :: (! (x == 0))<0> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value true with (! (x == 0))<1>(true,) --->
+{
+stack: main{false<-1> :: while ((! (x == 0)))
+ ... <0> :: return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value false with while ((! (x == 0)))
+ ... <1>(false,) --->
+{
+stack: main{return x;<-1>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step stmt return x; --->
+{
+stack: main{x<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- step exp x --->
+{
+stack: main{0<-1> :: return x;<0>} :: top{}
+heap: fun<main>, 0, 
+env: x: 0, main: fun<main>, 
+}
+--- handle value 0 with return x;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, !!0, 
+env: main: fun<main>, 
+}
+result: 0

+ 7 - 0
executable_semantics/testdata/zero.6c

@@ -0,0 +1,7 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+fn main() -> Int {
+  return 0;
+}

+ 72 - 0
executable_semantics/testdata/zero.golden

@@ -0,0 +1,72 @@
+********** source program **********
+fn main () -> Int {
+return 0;
+
+}
+********** type checking **********
+--- step exp Int --->
+--- step exp Int --->
+
+********** type checking complete **********
+fn main () -> Int {
+return 0;
+}
+********** starting execution **********
+********** initializing globals **********
+--- step exp () --->
+********** calling main function **********
+{
+stack: top{main()<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main() --->
+{
+stack: top{main<-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp main --->
+{
+stack: top{fun<main><-1> :: main()<0>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value fun<main> with main()<1>(fun<main>,) --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp () --->
+{
+stack: top{()<-1> :: main()<1>(fun<main>,)}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value () with main()<2>(fun<main>,(),) --->
+pattern_match((), ())
+{
+stack: main{return 0;<-1>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step stmt return 0; --->
+{
+stack: main{0<-1> :: return 0;<0>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- step exp 0 --->
+{
+stack: main{0<-1> :: return 0;<0>} :: top{}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+--- handle value 0 with return 0;<1>(0,) --->
+{
+stack: top{0<-1>}
+heap: fun<main>, 
+env: main: fun<main>, 
+}
+result: 0