Files
carbon-lang/executable_semantics/ast/expression.h
T
Geoff Romer bb28d37eed Drop support for named tuple fields (#886)
Rationale: Based on the status of #478 and #505, Carbon won't have this feature for a while, and it will be simpler not to support it on spec in the meantime.
2021-10-15 13:19:57 -07:00

456 lines
14 KiB
C++

// 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 <optional>
#include <string>
#include <variant>
#include <vector>
#include "common/ostream.h"
#include "executable_semantics/ast/paren_contents.h"
#include "executable_semantics/ast/source_location.h"
#include "executable_semantics/common/arena.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Compiler.h"
namespace Carbon {
class Value;
class Expression {
public:
enum class Kind {
BoolTypeLiteral,
BoolLiteral,
CallExpression,
FunctionTypeLiteral,
FieldAccessExpression,
IndexExpression,
IntTypeLiteral,
ContinuationTypeLiteral, // The type of a continuation value.
IntLiteral,
PrimitiveOperatorExpression,
StringLiteral,
StringTypeLiteral,
TupleLiteral,
StructLiteral,
StructTypeLiteral,
TypeTypeLiteral,
IdentifierExpression,
IntrinsicExpression,
};
void Print(llvm::raw_ostream& out) const;
LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto kind() const -> Kind { return kind_; }
auto source_loc() const -> SourceLocation { return source_loc_; }
// The static type of this expression. Cannot be called before typechecking.
auto static_type() const -> const Value& { return **static_type_; }
// Sets the static type of this expression. Can only be called once, during
// typechecking.
void set_static_type(Nonnull<const Value*> type) { static_type_ = type; }
// Returns whether the static type has been set. Should only be called
// during typechecking: before typechecking it's guaranteed to be false,
// and after typechecking it's guaranteed to be true.
auto has_static_type() const -> bool { return static_type_.has_value(); }
protected:
// Constructs an Expression representing syntax at the given line number.
// `kind` must be the enumerator corresponding to the most-derived type being
// constructed.
Expression(Kind kind, SourceLocation source_loc)
: kind_(kind), source_loc_(source_loc) {}
private:
const Kind kind_;
SourceLocation source_loc_;
std::optional<Nonnull<const Value*>> static_type_;
};
// Converts paren_contents to an Expression, interpreting the parentheses as
// grouping if their contents permit that interpretation, or as forming a
// tuple otherwise.
auto ExpressionFromParenContents(
Nonnull<Arena*> arena, SourceLocation source_loc,
const ParenContents<Expression>& paren_contents) -> Nonnull<Expression*>;
// Converts paren_contents to an Expression, interpreting the parentheses as
// forming a tuple.
auto TupleExpressionFromParenContents(
Nonnull<Arena*> arena, SourceLocation source_loc,
const ParenContents<Expression>& paren_contents) -> Nonnull<Expression*>;
// A FieldInitializer represents the initialization of a single struct field.
class FieldInitializer {
public:
FieldInitializer(std::string name, Nonnull<Expression*> expression)
: name_(std::move(name)), expression_(expression) {}
auto name() const -> const std::string& { return name_; }
auto expression() const -> const Expression& { return *expression_; }
auto expression() -> Expression& { return *expression_; }
private:
// The field name. Cannot be empty.
std::string name_;
// The expression that initializes the field.
Nonnull<Expression*> expression_;
};
enum class Operator {
Add,
And,
Deref,
Eq,
Mul,
Neg,
Not,
Or,
Sub,
Ptr,
};
class IdentifierExpression : public Expression {
public:
explicit IdentifierExpression(SourceLocation source_loc, std::string name)
: Expression(Kind::IdentifierExpression, source_loc),
name_(std::move(name)) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::IdentifierExpression;
}
auto name() const -> const std::string& { return name_; }
private:
std::string name_;
};
class FieldAccessExpression : public Expression {
public:
explicit FieldAccessExpression(SourceLocation source_loc,
Nonnull<Expression*> aggregate,
std::string field)
: Expression(Kind::FieldAccessExpression, source_loc),
aggregate_(aggregate),
field_(std::move(field)) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::FieldAccessExpression;
}
auto aggregate() const -> const Expression& { return *aggregate_; }
auto aggregate() -> Expression& { return *aggregate_; }
auto field() const -> const std::string& { return field_; }
private:
Nonnull<Expression*> aggregate_;
std::string field_;
};
class IndexExpression : public Expression {
public:
explicit IndexExpression(SourceLocation source_loc,
Nonnull<Expression*> aggregate,
Nonnull<Expression*> offset)
: Expression(Kind::IndexExpression, source_loc),
aggregate_(aggregate),
offset_(offset) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::IndexExpression;
}
auto aggregate() const -> const Expression& { return *aggregate_; }
auto aggregate() -> Expression& { return *aggregate_; }
auto offset() const -> const Expression& { return *offset_; }
auto offset() -> Expression& { return *offset_; }
private:
Nonnull<Expression*> aggregate_;
Nonnull<Expression*> offset_;
};
class IntLiteral : public Expression {
public:
explicit IntLiteral(SourceLocation source_loc, int value)
: Expression(Kind::IntLiteral, source_loc), value_(value) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::IntLiteral;
}
auto value() const -> int { return value_; }
private:
int value_;
};
class BoolLiteral : public Expression {
public:
explicit BoolLiteral(SourceLocation source_loc, bool value)
: Expression(Kind::BoolLiteral, source_loc), value_(value) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::BoolLiteral;
}
auto value() const -> bool { return value_; }
private:
bool value_;
};
class StringLiteral : public Expression {
public:
explicit StringLiteral(SourceLocation source_loc, std::string value)
: Expression(Kind::StringLiteral, source_loc), value_(std::move(value)) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::StringLiteral;
}
auto value() const -> const std::string& { return value_; }
private:
std::string value_;
};
class StringTypeLiteral : public Expression {
public:
explicit StringTypeLiteral(SourceLocation source_loc)
: Expression(Kind::StringTypeLiteral, source_loc) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::StringTypeLiteral;
}
};
class TupleLiteral : public Expression {
public:
explicit TupleLiteral(SourceLocation source_loc)
: TupleLiteral(source_loc, {}) {}
explicit TupleLiteral(SourceLocation source_loc,
std::vector<Nonnull<Expression*>> fields)
: Expression(Kind::TupleLiteral, source_loc),
fields_(std::move(fields)) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::TupleLiteral;
}
auto fields() const -> llvm::ArrayRef<Nonnull<const Expression*>> {
return fields_;
}
auto fields() -> llvm::ArrayRef<Nonnull<Expression*>> { return fields_; }
private:
std::vector<Nonnull<Expression*>> fields_;
};
// A non-empty literal value of a struct type.
//
// It can't be empty because the syntax `{}` is a struct type literal as well
// as a literal value of that type, so for consistency we always represent it
// as a StructTypeLiteral rather than let it oscillate unpredictably between
// the two.
class StructLiteral : public Expression {
public:
explicit StructLiteral(SourceLocation loc,
std::vector<FieldInitializer> fields)
: Expression(Kind::StructLiteral, loc), fields_(std::move(fields)) {
CHECK(!fields_.empty())
<< "`{}` is represented as a StructTypeLiteral, not a StructLiteral.";
}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::StructLiteral;
}
auto fields() const -> llvm::ArrayRef<FieldInitializer> { return fields_; }
auto fields() -> llvm::MutableArrayRef<FieldInitializer> { return fields_; }
private:
std::vector<FieldInitializer> fields_;
};
// A literal representing a struct type.
//
// Code that handles this type may sometimes need to have special-case handling
// for `{}`, which is a struct value in addition to being a struct type.
class StructTypeLiteral : public Expression {
public:
explicit StructTypeLiteral(SourceLocation loc) : StructTypeLiteral(loc, {}) {}
explicit StructTypeLiteral(SourceLocation loc,
std::vector<FieldInitializer> fields)
: Expression(Kind::StructTypeLiteral, loc), fields_(std::move(fields)) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::StructTypeLiteral;
}
auto fields() const -> llvm::ArrayRef<FieldInitializer> { return fields_; }
auto fields() -> llvm::MutableArrayRef<FieldInitializer> { return fields_; }
private:
std::vector<FieldInitializer> fields_;
};
class PrimitiveOperatorExpression : public Expression {
public:
explicit PrimitiveOperatorExpression(
SourceLocation source_loc, Operator op,
std::vector<Nonnull<Expression*>> arguments)
: Expression(Kind::PrimitiveOperatorExpression, source_loc),
op_(op),
arguments_(std::move(arguments)) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::PrimitiveOperatorExpression;
}
auto op() const -> Operator { return op_; }
auto arguments() const -> llvm::ArrayRef<Nonnull<Expression*>> {
return arguments_;
}
auto arguments() -> llvm::MutableArrayRef<Nonnull<Expression*>> {
return arguments_;
}
private:
Operator op_;
std::vector<Nonnull<Expression*>> arguments_;
};
class CallExpression : public Expression {
public:
explicit CallExpression(SourceLocation source_loc,
Nonnull<Expression*> function,
Nonnull<Expression*> argument)
: Expression(Kind::CallExpression, source_loc),
function_(function),
argument_(argument) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::CallExpression;
}
auto function() const -> const Expression& { return *function_; }
auto function() -> Expression& { return *function_; }
auto argument() const -> const Expression& { return *argument_; }
auto argument() -> Expression& { return *argument_; }
private:
Nonnull<Expression*> function_;
Nonnull<Expression*> argument_;
};
class FunctionTypeLiteral : public Expression {
public:
explicit FunctionTypeLiteral(SourceLocation source_loc,
Nonnull<Expression*> parameter,
Nonnull<Expression*> return_type,
bool is_omitted_return_type)
: Expression(Kind::FunctionTypeLiteral, source_loc),
parameter_(parameter),
return_type_(return_type),
is_omitted_return_type_(is_omitted_return_type) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::FunctionTypeLiteral;
}
auto parameter() const -> const Expression& { return *parameter_; }
auto parameter() -> Expression& { return *parameter_; }
auto return_type() const -> const Expression& { return *return_type_; }
auto return_type() -> Expression& { return *return_type_; }
auto is_omitted_return_type() const -> bool {
return is_omitted_return_type_;
}
private:
Nonnull<Expression*> parameter_;
Nonnull<Expression*> return_type_;
bool is_omitted_return_type_;
};
class BoolTypeLiteral : public Expression {
public:
explicit BoolTypeLiteral(SourceLocation source_loc)
: Expression(Kind::BoolTypeLiteral, source_loc) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::BoolTypeLiteral;
}
};
class IntTypeLiteral : public Expression {
public:
explicit IntTypeLiteral(SourceLocation source_loc)
: Expression(Kind::IntTypeLiteral, source_loc) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::IntTypeLiteral;
}
};
class ContinuationTypeLiteral : public Expression {
public:
explicit ContinuationTypeLiteral(SourceLocation source_loc)
: Expression(Kind::ContinuationTypeLiteral, source_loc) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::ContinuationTypeLiteral;
}
};
class TypeTypeLiteral : public Expression {
public:
explicit TypeTypeLiteral(SourceLocation source_loc)
: Expression(Kind::TypeTypeLiteral, source_loc) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::TypeTypeLiteral;
}
};
class IntrinsicExpression : public Expression {
public:
enum class Intrinsic {
Print,
};
explicit IntrinsicExpression(Intrinsic intrinsic)
: Expression(Kind::IntrinsicExpression, SourceLocation("<intrinsic>", 0)),
intrinsic_(intrinsic) {}
static auto classof(const Expression* exp) -> bool {
return exp->kind() == Kind::IntrinsicExpression;
}
auto intrinsic() const -> Intrinsic { return intrinsic_; }
private:
Intrinsic intrinsic_;
};
} // namespace Carbon
#endif // EXECUTABLE_SEMANTICS_AST_EXPRESSION_H_