diff --git a/.bazeliskrc b/.bazeliskrc new file mode 100644 index 000000000000..2eedb14067fe --- /dev/null +++ b/.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 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eaa678bfe647..b30f683fdbc7 100644 --- a/.pre-commit-config.yaml +++ b/.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 diff --git a/bazel/cc_toolchains/clang_cc_toolchain_config.bzl b/bazel/cc_toolchains/clang_cc_toolchain_config.bzl index 2e0e0c0de031..aac165c99161 100644 --- a/bazel/cc_toolchains/clang_cc_toolchain_config.bzl +++ b/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", ], ), ]), diff --git a/bazel/testing/BUILD b/bazel/testing/BUILD new file mode 100644 index 000000000000..8261f52b45ad --- /dev/null +++ b/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"]) diff --git a/bazel/testing/golden_test.bzl b/bazel/testing/golden_test.bzl new file mode 100644 index 000000000000..84577f0e29e2 --- /dev/null +++ b/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 + ) diff --git a/bazel/testing/golden_test.sh b/bazel/testing/golden_test.sh new file mode 100755 index 000000000000..e13591f9dace --- /dev/null +++ b/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 < + +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. diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD new file mode 100644 index 000000000000..b981a553a3c1 --- /dev/null +++ b/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"], +) diff --git a/executable_semantics/ast/declaration.cpp b/executable_semantics/ast/declaration.cpp new file mode 100644 index 000000000000..65b8f43c9c09 --- /dev/null +++ b/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 + +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* 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>* 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 diff --git a/executable_semantics/ast/declaration.h b/executable_semantics/ast/declaration.h new file mode 100644 index 000000000000..0953c8f9ab59 --- /dev/null +++ b/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 +#include + +#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>* alternatives; + } choice_def; + } u; +}; + +auto MakeFunDecl(struct FunctionDefinition* f) -> Declaration*; +auto MakeStructDecl(int line_num, std::string name, std::list* members) + -> Declaration*; +auto MakeChoiceDecl(int line_num, std::string name, + std::list>* alts) + -> Declaration*; + +void PrintDecl(Declaration* d); + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_AST_DECLARATION_H_ diff --git a/executable_semantics/ast/expression.cpp b/executable_semantics/ast/expression.cpp new file mode 100644 index 000000000000..8d71eb285b22 --- /dev/null +++ b/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 + +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* 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(); + 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(); + 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>* 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>* 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 diff --git a/executable_semantics/ast/expression.h b/executable_semantics/ast/expression.h new file mode 100644 index 000000000000..e7e0afe05812 --- /dev/null +++ b/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 +#include + +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>* fields; + } tuple; + struct { + Operator op; + std::vector* 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* 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>* 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_ diff --git a/executable_semantics/ast/expression_or_field_list.cpp b/executable_semantics/ast/expression_or_field_list.cpp new file mode 100644 index 000000000000..d3f0f8205b7b --- /dev/null +++ b/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>* 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>(); + 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 diff --git a/executable_semantics/ast/expression_or_field_list.h b/executable_semantics/ast/expression_or_field_list.h new file mode 100644 index 000000000000..b5054c7461ab --- /dev/null +++ b/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 + +#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>* fields; + } u; +}; + +auto MakeExp(Expression* exp) -> ExpOrFieldList*; +auto MakeFieldList(std::list>* fields) + -> ExpOrFieldList*; +auto MakeConsField(ExpOrFieldList* e1, ExpOrFieldList* e2) -> ExpOrFieldList*; + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_AST_EXPRESSION_OR_FIELD_LIST_H_ diff --git a/executable_semantics/ast/function_definition.cpp b/executable_semantics/ast/function_definition.cpp new file mode 100644 index 000000000000..d2d45116486b --- /dev/null +++ b/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 + +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 diff --git a/executable_semantics/ast/function_definition.h b/executable_semantics/ast/function_definition.h new file mode 100644 index 000000000000..68b65e6c8b1b --- /dev/null +++ b/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_ diff --git a/executable_semantics/ast/member.cpp b/executable_semantics/ast/member.cpp new file mode 100644 index 000000000000..7770bc07904b --- /dev/null +++ b/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 + +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 diff --git a/executable_semantics/ast/member.h b/executable_semantics/ast/member.h new file mode 100644 index 000000000000..7db721d7af31 --- /dev/null +++ b/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 + +#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_ diff --git a/executable_semantics/ast/statement.cpp b/executable_semantics/ast/statement.cpp new file mode 100644 index 000000000000..b282eebb37ba --- /dev/null +++ b/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 + +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>* 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 diff --git a/executable_semantics/ast/statement.h b/executable_semantics/ast/statement.h new file mode 100644 index 000000000000..5a6137748d8c --- /dev/null +++ b/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 + +#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>* 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>* clauses) + -> Statement*; + +void PrintStatement(Statement*, int); + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_AST_STATEMENT_H_ diff --git a/executable_semantics/ast/struct_definition.h b/executable_semantics/ast/struct_definition.h new file mode 100644 index 000000000000..d2c9105d3055 --- /dev/null +++ b/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 +#include + +#include "executable_semantics/ast/member.h" + +namespace Carbon { + +struct StructDefinition { + int line_num; + std::string* name; + std::list* members; +}; + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_AST_STRUCT_DEFINITION_H_ diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD new file mode 100644 index 000000000000..04c883a91c12 --- /dev/null +++ b/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", + ], +) diff --git a/executable_semantics/interpreter/action.cpp b/executable_semantics/interpreter/action.cpp new file mode 100644 index 000000000000..3c7b06a95ed6 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#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* 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 diff --git a/executable_semantics/interpreter/action.h b/executable_semantics/interpreter/action.h new file mode 100644 index 000000000000..478c31e9db8e --- /dev/null +++ b/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 +#include + +#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 results; // results from subexpression +}; + +void PrintAct(Action* act, std::ostream& out); +void PrintActList(Cons* 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_ diff --git a/executable_semantics/interpreter/assoc_list.h b/executable_semantics/interpreter/assoc_list.h new file mode 100644 index 000000000000..c5f9f0014468 --- /dev/null +++ b/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 +#include +#include + +namespace Carbon { + +template +struct AssocList { + AssocList(K k, V v, AssocList* n) : key(k), value(v), next(n) {} + + K key; + V value; + AssocList* next; +}; + +template +auto Lookup(int line_num, AssocList* 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_ diff --git a/executable_semantics/interpreter/cons_list.h b/executable_semantics/interpreter/cons_list.h new file mode 100644 index 000000000000..bc3512a1ed0d --- /dev/null +++ b/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 +struct Cons { + Cons(T e, Cons* n) : curr(e), next(n) {} + + T curr; + Cons* next; +}; + +template +auto MakeCons(const T& x) -> Cons* { + return new Cons(x, nullptr); +} + +template +auto MakeCons(const T& x, Cons* ls) -> Cons* { + return new Cons(x, ls); +} + +template +auto Length(Cons* ls) -> unsigned int { + if (ls) { + return 1 + Length(ls->next); + } else { + return 0; + } +} + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_INTERPRETER_CONS_LIST_H_ diff --git a/executable_semantics/interpreter/interpreter.cpp b/executable_semantics/interpreter/interpreter.cpp new file mode 100644 index 000000000000..90ebd666086e --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#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*, int) + -> Env*; +void HandleValue(); + +template +static auto FindField(const std::string& field, + const std::vector>& inits) + -> std::optional { + 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>(); + 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* ls, std::ostream& out) { + if (ls) { + PrintFrame(ls->curr, out); + if (ls->next) { + out << " :: "; + PrintStack(ls->next, out); + } + } +} + +void PrintHeap(const std::vector& 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& 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* 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 operas, State* state) { + CheckAlive(operas[0], line_num); + switch (operas[0]->tag) { + case ValKind::FunV: { + // Bind arguments to parameters + std::list params; + Env* env = PatternMatch(operas[0]->u.fun.param, operas[1], globals, + ¶ms, 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* 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>(); + 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* 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()); + 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* 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* todo) -> Cons* { + 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(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(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(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(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 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(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* fs) -> int { + state = new State(); // Runtime state. + std::cout << "********** initializing globals **********" << std::endl; + InitGlobals(fs); + + Expression* arg = + MakeTuple(0, new std::vector>()); + Expression* call_main = MakeCall(0, MakeVar(0, "main"), arg); + Cons* todo = MakeCons(MakeExpAct(call_main)); + auto* scope = new Scope(globals, std::list()); + 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* todo = MakeCons(MakeExpAct(e)); + auto* scope = new Scope(env, std::list()); + 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 diff --git a/executable_semantics/interpreter/interpreter.h b/executable_semantics/interpreter/interpreter.h new file mode 100644 index 000000000000..cb291dddd5a2 --- /dev/null +++ b/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 +#include +#include + +#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; + +/***** Scopes *****/ + +struct Scope { + Scope(Env* e, std::list l) : env(e), locals(std::move(l)) {} + Env* env; + std::list locals; +}; + +/***** Frames and State *****/ + +struct Frame { + std::string name; + Cons* scopes; + Cons* todo; + + Frame(std::string n, Cons* s, Cons* c) + : name(std::move(std::move(n))), scopes(s), todo(c) {} +}; + +struct State { + Cons* stack; + std::vector 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* fs) -> int; +auto InterpExp(Env* env, Expression* e) -> Value*; + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_INTERPRETER_INTERPRETER_H_ diff --git a/executable_semantics/interpreter/typecheck.cpp b/executable_semantics/interpreter/typecheck.cpp new file mode 100644 index 000000000000..c452eabebb57 --- /dev/null +++ b/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 +#include +#include +#include + +#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* 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>(); + 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>(); + 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(); + std::vector 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 { + 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>(); + 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>(); + 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>(); + 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>(); + 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(); + 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* fs) -> std::pair { + 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 diff --git a/executable_semantics/interpreter/typecheck.h b/executable_semantics/interpreter/typecheck.h new file mode 100644 index 000000000000..b74cc7612256 --- /dev/null +++ b/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 + +#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; + +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* fs) -> std::pair; + +void PrintErrorString(const std::string& s); + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_INTERPRETER_TYPECHECK_H_ diff --git a/executable_semantics/interpreter/value.cpp b/executable_semantics/interpreter/value.cpp new file mode 100644 index 000000000000..215b3400707d --- /dev/null +++ b/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 + +#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>* 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>* 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 diff --git a/executable_semantics/interpreter/value.h b/executable_semantics/interpreter/value.h new file mode 100644 index 000000000000..8873db7190c7 --- /dev/null +++ b/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 +#include + +#include "executable_semantics/ast/statement.h" + +namespace Carbon { + +struct Value; +using Address = unsigned int; +using VarValues = std::list>; + +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>* 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* 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>* 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_ diff --git a/executable_semantics/main.cpp b/executable_semantics/main.cpp new file mode 100644 index 000000000000..4ec90519971b --- /dev/null +++ b/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 +#include +#include + +#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(); +} diff --git a/executable_semantics/syntax.lpp b/executable_semantics/syntax.lpp new file mode 100644 index 000000000000..2384cb644ecc --- /dev/null +++ b/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 +#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(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; } diff --git a/executable_semantics/syntax.ypp b/executable_semantics/syntax.ypp new file mode 100644 index 000000000000..9887b2a77302 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +#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>* field_types; + Carbon::Statement* statement; + Carbon::Statement* statement_list; + Carbon::FunctionDefinition* function_definition; + Carbon::Declaration* declaration; + std::list* declaration_list; + Carbon::Member* member; + std::list* member_list; + Carbon::ExpOrFieldList* field_list; + std::pair* alternative; + std::list>* alternative_list; + std::pair* clause; + std::list>* clause_list; + Carbon::Expression* fun_type; +}; + +%token integer_literal +%token identifier +%type designator +%type declaration +%type function_declaration +%type function_definition +%type declaration_list +%type statement +%type statement_list +%type expression +%type pattern +%type return_type +%type tuple +%type member +%type member_list +%type field +%type field_list +%type alternative +%type alternative_list +%type clause +%type 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>(); + 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>( + $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>(); + fields->push_back(std::make_pair($1, $3)); + $$ = Carbon::MakeFieldList(fields); + } +; +field_list: + // Empty + { + $$ = Carbon::MakeFieldList( + new std::list>()); + } +| field + { $$ = $1; } +| field ',' field_list + { $$ = Carbon::MakeConsField($1, $3); } +; +clause: + CASE pattern DBLARROW statement + { $$ = new std::pair($2, $4); } +| DEFAULT DBLARROW statement + { + auto vp = Carbon::MakeVarPat(yylineno, "_", + Carbon::MakeAutoType(yylineno)); + $$ = new std::pair(vp, $3); + } +; +clause_list: + // Empty + { + $$ = new std::list>(); + } +| 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>()); + } +| 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(); } +| member member_list + { $$ = $2; $$->push_front($1); } +; +alternative: + identifier tuple ';' + { $$ = new std::pair($1, $2); } +; +alternative_list: + // Empty + { $$ = new std::list>(); } +| 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(); } +| declaration declaration_list + { + $$ = $2; + $$->push_front($1); + } +; +%% diff --git a/executable_semantics/syntax_helpers.cpp b/executable_semantics/syntax_helpers.cpp new file mode 100644 index 000000000000..dfef32344293 --- /dev/null +++ b/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 + +#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* 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 p = TopLevel(fs); + TypeEnv* top = p.first; + Env* ct_top = p.second; + std::list 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 diff --git a/executable_semantics/syntax_helpers.h b/executable_semantics/syntax_helpers.h new file mode 100644 index 000000000000..734c1b2c1d63 --- /dev/null +++ b/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 + +#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* fs); + +} // namespace Carbon + +#endif // EXECUTABLE_SEMANTICS_EXEC_H_ diff --git a/executable_semantics/testdata/block1.6c b/executable_semantics/testdata/block1.6c new file mode 100644 index 000000000000..7c6005123971 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/block1.golden b/executable_semantics/testdata/block1.golden new file mode 100644 index 000000000000..729da55d2915 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var Int: x = 0; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var Int: x = 0; ... ---> +{ +stack: main{var Int: x = 0;<-1> :: { + ... +} + ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var Int: x = 0; ---> +{ +stack: main{0<-1> :: var Int: x = 0;<0> :: { + ... +} + ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: var Int: x = 0;<0> :: { + ... +} + ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp Int: x ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: { + ... +} + ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp Int ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: { + ... +} + ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- handle value Int with Int: x<1>(Int,) ---> +{ +stack: main{Int: x<-1> :: var Int: x = 0;<1>(0,) :: { + ... +} + ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- handle value Int: x with var Int: x = 0;<2>(0,Int: x,) ---> +pattern_match(Int: x, 0) +{ +stack: main{{ + ... +} + ... <-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt { + ... +} + ... ---> +{ +stack: main{{ + ... +} +<-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{var Int: x = 1;<-1> :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt var Int: x = 1; ---> +{ +stack: main{var Int: x = 1;<-1> :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt var Int: x = 1; ---> +{ +stack: main{1<-1> :: var Int: x = 1;<0> :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: var Int: x = 1;<0> :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- step exp Int: x ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 1;<1>(1,) :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp Int ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 1;<1>(1,) :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, 1, +env: x: 1, x: 0, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{return x;<-1>} :: top{} +heap: fun
, 0, !!1, +env: x: 0, main: fun
, +} +--- step stmt return x; ---> +{ +stack: main{x<-1> :: return x;<0>} :: top{} +heap: fun
, 0, !!1, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: return x;<0>} :: top{} +heap: fun
, 0, !!1, +env: x: 0, main: fun
, +} +--- handle value 0 with return x;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!0, !!1, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/break1.6c b/executable_semantics/testdata/break1.6c new file mode 100644 index 000000000000..126336e210a8 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/break1.golden b/executable_semantics/testdata/break1.golden new file mode 100644 index 000000000000..f6cb9e290eaf --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var Int: x = 2; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var Int: x = 2; ... ---> +{ +stack: main{var Int: x = 2;<-1> :: while (true) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var Int: x = 2; ---> +{ +stack: main{2<-1> :: var Int: x = 2;<0> :: while (true) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 2 ---> +{ +stack: main{2<-1> :: var Int: x = 2;<0> :: while (true) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp Int: x ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 2;<1>(2,) :: while (true) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp Int ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 2;<1>(2,) :: while (true) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step stmt while (true) + ... ... ---> +{ +stack: main{while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt while (true) + ... ---> +{ +stack: main{true<-1> :: while (true) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp true ---> +{ +stack: main{true<-1> :: while (true) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- handle value true with while (true) + ... <1>(true,) ---> +{ +stack: main{{ + ... +} +<-1> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{if ((x == 0)) + ... +else + ... <-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt if ((x == 0)) + ... +else + ... ---> +{ +stack: main{if ((x == 0)) + ... +else + ... <-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step stmt x = (x - 1); ---> +{ +stack: main{x<-1> :: x = (x - 1);<0> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step lvalue x ---> +{ +stack: main{ptr<1><-1> :: x = (x - 1);<0> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- handle value 1 with x = (x - 1);<2>(ptr<1>,1,) ---> +{ +stack: main{{ + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt while (true) + ... ---> +{ +stack: main{true<-1> :: while (true) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp true ---> +{ +stack: main{true<-1> :: while (true) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- handle value true with while (true) + ... <1>(true,) ---> +{ +stack: main{{ + ... +} +<-1> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{if ((x == 0)) + ... +else + ... <-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt if ((x == 0)) + ... +else + ... ---> +{ +stack: main{if ((x == 0)) + ... +else + ... <-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- step stmt x = (x - 1); ---> +{ +stack: main{x<-1> :: x = (x - 1);<0> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step lvalue x ---> +{ +stack: main{ptr<1><-1> :: x = (x - 1);<0> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- handle value 0 with x = (x - 1);<2>(ptr<1>,0,) ---> +{ +stack: main{{ + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt while (true) + ... ---> +{ +stack: main{true<-1> :: while (true) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp true ---> +{ +stack: main{true<-1> :: while (true) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value true with while (true) + ... <1>(true,) ---> +{ +stack: main{{ + ... +} +<-1> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{if ((x == 0)) + ... +else + ... <-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt if ((x == 0)) + ... +else + ... ---> +{ +stack: main{if ((x == 0)) + ... +else + ... <-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- handle value true with if ((x == 0)) + ... +else + ... <1>(true,) ---> +{ +stack: main{break;<-1> :: { + ... +} +<0> :: while (true) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt break; ---> +{ +stack: main{return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt return x; ---> +{ +stack: main{x<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value 0 with return x;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!0, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/choice1.6c b/executable_semantics/testdata/choice1.6c new file mode 100644 index 000000000000..b031f59e639b --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/choice1.golden b/executable_semantics/testdata/choice1.golden new file mode 100644 index 000000000000..052a6d3ade66 --- /dev/null +++ b/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) diff --git a/executable_semantics/testdata/continue1.6c b/executable_semantics/testdata/continue1.6c new file mode 100644 index 000000000000..7eefc430a27b --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/continue1.golden b/executable_semantics/testdata/continue1.golden new file mode 100644 index 000000000000..d63b002d8630 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: x = 2; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: x = 2; ... ---> +{ +stack: main{var auto: x = 2;<-1> :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: x = 2; ---> +{ +stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 2 ---> +{ +stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp auto: x ---> +{ +stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp auto ---> +{ +stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ... ---> +{ +stack: main{while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ---> +{ +stack: main{(! (x == 0))<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp (! (x == 0)) ---> +{ +stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp (x == 0) ---> +{ +stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp x ---> +{ +stack: main{2<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: (x == 0)<1>(2,) :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- handle value false with (! (x == 0))<1>(false,) ---> +{ +stack: main{true<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- handle value true with while ((! (x == 0))) + ... <1>(true,) ---> +{ +stack: main{{ + ... +} +<-1> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{x = (x - 1); ... <-1> :: { + ... +} +<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt x = (x - 1); ... ---> +{ +stack: main{x = (x - 1);<-1> :: continue; ... <-1> :: { + ... +} +<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- step stmt continue; ... ---> +{ +stack: main{continue;<-1> :: x = (x + 1);<-1> :: { + ... +} +<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt continue; ---> +{ +stack: main{while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ---> +{ +stack: main{(! (x == 0))<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp (! (x == 0)) ---> +{ +stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp (x == 0) ---> +{ +stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp x ---> +{ +stack: main{1<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: (x == 0)<1>(1,) :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- handle value false with (! (x == 0))<1>(false,) ---> +{ +stack: main{true<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- handle value true with while ((! (x == 0))) + ... <1>(true,) ---> +{ +stack: main{{ + ... +} +<-1> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{x = (x - 1); ... <-1> :: { + ... +} +<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt x = (x - 1); ... ---> +{ +stack: main{x = (x - 1);<-1> :: continue; ... <-1> :: { + ... +} +<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- step stmt continue; ... ---> +{ +stack: main{continue;<-1> :: x = (x + 1);<-1> :: { + ... +} +<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt continue; ---> +{ +stack: main{while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ---> +{ +stack: main{(! (x == 0))<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp (! (x == 0)) ---> +{ +stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp (x == 0) ---> +{ +stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: (x == 0)<1>(0,) :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- handle value true with (! (x == 0))<1>(true,) ---> +{ +stack: main{false<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value false with while ((! (x == 0))) + ... <1>(false,) ---> +{ +stack: main{return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt return x; ---> +{ +stack: main{x<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value 0 with return x;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!0, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/fun1.6c b/executable_semantics/testdata/fun1.6c new file mode 100644 index 000000000000..f7ccc5ba83cd --- /dev/null +++ b/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); +} diff --git a/executable_semantics/testdata/fun1.golden b/executable_semantics/testdata/fun1.golden new file mode 100644 index 000000000000..387c3d0f1fc6 --- /dev/null +++ b/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) diff --git a/executable_semantics/testdata/fun2.6c b/executable_semantics/testdata/fun2.6c new file mode 100644 index 000000000000..8ea4f49fe4a0 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/fun2.golden b/executable_semantics/testdata/fun2.golden new file mode 100644 index 000000000000..8eec81ee819f --- /dev/null +++ b/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) diff --git a/executable_semantics/testdata/fun3.6c b/executable_semantics/testdata/fun3.6c new file mode 100644 index 000000000000..8cb0d9b5a34e --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/fun3.golden b/executable_semantics/testdata/fun3.golden new file mode 100644 index 000000000000..579c024f6b34 --- /dev/null +++ b/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, fun
, +env: main: fun
, f: fun, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{return (f(0 = 2, 1 = 3) - 5);<-1>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- 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, fun
, +env: main: fun
, f: fun, +} +--- 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, fun
, +env: main: fun
, f: fun, +} +--- 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, fun
, +env: main: fun
, f: fun, +} +--- step exp f ---> +{ +stack: main{fun<-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, fun
, +env: main: fun
, f: fun, +} +--- handle value fun with f(0 = 2, 1 = 3)<1>(fun,) ---> +{ +stack: main{(0 = 2, 1 = 3)<-1> :: f(0 = 2, 1 = 3)<1>(fun,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- step exp (0 = 2, 1 = 3) ---> +{ +stack: main{2<-1> :: (0 = 2, 1 = 3)<0> :: f(0 = 2, 1 = 3)<1>(fun,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- step exp 2 ---> +{ +stack: main{2<-1> :: (0 = 2, 1 = 3)<0> :: f(0 = 2, 1 = 3)<1>(fun,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- 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(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- step exp 3 ---> +{ +stack: main{3<-1> :: (0 = 2, 1 = 3)<1>(2,) :: f(0 = 2, 1 = 3)<1>(fun,) :: (f(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, f: fun, +} +--- 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(0 = 2, 1 = 3) - 5)<0> :: return (f(0 = 2, 1 = 3) - 5);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, 2, 3, +env: main: fun
, f: fun, +} +--- handle value (0 = 2@4, 1 = 3@5) with f(0 = 2, 1 = 3)<2>(fun,(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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, 2, 3, +env: y: 3, x: 2, main: fun
, f: fun, +} +--- 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, fun
, 2, 3, !!2, !!3, +env: main: fun
, f: fun, +} +--- 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, fun
, 2, 3, !!2, !!3, +env: main: fun
, f: fun, +} +--- 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, fun
, 2, 3, !!2, !!3, +env: main: fun
, f: fun, +} +--- 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, fun
, 2, 3, !!2, !!3, +env: main: fun
, f: fun, +} +--- handle value 0 with return (f(0 = 2, 1 = 3) - 5);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: Int: x, Int: y, fun, fun
, 2, 3, !!2, !!3, +env: main: fun
, f: fun, +} +result: 0 diff --git a/executable_semantics/testdata/fun4.6c b/executable_semantics/testdata/fun4.6c new file mode 100644 index 000000000000..fffd1288b359 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/fun4.golden b/executable_semantics/testdata/fun4.golden new file mode 100644 index 000000000000..78b0823dc6be --- /dev/null +++ b/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, fun
, +env: main: fun
, f: fun, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{f(); ... <-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step stmt f(); ... ---> +{ +stack: main{f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step stmt f(); ---> +{ +stack: main{f()<-1> :: f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp f() ---> +{ +stack: main{f<-1> :: f()<0> :: f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp f ---> +{ +stack: main{fun<-1> :: f()<0> :: f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value fun with f()<1>(fun,) ---> +{ +stack: main{()<-1> :: f()<1>(fun,) :: f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp () ---> +{ +stack: main{()<-1> :: f()<1>(fun,) :: f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value () with f()<2>(fun,(),) ---> +pattern_match((), ()) +{ +stack: f{return ();<-1>} :: main{f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step stmt return (); ---> +{ +stack: f{()<-1> :: return ();<0>} :: main{f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp () ---> +{ +stack: f{()<-1> :: return ();<0>} :: main{f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value () with return ();<1>((),) ---> +{ +stack: main{()<-1> :: f();<-1> :: return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value () with f();<0>((),) ---> +{ +stack: main{return 0;<-1>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step stmt return 0; ---> +{ +stack: main{0<-1> :: return 0;<0>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: return 0;<0>} :: top{} +heap: fun, fun
, +env: main: fun
, f: fun, +} +--- handle value 0 with return 0;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun, fun
, +env: main: fun
, f: fun, +} +result: 0 diff --git a/executable_semantics/testdata/fun5.6c b/executable_semantics/testdata/fun5.6c new file mode 100644 index 000000000000..85c525728ebb --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/fun5.golden b/executable_semantics/testdata/fun5.golden new file mode 100644 index 000000000000..1fb83d77c0e8 --- /dev/null +++ b/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, fun
, +env: main: fun
, add: fun, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{return (add(0 = 1, 1 = 2) - 3);<-1>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- 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, fun
, +env: main: fun
, add: fun, +} +--- 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, fun
, +env: main: fun
, add: fun, +} +--- 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, fun
, +env: main: fun
, add: fun, +} +--- step exp add ---> +{ +stack: main{fun<-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, fun
, +env: main: fun
, add: fun, +} +--- handle value fun with add(0 = 1, 1 = 2)<1>(fun,) ---> +{ +stack: main{(0 = 1, 1 = 2)<-1> :: add(0 = 1, 1 = 2)<1>(fun,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- step exp (0 = 1, 1 = 2) ---> +{ +stack: main{1<-1> :: (0 = 1, 1 = 2)<0> :: add(0 = 1, 1 = 2)<1>(fun,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: (0 = 1, 1 = 2)<0> :: add(0 = 1, 1 = 2)<1>(fun,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- 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(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- step exp 2 ---> +{ +stack: main{2<-1> :: (0 = 1, 1 = 2)<1>(1,) :: add(0 = 1, 1 = 2)<1>(fun,) :: (add(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, +env: main: fun
, add: fun, +} +--- 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(0 = 1, 1 = 2) - 3)<0> :: return (add(0 = 1, 1 = 2) - 3);<0>} :: top{} +heap: Int: x, Int: y, fun, fun
, 1, 2, +env: main: fun
, add: fun, +} +--- handle value (0 = 1@4, 1 = 2@5) with add(0 = 1, 1 = 2)<2>(fun,(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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, 1, 2, +env: y: 2, x: 1, main: fun
, add: fun, +} +--- 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, fun
, 1, 2, !!1, !!2, +env: main: fun
, add: fun, +} +--- 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, fun
, 1, 2, !!1, !!2, +env: main: fun
, add: fun, +} +--- 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, fun
, 1, 2, !!1, !!2, +env: main: fun
, add: fun, +} +--- 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, fun
, 1, 2, !!1, !!2, +env: main: fun
, add: fun, +} +--- handle value 0 with return (add(0 = 1, 1 = 2) - 3);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: Int: x, Int: y, fun, fun
, 1, 2, !!1, !!2, +env: main: fun
, add: fun, +} +result: 0 diff --git a/executable_semantics/testdata/fun6_fail_type.6c b/executable_semantics/testdata/fun6_fail_type.6c new file mode 100644 index 000000000000..b10a2c1537f0 --- /dev/null +++ b/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); +} diff --git a/executable_semantics/testdata/fun6_fail_type.golden b/executable_semantics/testdata/fun6_fail_type.golden new file mode 100644 index 000000000000..94b1a6bcc7ba --- /dev/null +++ b/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)) diff --git a/executable_semantics/testdata/fun_recur.6c b/executable_semantics/testdata/fun_recur.6c new file mode 100644 index 000000000000..b53060275b2f --- /dev/null +++ b/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); +} diff --git a/executable_semantics/testdata/fun_recur.golden b/executable_semantics/testdata/fun_recur.golden new file mode 100644 index 000000000000..83e98b9cf3c3 --- /dev/null +++ b/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) diff --git a/executable_semantics/testdata/funptr1.6c b/executable_semantics/testdata/funptr1.6c new file mode 100644 index 000000000000..114ace63fb3d --- /dev/null +++ b/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); +} diff --git a/executable_semantics/testdata/funptr1.golden b/executable_semantics/testdata/funptr1.golden new file mode 100644 index 000000000000..1902f0933fb8 --- /dev/null +++ b/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) diff --git a/executable_semantics/testdata/match_int.6c b/executable_semantics/testdata/match_int.6c new file mode 100644 index 000000000000..6e809eb27a9a --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/match_int.golden b/executable_semantics/testdata/match_int.golden new file mode 100644 index 000000000000..09c9b93feaae --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: t = 5; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: t = 5; ... ---> +{ +stack: main{var auto: t = 5;<-1> :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: t = 5; ---> +{ +stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 5 ---> +{ +stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp auto: t ---> +{ +stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp auto ---> +{ +stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 5, +env: t: 5, main: fun
, +} +--- step stmt match (t) {...} ---> +{ +stack: main{t<-1> :: match (t) {...}<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step exp t ---> +{ +stack: main{5<-1> :: match (t) {...}<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- handle value 5 with match (t) {...}<1>(5,) ---> +{ +stack: main{5<-1> :: match (t) {...}<1>(5,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step exp 5 ---> +{ +stack: main{5<-1> :: match (t) {...}<1>(5,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- handle value 5 with match (t) {...}<2>(5,5,) ---> +pattern_match(5, 5) +{ +stack: main{return 0;<-1> :: { + ... +} +<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step stmt return 0; ---> +{ +stack: main{0<-1> :: return 0;<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: return 0;<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- handle value 0 with return 0;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 5, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/match_int_default.6c b/executable_semantics/testdata/match_int_default.6c new file mode 100644 index 000000000000..62f61775940a --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/match_int_default.golden b/executable_semantics/testdata/match_int_default.golden new file mode 100644 index 000000000000..822c67942d7d --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: t = 5; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: t = 5; ... ---> +{ +stack: main{var auto: t = 5;<-1> :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: t = 5; ---> +{ +stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 5 ---> +{ +stack: main{5<-1> :: var auto: t = 5;<0> :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp auto: t ---> +{ +stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp auto ---> +{ +stack: main{auto<-1> :: auto: t<0> :: var auto: t = 5;<1>(5,) :: match (t) {...}<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 5, +env: t: 5, main: fun
, +} +--- step stmt match (t) {...} ---> +{ +stack: main{t<-1> :: match (t) {...}<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step exp t ---> +{ +stack: main{5<-1> :: match (t) {...}<0>} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- handle value 5 with match (t) {...}<1>(5,) ---> +{ +stack: main{3<-1> :: match (t) {...}<1>(5,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step exp 3 ---> +{ +stack: main{3<-1> :: match (t) {...}<1>(5,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- 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
, 5, +env: t: 5, main: fun
, +} +--- step exp 4 ---> +{ +stack: main{4<-1> :: match (t) {...}<3>(5,3,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- 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
, 5, +env: t: 5, main: fun
, +} +--- step exp auto: _ ---> +{ +stack: main{auto<-1> :: auto: _<0> :: match (t) {...}<5>(5,3,4,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- step exp auto ---> +{ +stack: main{auto<-1> :: auto: _<0> :: match (t) {...}<5>(5,3,4,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- handle value auto with auto: _<1>(auto,) ---> +{ +stack: main{auto: _<-1> :: match (t) {...}<5>(5,3,4,)} :: top{} +heap: fun
, 5, +env: t: 5, main: fun
, +} +--- handle value auto: _ with match (t) {...}<6>(5,3,4,auto: _,) ---> +pattern_match(auto: _, 5) +{ +stack: main{return 0;<-1> :: { + ... +} +<0>} :: top{} +heap: fun
, 5, 5, +env: _: 5, t: 5, main: fun
, +} +--- step stmt return 0; ---> +{ +stack: main{0<-1> :: return 0;<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 5, 5, +env: _: 5, t: 5, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: return 0;<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 5, 5, +env: _: 5, t: 5, main: fun
, +} +--- handle value 0 with return 0;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 5, !!5, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/match_type.6c b/executable_semantics/testdata/match_type.6c new file mode 100644 index 000000000000..a7714b8c0bfd --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/match_type.golden b/executable_semantics/testdata/match_type.golden new file mode 100644 index 000000000000..4bd82581859b --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: t = fn (0 = Int, 1 = Int) -> (); ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, +env: main: fun
, +} +--- 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
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- step stmt var Int: x = 0; ... ---> +{ +stack: main{var Int: x = 0;<-1> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- step stmt var Int: x = 0; ---> +{ +stack: main{0<-1> :: var Int: x = 0;<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: var Int: x = 0;<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- 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
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- step exp Int: x ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: match (t) {...} ... <-1>} :: top{} +heap: fun
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- step exp Int ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: match (t) {...} ... <-1>} :: top{} +heap: fun
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- 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
, Int, Int, Int, Int, fn (0 = Int@3, 1 = Int@4) -> (), +env: t: fn (0 = Int@3, 1 = Int@4) -> (), main: fun
, +} +--- 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
, 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
, +} +--- step stmt match (t) {...} ... ---> +{ +stack: main{match (t) {...}<-1> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt match (t) {...} ---> +{ +stack: main{t<-1> :: match (t) {...}<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- step exp t ---> +{ +stack: main{fn (0 = Int@3, 1 = Int@4) -> ()<-1> :: match (t) {...}<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- step stmt x = (x + 1); ---> +{ +stack: main{x<-1> :: x = (x + 1);<0> :: { + ... +} +<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- step lvalue x ---> +{ +stack: main{ptr<6><-1> :: x = (x + 1);<0> :: { + ... +} +<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- step exp (x + 1) ---> +{ +stack: main{x<-1> :: (x + 1)<0> :: x = (x + 1);<1>(ptr<6>,) :: { + ... +} +<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: (x + 1)<0> :: x = (x + 1);<1>(ptr<6>,) :: { + ... +} +<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: (x + 1)<1>(0,) :: x = (x + 1);<1>(ptr<6>,) :: { + ... +} +<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- handle value 1 with x = (x + 1);<2>(ptr<6>,1,) ---> +{ +stack: main{{ + ... +} +<0> :: match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{match (t) {...} ... <-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt match (t) {...} ... ---> +{ +stack: main{match (t) {...}<-1> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt match (t) {...} ---> +{ +stack: main{t<-1> :: match (t) {...}<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- step exp t ---> +{ +stack: main{fn (0 = Int@3, 1 = Int@4) -> ()<-1> :: match (t) {...}<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- step stmt x = (x - 1); ---> +{ +stack: main{x<-1> :: x = (x - 1);<0> :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- step lvalue x ---> +{ +stack: main{ptr<6><-1> :: x = (x - 1);<0> :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- step exp (x - 1) ---> +{ +stack: main{x<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<6>,) :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- step exp x ---> +{ +stack: main{1<-1> :: (x - 1)<0> :: x = (x - 1);<1>(ptr<6>,) :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: (x - 1)<1>(1,) :: x = (x - 1);<1>(ptr<6>,) :: { + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- handle value 0 with x = (x - 1);<2>(ptr<6>,0,) ---> +{ +stack: main{{ + ... +} +<0> :: return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt { + ... +} + ---> +{ +stack: main{return x;<-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt return x; ---> +{ +stack: main{x<-1> :: return x;<0>} :: top{} +heap: fun
, 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
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: return x;<0>} :: top{} +heap: fun
, 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
, +} +--- handle value 0 with return x;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 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
, +} +result: 0 diff --git a/executable_semantics/testdata/next.6c b/executable_semantics/testdata/next.6c new file mode 100644 index 000000000000..c1324486b8f8 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/next.golden b/executable_semantics/testdata/next.golden new file mode 100644 index 000000000000..441bc36a6587 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var Int: x = 0; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var Int: x = 0; ... ---> +{ +stack: main{var Int: x = 0;<-1> :: return x;<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var Int: x = 0; ---> +{ +stack: main{0<-1> :: var Int: x = 0;<0> :: return x;<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: var Int: x = 0;<0> :: return x;<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp Int: x ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: return x;<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp Int ---> +{ +stack: main{Int<-1> :: Int: x<0> :: var Int: x = 0;<1>(0,) :: return x;<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- step stmt return x; ---> +{ +stack: main{x<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value 0 with return x;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!0, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/pattern_init.6c b/executable_semantics/testdata/pattern_init.6c new file mode 100644 index 000000000000..7fa0b9cd3526 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/pattern_init.golden b/executable_semantics/testdata/pattern_init.golden new file mode 100644 index 000000000000..527a42bfdc75 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var (0 = auto: x, 1 = auto: y) = (0 = 2, 1 = 3); ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, +env: main: fun
, +} +--- 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
, 2, 3, auto: x, auto: y, +env: main: fun
, +} +--- 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
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- step stmt return ((y - x) - 1); ---> +{ +stack: main{((y - x) - 1)<-1> :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- step exp ((y - x) - 1) ---> +{ +stack: main{(y - x)<-1> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- step exp (y - x) ---> +{ +stack: main{y<-1> :: (y - x)<0> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- step exp y ---> +{ +stack: main{3<-1> :: (y - x)<0> :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- 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
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- step exp x ---> +{ +stack: main{2<-1> :: (y - x)<1>(3,) :: ((y - x) - 1)<0> :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- 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
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- 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
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: ((y - x) - 1)<1>(1,) :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- handle value 1 with ((y - x) - 1)<2>(1,1,) ---> +{ +stack: main{0<-1> :: return ((y - x) - 1);<0>} :: top{} +heap: fun
, 2, 3, auto: x, auto: y, 2, 3, +env: y: 3, x: 2, main: fun
, +} +--- handle value 0 with return ((y - x) - 1);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 2, 3, auto: x, auto: y, !!2, !!3, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/record1.6c b/executable_semantics/testdata/record1.6c new file mode 100644 index 000000000000..661685e4a99e --- /dev/null +++ b/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 +} diff --git a/executable_semantics/testdata/record1.golden b/executable_semantics/testdata/record1.golden new file mode 100644 index 000000000000..d1997a9ab5bb --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var (x = Int, y = Int): t2 = (y = 5, x = 2); ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, Int, Int, +env: main: fun
, +} +--- 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
, 5, 2, Int, Int, +env: main: fun
, +} +--- 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
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- step stmt t2.y = 3; ... ---> +{ +stack: main{t2.y = 3;<-1> :: return ((t2.y - t2.x) - 1);<-1>} :: top{} +heap: fun
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- step stmt t2.y = 3; ---> +{ +stack: main{t2.y<-1> :: t2.y = 3;<0> :: return ((t2.y - t2.x) - 1);<-1>} :: top{} +heap: fun
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- step exp 3 ---> +{ +stack: main{3<-1> :: t2.y = 3;<1>(ptr<5>,) :: return ((t2.y - t2.x) - 1);<-1>} :: top{} +heap: fun
, 5, 2, Int, Int, 5, 2, (y = 5@5, x = 2@6), +env: t2: (y = 5@5, x = 2@6), main: fun
, +} +--- handle value 3 with t2.y = 3;<2>(ptr<5>,3,) ---> +{ +stack: main{return ((t2.y - t2.x) - 1);<-1>} :: top{} +heap: fun
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: ((t2.y - t2.x) - 1)<1>(1,) :: return ((t2.y - t2.x) - 1);<0>} :: top{} +heap: fun
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- 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
, 5, 2, Int, Int, 3, 2, (y = 3@5, x = 2@6), +env: t2: (y = 3@5, x = 2@6), main: fun
, +} +--- handle value 0 with return ((t2.y - t2.x) - 1);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 5, 2, Int, Int, !!3, !!2, !!(y = !!3@5, x = !!2@6), +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/struct1.6c b/executable_semantics/testdata/struct1.6c new file mode 100644 index 000000000000..7950f53ef191 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/struct1.golden b/executable_semantics/testdata/struct1.golden new file mode 100644 index 000000000000..28ae32f7f6ce --- /dev/null +++ b/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
, +env: main: fun
, Point: struct Point, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: p = Point(x = 1, y = 2); ... <-1>} :: top{} +heap: struct Point, fun
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p: Point(x = 1@6, y = 2@7), main: fun
, Point: struct Point, +} +--- handle value 0 with return ((p.y - p.x) - 1);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: struct Point, fun
, 1, 2, 1, 2, !!1, !!2, !!Point!!(x = !!1@6, y = !!2@7), +env: main: fun
, Point: struct Point, +} +result: 0 diff --git a/executable_semantics/testdata/struct2.6c b/executable_semantics/testdata/struct2.6c new file mode 100644 index 000000000000..ee43764a5909 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/struct2.golden b/executable_semantics/testdata/struct2.golden new file mode 100644 index 000000000000..c8c5abbab451 --- /dev/null +++ b/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
, +env: main: fun
, Point: struct Point, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: p1 = Point(x = 1, y = 2); ... <-1>} :: top{} +heap: struct Point, fun
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 1, 2, 1, 2, 1, 2, Point(x = 1@6, y = 2@7), +env: p1: Point(x = 1@6, y = 2@7), main: fun
, 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
, 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
, Point: struct Point, +} +--- step stmt p2.x = 3; ... ---> +{ +stack: main{p2.x = 3;<-1> :: return (p1.x - 1);<-1>} :: top{} +heap: struct Point, fun
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, 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
, Point: struct Point, +} +--- handle value 0 with return (p1.x - 1);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: struct Point, fun
, 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
, Point: struct Point, +} +result: 0 diff --git a/executable_semantics/testdata/struct3.6c b/executable_semantics/testdata/struct3.6c new file mode 100644 index 000000000000..3b425545df37 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/struct3.golden b/executable_semantics/testdata/struct3.golden new file mode 100644 index 000000000000..4db864374f31 --- /dev/null +++ b/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
, +env: main: fun
, Point: struct Point, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: struct Point, fun
, +env: main: fun
, Point: struct Point, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{return (Point(x = 1, y = 2).x - 1);<-1>} :: top{} +heap: struct Point, fun
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, +env: main: fun
, 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
, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, +env: main: fun
, 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
, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), +env: main: fun
, 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
, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), +env: main: fun
, 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
, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), +env: main: fun
, 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
, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), +env: main: fun
, 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
, 1, 2, 1, 2, Point(x = 1@4, y = 2@5), +env: main: fun
, 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
, 1, 2, !!1, !!2, !!Point!!(x = !!1@4, y = !!2@5), +env: main: fun
, 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
, 1, 2, !!1, !!2, !!Point!!(x = !!1@4, y = !!2@5), +env: main: fun
, Point: struct Point, +} +result: 0 diff --git a/executable_semantics/testdata/tuple1.6c b/executable_semantics/testdata/tuple1.6c new file mode 100644 index 000000000000..c6b7a382f0b7 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/tuple1.golden b/executable_semantics/testdata/tuple1.golden new file mode 100644 index 000000000000..12f4fca79183 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var Int: x = 1; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, Int, Int, +env: x: 1, main: fun
, +} +--- 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
, 1, 5, 2, Int, Int, +env: x: 1, main: fun
, +} +--- 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
, 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
, +} +--- step stmt t2[0] = 3; ... ---> +{ +stack: main{t2[0] = 3;<-1> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{} +heap: fun
, 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
, +} +--- step stmt t2[0] = 3; ---> +{ +stack: main{t2[0]<-1> :: t2[0] = 3;<0> :: return ((t2[0] - t2[1]) - x);<-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- step exp 3 ---> +{ +stack: main{3<-1> :: t2[0] = 3;<1>(ptr<6>,) :: return ((t2[0] - t2[1]) - x);<-1>} :: top{} +heap: fun
, 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
, +} +--- handle value 3 with t2[0] = 3;<2>(ptr<6>,3,) ---> +{ +stack: main{return ((t2[0] - t2[1]) - x);<-1>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- step exp x ---> +{ +stack: main{1<-1> :: ((t2[0] - t2[1]) - x)<1>(1,) :: return ((t2[0] - t2[1]) - x);<0>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- handle value 0 with return ((t2[0] - t2[1]) - x);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!1, 5, 2, Int, Int, !!3, !!2, !!(0 = !!3@6, 1 = !!2@7), +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/tuple2.6c b/executable_semantics/testdata/tuple2.6c new file mode 100644 index 000000000000..f4a3690408bf --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/tuple2.golden b/executable_semantics/testdata/tuple2.golden new file mode 100644 index 000000000000..d16e910b368a --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var (0 = Int): t = (0 = 5); ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 5, +env: main: fun
, +} +--- 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
, 5, +env: main: fun
, +} +--- 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
, 5, +env: main: fun
, +} +--- 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
, 5, +env: main: fun
, +} +--- 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
, 5, +env: main: fun
, +} +--- 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
, 5, Int, +env: main: fun
, +} +--- 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
, 5, Int, +env: main: fun
, +} +--- 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
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- step stmt return (t[0] - 5); ---> +{ +stack: main{(t[0] - 5)<-1> :: return (t[0] - 5);<0>} :: top{} +heap: fun
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- step exp (t[0] - 5) ---> +{ +stack: main{t[0]<-1> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{} +heap: fun
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- step exp t[0] ---> +{ +stack: main{t<-1> :: t[0]<0> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{} +heap: fun
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- step exp t ---> +{ +stack: main{(0 = 5@3)<-1> :: t[0]<0> :: (t[0] - 5)<0> :: return (t[0] - 5);<0>} :: top{} +heap: fun
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- 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
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- 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
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- 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
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- 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
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- step exp 5 ---> +{ +stack: main{5<-1> :: (t[0] - 5)<1>(5,) :: return (t[0] - 5);<0>} :: top{} +heap: fun
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- handle value 5 with (t[0] - 5)<2>(5,5,) ---> +{ +stack: main{0<-1> :: return (t[0] - 5);<0>} :: top{} +heap: fun
, 5, Int, 5, (0 = 5@3), +env: t: (0 = 5@3), main: fun
, +} +--- handle value 0 with return (t[0] - 5);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 5, Int, !!5, !!(0 = !!5@3), +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/tuple_assign.6c b/executable_semantics/testdata/tuple_assign.6c new file mode 100644 index 000000000000..392babb1c4a1 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/tuple_assign.golden b/executable_semantics/testdata/tuple_assign.golden new file mode 100644 index 000000000000..ac471eac4ff2 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: x = 0; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: x = 0; ... ---> +{ +stack: main{var auto: x = 0;<-1> :: var auto: y = 1; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: x = 0; ---> +{ +stack: main{0<-1> :: var auto: x = 0;<0> :: var auto: y = 1; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: var auto: x = 0;<0> :: var auto: y = 1; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp auto ---> +{ +stack: main{auto<-1> :: auto: x<0> :: var auto: x = 0;<1>(0,) :: var auto: y = 1; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- step exp 1 ---> +{ +stack: main{1<-1> :: var auto: y = 1;<0> :: (0 = x, 1 = y) = (0 = 5, 1 = (- 5)); ... <-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 0, 1, ptr<1>, ptr<2>, 5, -5, +env: y: 1, x: 0, main: fun
, +} +--- 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
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- step stmt return (x + y); ---> +{ +stack: main{(x + y)<-1> :: return (x + y);<0>} :: top{} +heap: fun
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- step exp (x + y) ---> +{ +stack: main{x<-1> :: (x + y)<0> :: return (x + y);<0>} :: top{} +heap: fun
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- step exp x ---> +{ +stack: main{5<-1> :: (x + y)<0> :: return (x + y);<0>} :: top{} +heap: fun
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- handle value 5 with (x + y)<1>(5,) ---> +{ +stack: main{y<-1> :: (x + y)<1>(5,) :: return (x + y);<0>} :: top{} +heap: fun
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- step exp y ---> +{ +stack: main{-5<-1> :: (x + y)<1>(5,) :: return (x + y);<0>} :: top{} +heap: fun
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- handle value -5 with (x + y)<2>(5,-5,) ---> +{ +stack: main{0<-1> :: return (x + y);<0>} :: top{} +heap: fun
, 5, -5, ptr<1>, ptr<2>, 5, -5, +env: y: -5, x: 5, main: fun
, +} +--- handle value 0 with return (x + y);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!5, !!-5, ptr<1>, ptr<2>, !!5, !!-5, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/tuple_match.6c b/executable_semantics/testdata/tuple_match.6c new file mode 100644 index 000000000000..bc98c3ee2e89 --- /dev/null +++ b/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; + } +} diff --git a/executable_semantics/testdata/tuple_match.golden b/executable_semantics/testdata/tuple_match.golden new file mode 100644 index 000000000000..f799a5869a1d --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: t = (0 = 5, 1 = 2); ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, +env: main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- step stmt match (t) {...} ---> +{ +stack: main{t<-1> :: match (t) {...}<0>} :: top{} +heap: fun
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- step exp t ---> +{ +stack: main{(0 = 5@3, 1 = 2@4)<-1> :: match (t) {...}<0>} :: top{} +heap: fun
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, +env: t: (0 = 5@3, 1 = 2@4), main: fun
, +} +--- 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
, 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
, +} +--- step stmt return ((a + b) - 7); ---> +{ +stack: main{((a + b) - 7)<-1> :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- step exp ((a + b) - 7) ---> +{ +stack: main{(a + b)<-1> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- step exp (a + b) ---> +{ +stack: main{a<-1> :: (a + b)<0> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- step exp a ---> +{ +stack: main{5<-1> :: (a + b)<0> :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- step exp b ---> +{ +stack: main{2<-1> :: (a + b)<1>(5,) :: ((a + b) - 7)<0> :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- 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
, 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
, +} +--- 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
, 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
, +} +--- step exp 7 ---> +{ +stack: main{7<-1> :: ((a + b) - 7)<1>(7,) :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- handle value 7 with ((a + b) - 7)<2>(7,7,) ---> +{ +stack: main{0<-1> :: return ((a + b) - 7);<0> :: { + ... +} +<0>} :: top{} +heap: fun
, 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
, +} +--- handle value 0 with return ((a + b) - 7);<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, 5, 2, 5, 2, (0 = 5@3, 1 = 2@4), auto: a, auto: b, !!5, !!2, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/undef1.6c b/executable_semantics/testdata/undef1.6c new file mode 100644 index 000000000000..b83dcfc19f97 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/undef1.golden b/executable_semantics/testdata/undef1.golden new file mode 100644 index 000000000000..90b8af3fd78a --- /dev/null +++ b/executable_semantics/testdata/undef1.golden @@ -0,0 +1 @@ +executable_semantics/testdata/undef1.6c:8: syntax error diff --git a/executable_semantics/testdata/undef2.6c b/executable_semantics/testdata/undef2.6c new file mode 100644 index 000000000000..85df56eb4655 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/undef2.golden b/executable_semantics/testdata/undef2.golden new file mode 100644 index 000000000000..138b901faa90 --- /dev/null +++ b/executable_semantics/testdata/undef2.golden @@ -0,0 +1,3 @@ +********** source program ********** +********** type checking ********** +error, program must contain a function named `main` diff --git a/executable_semantics/testdata/while1.6c b/executable_semantics/testdata/while1.6c new file mode 100644 index 000000000000..ed80d1db47c4 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/while1.golden b/executable_semantics/testdata/while1.golden new file mode 100644 index 000000000000..3680ec3e5196 --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{var auto: x = 2; ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: x = 2; ... ---> +{ +stack: main{var auto: x = 2;<-1> :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt var auto: x = 2; ---> +{ +stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 2 ---> +{ +stack: main{2<-1> :: var auto: x = 2;<0> :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- step exp auto: x ---> +{ +stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp auto ---> +{ +stack: main{auto<-1> :: auto: x<0> :: var auto: x = 2;<1>(2,) :: while ((! (x == 0))) + ... ... <-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- 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
, +env: main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ... ---> +{ +stack: main{while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ---> +{ +stack: main{(! (x == 0))<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp (! (x == 0)) ---> +{ +stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp (x == 0) ---> +{ +stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step exp x ---> +{ +stack: main{2<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: (x == 0)<1>(2,) :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- handle value false with (! (x == 0))<1>(false,) ---> +{ +stack: main{true<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- step stmt x = (x - 1); ---> +{ +stack: main{x<-1> :: x = (x - 1);<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- step lvalue x ---> +{ +stack: main{ptr<1><-1> :: x = (x - 1);<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- 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
, 2, +env: x: 2, main: fun
, +} +--- handle value 1 with x = (x - 1);<2>(ptr<1>,1,) ---> +{ +stack: main{while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ---> +{ +stack: main{(! (x == 0))<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp (! (x == 0)) ---> +{ +stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp (x == 0) ---> +{ +stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step exp x ---> +{ +stack: main{1<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: (x == 0)<1>(1,) :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- handle value false with (! (x == 0))<1>(false,) ---> +{ +stack: main{true<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- step stmt x = (x - 1); ---> +{ +stack: main{x<-1> :: x = (x - 1);<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- step lvalue x ---> +{ +stack: main{ptr<1><-1> :: x = (x - 1);<0> :: while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- 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
, 1, +env: x: 1, main: fun
, +} +--- handle value 0 with x = (x - 1);<2>(ptr<1>,0,) ---> +{ +stack: main{while ((! (x == 0))) + ... <-1> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt while ((! (x == 0))) + ... ---> +{ +stack: main{(! (x == 0))<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp (! (x == 0)) ---> +{ +stack: main{(x == 0)<-1> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp (x == 0) ---> +{ +stack: main{x<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: (x == 0)<0> :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: (x == 0)<1>(0,) :: (! (x == 0))<0> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- 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
, 0, +env: x: 0, main: fun
, +} +--- handle value true with (! (x == 0))<1>(true,) ---> +{ +stack: main{false<-1> :: while ((! (x == 0))) + ... <0> :: return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value false with while ((! (x == 0))) + ... <1>(false,) ---> +{ +stack: main{return x;<-1>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step stmt return x; ---> +{ +stack: main{x<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- step exp x ---> +{ +stack: main{0<-1> :: return x;<0>} :: top{} +heap: fun
, 0, +env: x: 0, main: fun
, +} +--- handle value 0 with return x;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, !!0, +env: main: fun
, +} +result: 0 diff --git a/executable_semantics/testdata/zero.6c b/executable_semantics/testdata/zero.6c new file mode 100644 index 000000000000..85911ed193e6 --- /dev/null +++ b/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; +} diff --git a/executable_semantics/testdata/zero.golden b/executable_semantics/testdata/zero.golden new file mode 100644 index 000000000000..33c89ae16eea --- /dev/null +++ b/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
, +env: main: fun
, +} +--- step exp main() ---> +{ +stack: top{main<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- step exp main ---> +{ +stack: top{fun
<-1> :: main()<0>} +heap: fun
, +env: main: fun
, +} +--- handle value fun
with main()<1>(fun
,) ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- step exp () ---> +{ +stack: top{()<-1> :: main()<1>(fun
,)} +heap: fun
, +env: main: fun
, +} +--- handle value () with main()<2>(fun
,(),) ---> +pattern_match((), ()) +{ +stack: main{return 0;<-1>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step stmt return 0; ---> +{ +stack: main{0<-1> :: return 0;<0>} :: top{} +heap: fun
, +env: main: fun
, +} +--- step exp 0 ---> +{ +stack: main{0<-1> :: return 0;<0>} :: top{} +heap: fun
, +env: main: fun
, +} +--- handle value 0 with return 0;<1>(0,) ---> +{ +stack: top{0<-1>} +heap: fun
, +env: main: fun
, +} +result: 0