Boaz Brickner aa23e9e2d8 Update LLVM (#4807) hai 1 ano
..
BUILD 13de9e9d06 Fix outstanding `clang-tidy` errors. (#3654) %!s(int64=2) %!d(string=hai) anos
README.md bfe5c36bfc Move `Value`, `Address`, and `ElementPath` to ast/. (#2659) %!s(int64=3) %!d(string=hai) anos
action.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
action.h 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
action_stack.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
action_stack.h 53af8f04b2 Provide a Printable CRTP parent to replace HasPrintable templates. (#3166) %!s(int64=2) %!d(string=hai) anos
builtins.cpp 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
builtins.def 9e1a5cfaee Reuse EnumBase for interpreter's Builtin enum (#2688) %!s(int64=3) %!d(string=hai) anos
builtins.h 5020fdb3be Use abbreviation "decl" instead of "declaration" (#3382) %!s(int64=2) %!d(string=hai) anos
dictionary.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
exec_program.cpp 289d05813e Explorer: Remove `PrintDepth` and implement `PrintIndent`. (#3113) %!s(int64=2) %!d(string=hai) anos
exec_program.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
heap.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
heap.h dd0890619a Enable a couple of boring warnings. (#4018) hai 1 ano
heap_allocation_interface.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
impl_scope.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
impl_scope.h 53af8f04b2 Provide a Printable CRTP parent to replace HasPrintable templates. (#3166) %!s(int64=2) %!d(string=hai) anos
interpreter.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
interpreter.h b6d660b4d9 Add nested array size deduction from tuple (#2909) %!s(int64=2) %!d(string=hai) anos
matching_impl_set.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
matching_impl_set.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
pattern_analysis.cpp aa23e9e2d8 Update LLVM (#4807) hai 1 ano
pattern_analysis.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
pattern_match.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
pattern_match.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
resolve_control_flow.cpp 8c64f0bfdd Add `-Wmissing-prototypes` and fix issues it finds. (#4019) hai 1 ano
resolve_control_flow.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
resolve_names.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
resolve_names.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
resolve_unformed.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
resolve_unformed.h 357baaeef8 Rename //explorer/common to base (#3103) %!s(int64=2) %!d(string=hai) anos
stack.h 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
stack_space.cpp ce1a63509d Make stack detection more reliable. (#2845) %!s(int64=2) %!d(string=hai) anos
stack_space.h 81e53886a8 Fix crash on use of uninitialized array element, and improve unformed checking (#2862) %!s(int64=2) %!d(string=hai) anos
type_checker.cpp a45cb86bf7 Add a compile-time check that the condition of a CHECK is not constant. (#4628) hai 1 ano
type_checker.h a4c0febc0f handle missing addr in self pointer pattern (#3369) %!s(int64=2) %!d(string=hai) anos
type_structure.cpp c93a0e5e42 Implement canonicalization of Value and Element (#3024) %!s(int64=2) %!d(string=hai) anos
type_structure.h 53af8f04b2 Provide a Printable CRTP parent to replace HasPrintable templates. (#3166) %!s(int64=2) %!d(string=hai) anos
type_utils.cpp 4845f40dff Switch `CARBON_CHECK` to a format string API (#4285) hai 1 ano
type_utils.h ada9564077 Add missing `#include` (#4513) hai 1 ano

README.md

explorer execution

The code in this directory defines all phases of program execution after parsing, including typechecking, name resolution, and execution. The overall flow can be found in ExecProgram, which executes each phase in sequence.

The Carbon abstract machine

Execution is specified in terms of an abstract machine, which executes minimal program steps in a loop until the program terminates. The state of the Carbon program (including the stack as well as the heap) is represented explicitly in C++ data structures, rather than implicitly in the C++ call stack. The Interpreter class represents an instance of the abstract machine, and is responsible for maintaining those data structures and implementing the steps of abstract machine execution.

The control-flow state of the abstract machine is encapsulated in an ActionStack object, which a represents a stack of Actions. An Action represents a self-contained computation (such as evaluation of an expression or execution of a statement) as a state machine, and the abstract machine proceeds by repeatedly executing the next state transition of the Action at the top of the stack. Executing a step may modify the internal state of the Action, and may also modify the Action stack, for example by pushing a new Action onto it. When an Action is done executing, it can optionally produce a value as its result, which is made available to the Action below it on the stack.

Carbon values are represented as Value objects, both at compile time and at run time. Note that in Carbon, a type is a kind of value, so types are represented as Values. More subtly, Value can also represent information that isn't a true Carbon value, but needs to be propagated through channels that use Value. Most notably, certain kinds of Value are used to represent the result of "evaluating" a Pattern, which evaluates all the subexpressions nested within it, while preserving the structure of the non-expression parts for use in pattern matching.

Values are always immutable. The abstract machine's mutable memory is represented using the Heap class, which is essentially a mapping of Addresses to Values.

Example

To evaluate the expression ((1 + 2) + 4), the interpreter starts by pushing an Action onto the stack that corresponds to the whole expression:

((1 + 2) + 4) .0. ## ...

In this notation, we're expressing the stack as a sequence of Actions separated by ##, with the top at the left, and representing each Action as the expression it evaluates, followed by its state. An Action consists of:

  • The syntax for the part of the program being executed, in this case ((1 + 2) + 4).
  • An integer pos for position, which is initially 0 and usually counts the number of steps executed. Here that's denoted with a number between two periods.
  • A vector results, which collects the results of any sub-Actions spawned by the Action. Above the results are omitted because they are currently empty.
  • A scope mapping variables to their values, for those variables whose lifetimes are associated with this action.

Then the interpreter proceeds by repeatedly taking the next step of the Action at the top of the stack. For expression Actions, pos typically identifies the operand that the next step should begin evaluation of. In this case, that operand is the expression (1 + 2), so we push a new Action onto the stack, and increment pos on the old one:

(1 + 2) .0. ## ((1 + 2) + 4) .1. ## ...

The next step spawns an action to evaluate 1:

1 .0. ## (1 + 2) .1. ## ((1 + 2) + 4) .1. ## ...

That expression can be fully evaluated in a single step, so the next step evaluates it, appends the result to the next Action down the stack, and pops the now-completed Action off the stack:

(1 + 2) .1. [[1]] ## ((1 + 2) + 4) .1. ## ...

The result 1 has been stored in the results list of the top Action, which is displayed between [[ and ]]. The top Action's pos is 1, so the next step begins evaluation of the second operand:

2 .0. ## (1 + 2) .2. [[1]] ## ((1 + 2) + 4) .1. ## ...

Which again can be evaluated immediately:

(1 + 2) .2. [[1, 2]] ## ((1 + 2) + 4) .1. ## ...

This expression has two operands, so now that pos is 2, all operands have been evaluated, and their results are in the corresponding entries of results. Thus, the next step can compute the expression value, passing it down to the parent Action and popping the completed action as before:

((1 + 2) + 4) .1. [[3]] ## ...

Evaluation now proceeds to the second operand:

4 .0. ## ((1 + 2) + 4) .2. [[3]] ## ...

Which, again, can be evaluated immediately:

((1 + 2) + 4) .2. [[3, 4]] ## ...

pos now indicates that all subexpressions have been evaluated, so the next step computes the final result of 7.