mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-25 12:20:10 +01:00
Sorry about the big change, this is hard to split. ParenContents is used by both, templated, and expects the same pointer type. While I could duplicate ParenContents with some ExpressionParenContents or PatternParenContents, that seems a little kludgy versus a single large change handling both. The worst of it is that Expression is already pretty sweeping, Pattern is really just incrementally adding. That said, I believe this includes a couple fixes I found with incorrect use of dyn_cast in typecheck.cpp (checked nullptr at the wrong step in 2 code locations). There's also a missing `*` in member.cpp this caught. I adjust passing of expressions for Return due to nullness (I felt adding another constructor was the best solution). I add a `.Release()` to BisonWrap due to things like `$3.first` needing some way to work through BIsonWrap. I felt this was better than `operator->`, but feel free to comment if you prefer the other path (`.Release()` conveniently lets me do pair unwrapping, so it felt a better solution). I do add a TODO to think about better Ptr-to-Ptr cast<> support too, though, as that doesn't work cleanly with LLVM's infra. But so far it seems to only come up in one spot, so I'm not prioritizing it.
163 lines
4.7 KiB
C++
163 lines
4.7 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
|
|
|
|
#include "executable_semantics/ast/expression.h"
|
|
|
|
#include <optional>
|
|
|
|
#include "executable_semantics/common/arena.h"
|
|
#include "executable_semantics/common/error.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
namespace Carbon {
|
|
|
|
using llvm::cast;
|
|
|
|
auto ExpressionFromParenContents(
|
|
SourceLocation loc, const ParenContents<Expression>& paren_contents)
|
|
-> Ptr<const Expression> {
|
|
std::optional<Ptr<const Expression>> single_term =
|
|
paren_contents.SingleTerm();
|
|
if (single_term.has_value()) {
|
|
return *single_term;
|
|
} else {
|
|
return TupleExpressionFromParenContents(loc, paren_contents);
|
|
}
|
|
}
|
|
|
|
auto TupleExpressionFromParenContents(
|
|
SourceLocation loc, const ParenContents<Expression>& paren_contents)
|
|
-> Ptr<const Expression> {
|
|
return global_arena->New<TupleLiteral>(
|
|
loc, paren_contents.TupleElements<FieldInitializer>(loc));
|
|
}
|
|
|
|
static void PrintOp(llvm::raw_ostream& out, Operator op) {
|
|
switch (op) {
|
|
case Operator::Add:
|
|
out << "+";
|
|
break;
|
|
case Operator::Neg:
|
|
case Operator::Sub:
|
|
out << "-";
|
|
break;
|
|
case Operator::Mul:
|
|
case Operator::Deref:
|
|
case Operator::Ptr:
|
|
out << "*";
|
|
break;
|
|
case Operator::Not:
|
|
out << "not";
|
|
break;
|
|
case Operator::And:
|
|
out << "and";
|
|
break;
|
|
case Operator::Or:
|
|
out << "or";
|
|
break;
|
|
case Operator::Eq:
|
|
out << "==";
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void PrintFields(llvm::raw_ostream& out,
|
|
const std::vector<FieldInitializer>& fields) {
|
|
llvm::ListSeparator sep;
|
|
for (const auto& field : fields) {
|
|
out << sep << field.name << " = " << *field.expression;
|
|
}
|
|
}
|
|
|
|
void Expression::Print(llvm::raw_ostream& out) const {
|
|
switch (Tag()) {
|
|
case Expression::Kind::IndexExpression: {
|
|
const auto& index = cast<IndexExpression>(*this);
|
|
out << *index.Aggregate() << "[" << *index.Offset() << "]";
|
|
break;
|
|
}
|
|
case Expression::Kind::FieldAccessExpression: {
|
|
const auto& access = cast<FieldAccessExpression>(*this);
|
|
out << *access.Aggregate() << "." << access.Field();
|
|
break;
|
|
}
|
|
case Expression::Kind::TupleLiteral:
|
|
out << "(";
|
|
PrintFields(out, cast<TupleLiteral>(*this).Fields());
|
|
out << ")";
|
|
break;
|
|
case Expression::Kind::IntLiteral:
|
|
out << cast<IntLiteral>(*this).Val();
|
|
break;
|
|
case Expression::Kind::BoolLiteral:
|
|
out << (cast<BoolLiteral>(*this).Val() ? "true" : "false");
|
|
break;
|
|
case Expression::Kind::PrimitiveOperatorExpression: {
|
|
out << "(";
|
|
PrimitiveOperatorExpression op = cast<PrimitiveOperatorExpression>(*this);
|
|
if (op.Arguments().size() == 0) {
|
|
PrintOp(out, op.Op());
|
|
} else if (op.Arguments().size() == 1) {
|
|
PrintOp(out, op.Op());
|
|
out << " " << *op.Arguments()[0];
|
|
} else if (op.Arguments().size() == 2) {
|
|
out << *op.Arguments()[0] << " ";
|
|
PrintOp(out, op.Op());
|
|
out << " " << *op.Arguments()[1];
|
|
}
|
|
out << ")";
|
|
break;
|
|
}
|
|
case Expression::Kind::IdentifierExpression:
|
|
out << cast<IdentifierExpression>(*this).Name();
|
|
break;
|
|
case Expression::Kind::CallExpression: {
|
|
const auto& call = cast<CallExpression>(*this);
|
|
out << *call.Function();
|
|
if (call.Argument()->Tag() == Expression::Kind::TupleLiteral) {
|
|
out << *call.Argument();
|
|
} else {
|
|
out << "(" << *call.Argument() << ")";
|
|
}
|
|
break;
|
|
}
|
|
case Expression::Kind::BoolTypeLiteral:
|
|
out << "Bool";
|
|
break;
|
|
case Expression::Kind::IntTypeLiteral:
|
|
out << "i32";
|
|
break;
|
|
case Expression::Kind::StringLiteral:
|
|
out << "\"";
|
|
out.write_escaped(cast<StringLiteral>(*this).Val());
|
|
out << "\"";
|
|
break;
|
|
case Expression::Kind::StringTypeLiteral:
|
|
out << "String";
|
|
break;
|
|
case Expression::Kind::TypeTypeLiteral:
|
|
out << "Type";
|
|
break;
|
|
case Expression::Kind::ContinuationTypeLiteral:
|
|
out << "Continuation";
|
|
break;
|
|
case Expression::Kind::FunctionTypeLiteral: {
|
|
const auto& fn = cast<FunctionTypeLiteral>(*this);
|
|
out << "fn " << *fn.Parameter() << " -> " << *fn.ReturnType();
|
|
break;
|
|
}
|
|
case Expression::Kind::IntrinsicExpression:
|
|
out << "intrinsic_expression(";
|
|
switch (cast<IntrinsicExpression>(*this).Intrinsic()) {
|
|
case IntrinsicExpression::IntrinsicKind::Print:
|
|
out << "print";
|
|
}
|
|
out << ")";
|
|
}
|
|
}
|
|
|
|
} // namespace Carbon
|