Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store named constant values in the AST #1011

Merged
merged 2 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions executable_semantics/ast/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,22 @@ class GenericBinding : public AstNode {
auto has_static_type() const -> bool { return static_type_.has_value(); }

auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return constant_value_;
}

// Sets the value returned by constant_value(). Can only be called once,
// during typechecking.
void set_constant_value(Nonnull<const Value*> value) {
CHECK(!constant_value_.has_value());
constant_value_ = value;
}

private:
std::string name_;
Nonnull<Expression*> type_;
std::optional<Nonnull<const Value*>> static_type_;
std::optional<Nonnull<const Value*>> constant_value_;
};

// The syntactic representation of a function declaration's return type.
Expand Down Expand Up @@ -232,13 +243,24 @@ class FunctionDeclaration : public Declaration {
auto body() -> std::optional<Nonnull<Block*>> { return body_; }

auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return constant_value_;
}

// Sets the value returned by constant_value(). Can only be called once,
// during typechecking.
void set_constant_value(Nonnull<const Value*> value) {
CHECK(!constant_value_.has_value());
constant_value_ = value;
}

private:
std::string name_;
std::vector<Nonnull<GenericBinding*>> deduced_parameters_;
Nonnull<TuplePattern*> param_pattern_;
ReturnTerm return_term_;
std::optional<Nonnull<Block*>> body_;
std::optional<Nonnull<const Value*>> constant_value_;
};

class ClassDeclaration : public Declaration {
Expand All @@ -259,10 +281,21 @@ class ClassDeclaration : public Declaration {
auto members() const -> llvm::ArrayRef<Nonnull<Member*>> { return members_; }

auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return constant_value_;
}

// Sets the value returned by constant_value(). Can only be called once,
// during typechecking.
void set_constant_value(Nonnull<const Value*> value) {
CHECK(!constant_value_.has_value());
constant_value_ = value;
}

private:
std::string name_;
std::vector<Nonnull<Member*>> members_;
std::optional<Nonnull<const Value*>> constant_value_;
};

class AlternativeSignature : public AstNode {
Expand Down Expand Up @@ -312,10 +345,21 @@ class ChoiceDeclaration : public Declaration {
}

auto value_category() const -> ValueCategory { return ValueCategory::Let; }
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return constant_value_;
}

// Sets the value returned by constant_value(). Can only be called once,
// during typechecking.
void set_constant_value(Nonnull<const Value*> value) {
CHECK(!constant_value_.has_value());
constant_value_ = value;
}

private:
std::string name_;
std::vector<Nonnull<AlternativeSignature*>> alternatives_;
std::optional<Nonnull<const Value*>> constant_value_;
};

// Global variable definition implements the Declaration concept.
Expand Down
5 changes: 5 additions & 0 deletions executable_semantics/ast/pattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class Pattern : public AstNode {
auto has_static_type() const -> bool { return static_type_.has_value(); }

// The value of this pattern. Cannot be called before typechecking.
// TODO rename to avoid confusion with BindingPattern::constant_value
auto value() const -> const Value& { return **value_; }

// Sets the value of this pattern. Can only be called once, during
Expand Down Expand Up @@ -122,6 +123,10 @@ class BindingPattern : public Pattern {

auto value_category() const -> ValueCategory { return ValueCategory::Var; }

auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}

private:
std::string name_;
Nonnull<Pattern*> type_;
Expand Down
3 changes: 3 additions & 0 deletions executable_semantics/ast/statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,9 @@ class Continuation : public Statement {
auto has_static_type() const -> bool { return static_type_.has_value(); }

auto value_category() const -> ValueCategory { return ValueCategory::Var; }
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}

private:
std::string name_;
Expand Down
17 changes: 16 additions & 1 deletion executable_semantics/ast/static_scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ static constexpr std::string_view AnonymousName = "_";
// Returns the name of an IdentifierExpression that names *this. If *this
// is anonymous, returns AnonymousName.
auto name() const -> std::string_view;

// If *this names a compile-time constant whose value is known, returns that
// value. Otherwise returns std::nullopt.
auto constant_value() const -> std::optional<Nonnull<const Value*>>;
*/
// NodeType must be derived from AstNode.
//
Expand Down Expand Up @@ -70,7 +74,11 @@ class NamedEntityView {
}),
value_category_([](const AstNode& base) -> ValueCategory {
return llvm::cast<NodeType>(base).value_category();
}) {
}),
constant_value_(
[](const AstNode& base) -> std::optional<Nonnull<const Value*>> {
return llvm::cast<NodeType>(base).constant_value();
}) {
CHECK(node->name() != AnonymousName)
<< "Entity with no name used as NamedEntity: " << *node;
}
Expand All @@ -94,6 +102,11 @@ class NamedEntityView {
return value_category_(*base_);
}

// Returns node->constant_value()
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return constant_value_(*base_);
}

friend auto operator==(const NamedEntityView& lhs, const NamedEntityView& rhs)
-> bool {
return lhs.base_ == rhs.base_;
Expand All @@ -114,6 +127,8 @@ class NamedEntityView {
std::function<std::string_view(const AstNode&)> name_;
std::function<const Value&(const AstNode&)> static_type_;
std::function<ValueCategory(const AstNode&)> value_category_;
std::function<std::optional<Nonnull<const Value*>>(const AstNode&)>
constant_value_;
};

// Maps the names visible in a given scope to the entities they name.
Expand Down
1 change: 1 addition & 0 deletions executable_semantics/interpreter/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ cc_library(
":heap",
"//common:check",
"//common:ostream",
"//executable_semantics/ast",
"//executable_semantics/ast:declaration",
"//executable_semantics/ast:expression",
"//executable_semantics/common:arena",
Expand Down
3 changes: 3 additions & 0 deletions executable_semantics/interpreter/action.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ void Action::Print(llvm::raw_ostream& out) const {
case Action::Kind::StatementAction:
cast<StatementAction>(*this).statement().PrintDepth(1, out);
break;
case Action::Kind::DeclarationAction:
cast<DeclarationAction>(*this).declaration().Print(out);
break;
case Action::Kind::ScopeAction:
out << "ScopeAction";
}
Expand Down
19 changes: 19 additions & 0 deletions executable_semantics/interpreter/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class Action {
ExpressionAction,
PatternAction,
StatementAction,
DeclarationAction,
ScopeAction,
};

Expand Down Expand Up @@ -203,6 +204,24 @@ class StatementAction : public Action {
Nonnull<const Statement*> statement_;
};

// Action which implements the run-time effects of executing a Declaration.
// Does not produce a result.
class DeclarationAction : public Action {
public:
explicit DeclarationAction(Nonnull<const Declaration*> declaration)
: Action(Kind::DeclarationAction), declaration_(declaration) {}

static auto classof(const Action* action) -> bool {
return action->kind() == Kind::DeclarationAction;
}

// The Declaration this Action executes.
auto declaration() const -> const Declaration& { return *declaration_; }

private:
Nonnull<const Declaration*> declaration_;
};

// Action which does nothing except introduce a new scope into the action
// stack. This is useful when a distinct scope doesn't otherwise have an
// Action it can naturally be associated with. ScopeActions are not associated
Expand Down
11 changes: 6 additions & 5 deletions executable_semantics/interpreter/action_stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ void ActionStack::Print(llvm::raw_ostream& out) const {
}
}

void ActionStack::Start(std::unique_ptr<Action> action, Scope scope) {
void ActionStack::Start(std::unique_ptr<Action> action) {
result_ = std::nullopt;
CHECK(todo_.IsEmpty());
todo_ = {};
todo_.Push(std::make_unique<ScopeAction>(std::move(scope)));
todo_.Push(std::move(action));
}

Expand All @@ -30,7 +30,7 @@ auto ActionStack::CurrentScope() const -> Scope& {
return *action->scope();
}
}
FATAL() << "No current scope";
return globals_;
}

void ActionStack::FinishAction() {
Expand All @@ -43,16 +43,17 @@ void ActionStack::FinishAction() {
case Action::Kind::ScopeAction:
FATAL() << "ScopeAction at top of stack";
case Action::Kind::StatementAction:
case Action::Kind::DeclarationAction:
PopScopes();
CHECK(!IsEmpty());
}
}

void ActionStack::FinishAction(Nonnull<const Value*> result) {
std::unique_ptr<Action> act = todo_.Pop();
switch (act->kind()) {
case Action::Kind::StatementAction:
FATAL() << "Statements cannot produce results.";
case Action::Kind::DeclarationAction:
FATAL() << "This kind of Action cannot produce results.";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"This" is too vague in the error message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, updated this to log the action as well.

case Action::Kind::ScopeAction:
FATAL() << "ScopeAction at top of stack";
case Action::Kind::ExpressionAction:
Expand Down
12 changes: 8 additions & 4 deletions executable_semantics/interpreter/action_stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ namespace Carbon {
class ActionStack {
public:
// Constructs an empty ActionStack
ActionStack() = default;
explicit ActionStack(Scope globals) : globals_(std::move(globals)) {}

void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }

// Starts execution with `action` at the top of the stack, in the given scope.
// `action` must be an `ExpressionAction` or `PatternAction`.
void Start(std::unique_ptr<Action> action, Scope scope);
// Returns an Env containing the currently-defined global variables.
auto GlobalEnv() const -> Env { return globals_.values(); }

// Starts execution with `action` at the top of the stack. Cannot be called
// when IsEmpty() is false.
void Start(std::unique_ptr<Action> action);

// True if the stack is empty.
auto IsEmpty() const -> bool { return todo_.IsEmpty(); }
Expand Down Expand Up @@ -97,6 +100,7 @@ class ActionStack {
// TODO: consider defining a non-nullable unique_ptr-like type to use here.
Stack<std::unique_ptr<Action>> todo_;
std::optional<Nonnull<const Value*>> result_;
mutable Scope globals_;
};

} // namespace Carbon
Expand Down
3 changes: 1 addition & 2 deletions executable_semantics/interpreter/exec_program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ void ExecProgram(Nonnull<Arena*> arena, AST ast, bool trace) {
}
llvm::outs() << "********** starting execution **********\n";
}
int result =
Interpreter(arena, trace).InterpProgram(ast.declarations, *ast.main_call);
int result = Interpreter(arena, trace).InterpProgram(ast);
llvm::outs() << "result: " << result << "\n";
}

Expand Down
Loading