mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 18:40:16 +01:00
Add support for compound assignment and increment (#2526)
Add support for user-defined assignment, as well as compound assignment and increment, following the design direction in pending proposal #2511. Some of this isn't fully testable yet: because explorer doesn't properly support `impl` specialization, the blanket `impl`s in the prelude prevent types from customizing assignment.
This commit is contained in:
@@ -241,8 +241,27 @@ message ExpressionStatement {
|
||||
}
|
||||
|
||||
message AssignStatement {
|
||||
enum Operator {
|
||||
Plain = 0;
|
||||
Add = 1;
|
||||
And = 2;
|
||||
Div = 3;
|
||||
Mul = 4;
|
||||
Or = 5;
|
||||
Sub = 6;
|
||||
Mod = 7;
|
||||
Xor = 8;
|
||||
ShiftLeft = 9;
|
||||
ShiftRight = 10;
|
||||
}
|
||||
optional Expression lhs = 1;
|
||||
optional Expression rhs = 2;
|
||||
optional Operator op = 3;
|
||||
}
|
||||
|
||||
message IncrementDecrementStatement {
|
||||
optional Expression operand = 1;
|
||||
optional bool is_increment = 2;
|
||||
}
|
||||
|
||||
message VariableDefinitionStatement {
|
||||
@@ -321,6 +340,7 @@ message Statement {
|
||||
BreakStatement break_statement = 13;
|
||||
ContinueStatement continue_statement = 14;
|
||||
ForStatement for_statement = 15;
|
||||
IncrementDecrementStatement inc_dec = 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -534,12 +534,54 @@ static auto StatementToCarbon(const Fuzzing::Statement& statement,
|
||||
case Fuzzing::Statement::kAssign: {
|
||||
const auto& assign_statement = statement.assign();
|
||||
ExpressionToCarbon(assign_statement.lhs(), out);
|
||||
out << " = ";
|
||||
switch (assign_statement.op()) {
|
||||
case Fuzzing::AssignStatement::Plain:
|
||||
out << " = ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Add:
|
||||
out << " += ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::And:
|
||||
out << " &= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Div:
|
||||
out << " /= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Mod:
|
||||
out << " %= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Mul:
|
||||
out << " *= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Or:
|
||||
out << " |= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::ShiftLeft:
|
||||
out << " <<= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::ShiftRight:
|
||||
out << " >>= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Sub:
|
||||
out << " -= ";
|
||||
break;
|
||||
case Fuzzing::AssignStatement::Xor:
|
||||
out << " ^= ";
|
||||
break;
|
||||
}
|
||||
ExpressionToCarbon(assign_statement.rhs(), out);
|
||||
out << ";";
|
||||
break;
|
||||
}
|
||||
|
||||
case Fuzzing::Statement::kIncDec: {
|
||||
const auto& inc_dec_statement = statement.inc_dec();
|
||||
out << (inc_dec_statement.is_increment() ? "++" : "--");
|
||||
ExpressionToCarbon(inc_dec_statement.operand(), out);
|
||||
out << ";";
|
||||
break;
|
||||
}
|
||||
|
||||
case Fuzzing::Statement::kVariableDefinition: {
|
||||
const auto& def = statement.variable_definition();
|
||||
if (def.is_returned()) {
|
||||
|
||||
@@ -36,6 +36,7 @@ class AlternativeSignature : AstNode;
|
||||
abstract class Statement : AstNode;
|
||||
class ExpressionStatement : Statement;
|
||||
class Assign : Statement;
|
||||
class IncrementDecrement : Statement;
|
||||
class VariableDefinition : Statement;
|
||||
class If : Statement;
|
||||
abstract class Return : Statement;
|
||||
|
||||
@@ -72,7 +72,13 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
break;
|
||||
case StatementKind::Assign: {
|
||||
const auto& assign = cast<Assign>(*this);
|
||||
out << assign.lhs() << " = " << assign.rhs() << ";";
|
||||
out << assign.lhs() << " " << AssignOperatorToString(assign.op()) << " "
|
||||
<< assign.rhs() << ";";
|
||||
break;
|
||||
}
|
||||
case StatementKind::IncrementDecrement: {
|
||||
const auto& inc_dec = cast<IncrementDecrement>(*this);
|
||||
out << (inc_dec.is_increment() ? "++" : "--") << inc_dec.argument();
|
||||
break;
|
||||
}
|
||||
case StatementKind::If: {
|
||||
@@ -137,4 +143,31 @@ void Statement::PrintDepth(int depth, llvm::raw_ostream& out) const {
|
||||
}
|
||||
}
|
||||
|
||||
auto AssignOperatorToString(AssignOperator op) -> std::string_view {
|
||||
switch (op) {
|
||||
case AssignOperator::Plain:
|
||||
return "=";
|
||||
case AssignOperator::Add:
|
||||
return "+=";
|
||||
case AssignOperator::Div:
|
||||
return "/=";
|
||||
case AssignOperator::Mul:
|
||||
return "*=";
|
||||
case AssignOperator::Mod:
|
||||
return "%=";
|
||||
case AssignOperator::Sub:
|
||||
return "-=";
|
||||
case AssignOperator::And:
|
||||
return "&=";
|
||||
case AssignOperator::Or:
|
||||
return "|=";
|
||||
case AssignOperator::Xor:
|
||||
return "^=";
|
||||
case AssignOperator::ShiftLeft:
|
||||
return "<<=";
|
||||
case AssignOperator::ShiftRight:
|
||||
return ">>=";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -86,11 +86,31 @@ class ExpressionStatement : public Statement {
|
||||
Nonnull<Expression*> expression_;
|
||||
};
|
||||
|
||||
enum class AssignOperator {
|
||||
Plain,
|
||||
Add,
|
||||
Div,
|
||||
Mul,
|
||||
Mod,
|
||||
Sub,
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
ShiftLeft,
|
||||
ShiftRight,
|
||||
};
|
||||
|
||||
// Returns the spelling of this assignment operator token.
|
||||
auto AssignOperatorToString(AssignOperator op) -> std::string_view;
|
||||
|
||||
class Assign : public Statement {
|
||||
public:
|
||||
Assign(SourceLocation source_loc, Nonnull<Expression*> lhs,
|
||||
Assign(SourceLocation source_loc, Nonnull<Expression*> lhs, AssignOperator op,
|
||||
Nonnull<Expression*> rhs)
|
||||
: Statement(AstNodeKind::Assign, source_loc), lhs_(lhs), rhs_(rhs) {}
|
||||
: Statement(AstNodeKind::Assign, source_loc),
|
||||
lhs_(lhs),
|
||||
rhs_(rhs),
|
||||
op_(op) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromAssign(node->kind());
|
||||
@@ -101,12 +121,66 @@ class Assign : public Statement {
|
||||
auto rhs() const -> const Expression& { return *rhs_; }
|
||||
auto rhs() -> Expression& { return *rhs_; }
|
||||
|
||||
auto op() const -> AssignOperator { return op_; }
|
||||
|
||||
// Can only be called by type-checking, if a conversion was required.
|
||||
void set_rhs(Nonnull<Expression*> rhs) { rhs_ = rhs; }
|
||||
|
||||
// Set the rewritten form of this statement. Can only be called during type
|
||||
// checking.
|
||||
auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
|
||||
CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice";
|
||||
rewritten_form_ = rewritten_form;
|
||||
}
|
||||
|
||||
// Get the rewritten form of this statement. A rewritten form is used when
|
||||
// the statement is rewritten as a function call on an interface. A
|
||||
// rewritten form is not used when providing built-in operator semantics for
|
||||
// a plain assignment.
|
||||
auto rewritten_form() const -> std::optional<Nonnull<const Expression*>> {
|
||||
return rewritten_form_;
|
||||
}
|
||||
|
||||
private:
|
||||
Nonnull<Expression*> lhs_;
|
||||
Nonnull<Expression*> rhs_;
|
||||
AssignOperator op_;
|
||||
std::optional<Nonnull<const Expression*>> rewritten_form_;
|
||||
};
|
||||
|
||||
class IncrementDecrement : public Statement {
|
||||
public:
|
||||
IncrementDecrement(SourceLocation source_loc, Nonnull<Expression*> argument,
|
||||
bool is_increment)
|
||||
: Statement(AstNodeKind::IncrementDecrement, source_loc),
|
||||
argument_(argument),
|
||||
is_increment_(is_increment) {}
|
||||
|
||||
static auto classof(const AstNode* node) -> bool {
|
||||
return InheritsFromIncrementDecrement(node->kind());
|
||||
}
|
||||
|
||||
auto argument() const -> const Expression& { return *argument_; }
|
||||
auto argument() -> Expression& { return *argument_; }
|
||||
|
||||
bool is_increment() const { return is_increment_; }
|
||||
|
||||
// Set the rewritten form of this statement. Can only be called during type
|
||||
// checking.
|
||||
auto set_rewritten_form(Nonnull<const Expression*> rewritten_form) -> void {
|
||||
CARBON_CHECK(!rewritten_form_.has_value()) << "rewritten form set twice";
|
||||
rewritten_form_ = rewritten_form;
|
||||
}
|
||||
|
||||
// Get the rewritten form of this statement.
|
||||
auto rewritten_form() const -> std::optional<Nonnull<const Expression*>> {
|
||||
return rewritten_form_;
|
||||
}
|
||||
|
||||
private:
|
||||
Nonnull<Expression*> argument_;
|
||||
bool is_increment_;
|
||||
std::optional<Nonnull<const Expression*>> rewritten_form_;
|
||||
};
|
||||
|
||||
class VariableDefinition : public Statement {
|
||||
|
||||
@@ -501,6 +501,168 @@ external impl i32 as RightShiftWith(i32) where .Result = i32 {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
// Assignment and compound assignment.
|
||||
// -----------------------------------
|
||||
|
||||
interface AssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint Assign { extends AssignWith(Self); }
|
||||
|
||||
interface AddAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint AddAssign { extends AddAssignWith(Self); }
|
||||
|
||||
interface SubAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint SubAssign { extends SubAssignWith(Self); }
|
||||
|
||||
interface MulAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint MulAssign { extends MulAssignWith(Self); }
|
||||
|
||||
interface DivAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint DivAssign { extends DivAssignWith(Self); }
|
||||
|
||||
interface ModAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint ModAssign { extends ModAssignWith(Self); }
|
||||
|
||||
interface BitAndAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint BitAssignAnd { extends BitAndAssignWith(Self); }
|
||||
|
||||
interface BitOrAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint BitAssignOr { extends BitOrAssignWith(Self); }
|
||||
|
||||
interface BitXorAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint BitAssignXor { extends BitXorAssignWith(Self); }
|
||||
|
||||
interface LeftShiftAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint LeftShiftAssign { extends LeftShiftAssignWith(Self); }
|
||||
|
||||
interface RightShiftAssignWith(U:! type) {
|
||||
fn Op[addr self: Self*](other: U);
|
||||
}
|
||||
constraint RightShiftAssign { extends RightShiftAssignWith(Self); }
|
||||
|
||||
// TODO: This is temporary, and should eventually be replaced by
|
||||
// something more fine-grained. Not all class types should be
|
||||
// assignable.
|
||||
impl forall [T:! type, U:! ImplicitAs(T)]
|
||||
T as AssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = other.Convert();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should `AddWith(U) & AssignWith(.Self.(AddWith(U).Result))` work?
|
||||
impl forall [U:! type, T:! AddWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as AddAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! SubWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as SubAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self - other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! MulWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as MulAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self * other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! DivWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as DivAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self / other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! ModWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as ModAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self % other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! BitAndWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as BitAndAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self & other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! BitOrWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as BitOrAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self | other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! BitXorWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as BitXorAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self ^ other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! LeftShiftWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as LeftShiftAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self << other;
|
||||
}
|
||||
}
|
||||
|
||||
impl forall [U:! type, T:! RightShiftWith(U) where .Self is AssignWith(.Self.Result)]
|
||||
T as RightShiftAssignWith(U) {
|
||||
fn Op[addr self: Self*](other: U) {
|
||||
*self = *self >> other;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------
|
||||
// Increment and decrement.
|
||||
// ------------------------
|
||||
|
||||
interface Inc {
|
||||
fn Op[addr self: Self*]();
|
||||
}
|
||||
interface Dec {
|
||||
fn Op[addr self: Self*]();
|
||||
}
|
||||
|
||||
impl i32 as Inc {
|
||||
fn Op[addr self: Self*]() {
|
||||
*self = *self + 1;
|
||||
}
|
||||
}
|
||||
impl i32 as Dec {
|
||||
fn Op[addr self: Self*]() {
|
||||
*self = *self - 1;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------
|
||||
// Optional
|
||||
//-------------------------
|
||||
|
||||
@@ -89,6 +89,34 @@ static auto OperatorToProtoEnum(const Operator op)
|
||||
}
|
||||
}
|
||||
|
||||
static auto AssignOperatorToProtoEnum(const AssignOperator op)
|
||||
-> Fuzzing::AssignStatement::Operator {
|
||||
switch (op) {
|
||||
case AssignOperator::Plain:
|
||||
return Fuzzing::AssignStatement::Plain;
|
||||
case AssignOperator::Add:
|
||||
return Fuzzing::AssignStatement::Add;
|
||||
case AssignOperator::And:
|
||||
return Fuzzing::AssignStatement::And;
|
||||
case AssignOperator::Mul:
|
||||
return Fuzzing::AssignStatement::Mul;
|
||||
case AssignOperator::Div:
|
||||
return Fuzzing::AssignStatement::Div;
|
||||
case AssignOperator::Mod:
|
||||
return Fuzzing::AssignStatement::Mod;
|
||||
case AssignOperator::Or:
|
||||
return Fuzzing::AssignStatement::Or;
|
||||
case AssignOperator::ShiftLeft:
|
||||
return Fuzzing::AssignStatement::ShiftLeft;
|
||||
case AssignOperator::ShiftRight:
|
||||
return Fuzzing::AssignStatement::ShiftRight;
|
||||
case AssignOperator::Sub:
|
||||
return Fuzzing::AssignStatement::Sub;
|
||||
case AssignOperator::Xor:
|
||||
return Fuzzing::AssignStatement::Xor;
|
||||
}
|
||||
}
|
||||
|
||||
static auto FieldInitializerToProto(const FieldInitializer& field)
|
||||
-> Fuzzing::FieldInitializer {
|
||||
Fuzzing::FieldInitializer field_proto;
|
||||
@@ -435,6 +463,15 @@ static auto StatementToProto(const Statement& statement) -> Fuzzing::Statement {
|
||||
auto* assign_proto = statement_proto.mutable_assign();
|
||||
*assign_proto->mutable_lhs() = ExpressionToProto(assign.lhs());
|
||||
*assign_proto->mutable_rhs() = ExpressionToProto(assign.rhs());
|
||||
assign_proto->set_op(AssignOperatorToProtoEnum(assign.op()));
|
||||
break;
|
||||
}
|
||||
|
||||
case StatementKind::IncrementDecrement: {
|
||||
const auto& inc_dec = cast<IncrementDecrement>(statement);
|
||||
auto* inc_dec_proto = statement_proto.mutable_inc_dec();
|
||||
*inc_dec_proto->mutable_operand() = ExpressionToProto(inc_dec.argument());
|
||||
inc_dec_proto->set_is_increment(inc_dec.is_increment());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,26 @@ class Builtins {
|
||||
LeftShiftWith,
|
||||
RightShiftWith,
|
||||
|
||||
Last = RightShiftWith
|
||||
// Simple assignment.
|
||||
AssignWith,
|
||||
|
||||
// Compound assignment.
|
||||
AddAssignWith,
|
||||
SubAssignWith,
|
||||
MulAssignWith,
|
||||
DivAssignWith,
|
||||
ModAssignWith,
|
||||
BitAndAssignWith,
|
||||
BitOrAssignWith,
|
||||
BitXorAssignWith,
|
||||
LeftShiftAssignWith,
|
||||
RightShiftAssignWith,
|
||||
|
||||
// Increment and decrement.
|
||||
Inc,
|
||||
Dec,
|
||||
|
||||
Last = Dec
|
||||
};
|
||||
// TODO: In C++20, replace with `using enum Builtin;`.
|
||||
static constexpr Builtin As = Builtin::As;
|
||||
@@ -61,6 +80,7 @@ class Builtins {
|
||||
static constexpr Builtin LessEqWith = Builtin::LessEqWith;
|
||||
static constexpr Builtin GreaterWith = Builtin::GreaterWith;
|
||||
static constexpr Builtin GreaterEqWith = Builtin::GreaterEqWith;
|
||||
static constexpr Builtin CompareWith = Builtin::CompareWith;
|
||||
static constexpr Builtin Negate = Builtin::Negate;
|
||||
static constexpr Builtin AddWith = Builtin::AddWith;
|
||||
static constexpr Builtin SubWith = Builtin::SubWith;
|
||||
@@ -73,7 +93,19 @@ class Builtins {
|
||||
static constexpr Builtin BitXorWith = Builtin::BitXorWith;
|
||||
static constexpr Builtin LeftShiftWith = Builtin::LeftShiftWith;
|
||||
static constexpr Builtin RightShiftWith = Builtin::RightShiftWith;
|
||||
static constexpr Builtin CompareWith = Builtin::CompareWith;
|
||||
static constexpr Builtin AssignWith = Builtin::AssignWith;
|
||||
static constexpr Builtin AddAssignWith = Builtin::AddAssignWith;
|
||||
static constexpr Builtin SubAssignWith = Builtin::SubAssignWith;
|
||||
static constexpr Builtin MulAssignWith = Builtin::MulAssignWith;
|
||||
static constexpr Builtin DivAssignWith = Builtin::DivAssignWith;
|
||||
static constexpr Builtin ModAssignWith = Builtin::ModAssignWith;
|
||||
static constexpr Builtin BitAndAssignWith = Builtin::BitAndAssignWith;
|
||||
static constexpr Builtin BitOrAssignWith = Builtin::BitOrAssignWith;
|
||||
static constexpr Builtin BitXorAssignWith = Builtin::BitXorAssignWith;
|
||||
static constexpr Builtin LeftShiftAssignWith = Builtin::LeftShiftAssignWith;
|
||||
static constexpr Builtin RightShiftAssignWith = Builtin::RightShiftAssignWith;
|
||||
static constexpr Builtin Inc = Builtin::Inc;
|
||||
static constexpr Builtin Dec = Builtin::Dec;
|
||||
|
||||
// Register a declaration that might be a builtin.
|
||||
void Register(Nonnull<const Declaration*> decl);
|
||||
@@ -90,11 +122,39 @@ class Builtins {
|
||||
private:
|
||||
static constexpr int NumBuiltins = static_cast<int>(Builtin::Last) + 1;
|
||||
static constexpr const char* BuiltinNames[NumBuiltins] = {
|
||||
"As", "ImplicitAs", "EqWith", "LessWith",
|
||||
"LessEqWith", "GreaterWith", "GreaterEqWith", "CompareWith",
|
||||
"Negate", "AddWith", "SubWith", "MulWith",
|
||||
"DivWith", "ModWith", "BitComplement", "BitAndWith",
|
||||
"BitOrWith", "BitXorWith", "LeftShiftWith", "RightShiftWith"};
|
||||
"As",
|
||||
"ImplicitAs",
|
||||
"EqWith",
|
||||
"LessWith",
|
||||
"LessEqWith",
|
||||
"GreaterWith",
|
||||
"GreaterEqWith",
|
||||
"CompareWith",
|
||||
"Negate",
|
||||
"AddWith",
|
||||
"SubWith",
|
||||
"MulWith",
|
||||
"DivWith",
|
||||
"ModWith",
|
||||
"BitComplement",
|
||||
"BitAndWith",
|
||||
"BitOrWith",
|
||||
"BitXorWith",
|
||||
"LeftShiftWith",
|
||||
"RightShiftWith",
|
||||
"AssignWith",
|
||||
"AddAssignWith",
|
||||
"SubAssignWith",
|
||||
"MulAssignWith",
|
||||
"DivAssignWith",
|
||||
"ModAssignWith",
|
||||
"BitAndAssignWith",
|
||||
"BitOrAssignWith",
|
||||
"BitXorAssignWith",
|
||||
"LeftShiftAssignWith",
|
||||
"RightShiftAssignWith",
|
||||
"Inc",
|
||||
"Dec"};
|
||||
|
||||
std::optional<Nonnull<const Declaration*>> builtins_[NumBuiltins] = {};
|
||||
};
|
||||
|
||||
@@ -1937,6 +1937,13 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
|
||||
}
|
||||
case StatementKind::Assign: {
|
||||
const auto& assign = cast<Assign>(stmt);
|
||||
if (auto rewrite = assign.rewritten_form()) {
|
||||
if (act.pos() == 0) {
|
||||
return todo_.Spawn(std::make_unique<ExpressionAction>(*rewrite));
|
||||
} else {
|
||||
return todo_.FinishAction();
|
||||
}
|
||||
}
|
||||
if (act.pos() == 0) {
|
||||
// { {(lv = e) :: C, E, F} :: S, H}
|
||||
// -> { {lv :: ([] = e) :: C, E, F} :: S, H}
|
||||
@@ -1958,6 +1965,15 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
|
||||
return todo_.FinishAction();
|
||||
}
|
||||
}
|
||||
case StatementKind::IncrementDecrement: {
|
||||
const auto& inc_dec = cast<IncrementDecrement>(stmt);
|
||||
if (act.pos() == 0) {
|
||||
return todo_.Spawn(
|
||||
std::make_unique<ExpressionAction>(*inc_dec.rewritten_form()));
|
||||
} else {
|
||||
return todo_.FinishAction();
|
||||
}
|
||||
}
|
||||
case StatementKind::If:
|
||||
if (act.pos() == 0) {
|
||||
// { {(if (e) then_stmt else else_stmt) :: C, E, F} :: S, H}
|
||||
|
||||
@@ -130,6 +130,7 @@ static auto ResolveControlFlow(Nonnull<Statement*> statement,
|
||||
return Success();
|
||||
case StatementKind::ExpressionStatement:
|
||||
case StatementKind::Assign:
|
||||
case StatementKind::IncrementDecrement:
|
||||
case StatementKind::VariableDefinition:
|
||||
case StatementKind::Run:
|
||||
case StatementKind::Await:
|
||||
|
||||
@@ -380,6 +380,11 @@ static auto ResolveNames(Statement& statement, StaticScope& enclosing_scope)
|
||||
CARBON_RETURN_IF_ERROR(ResolveNames(assign.rhs(), enclosing_scope));
|
||||
break;
|
||||
}
|
||||
case StatementKind::IncrementDecrement: {
|
||||
auto& inc_dec = cast<IncrementDecrement>(statement);
|
||||
CARBON_RETURN_IF_ERROR(ResolveNames(inc_dec.argument(), enclosing_scope));
|
||||
break;
|
||||
}
|
||||
case StatementKind::VariableDefinition: {
|
||||
auto& def = cast<VariableDefinition>(statement);
|
||||
if (def.has_init()) {
|
||||
|
||||
@@ -222,7 +222,10 @@ static auto ResolveUnformed(Nonnull<const Statement*> statement,
|
||||
}
|
||||
case StatementKind::Assign: {
|
||||
const auto& assign = cast<Assign>(*statement);
|
||||
if (assign.lhs().kind() == ExpressionKind::IdentifierExpression) {
|
||||
if (assign.op() != AssignOperator::Plain) {
|
||||
CARBON_RETURN_IF_ERROR(ResolveUnformed(&assign.lhs(), flow_facts,
|
||||
FlowFacts::ActionType::Check));
|
||||
} else if (assign.lhs().kind() == ExpressionKind::IdentifierExpression) {
|
||||
CARBON_RETURN_IF_ERROR(ResolveUnformed(&assign.lhs(), flow_facts,
|
||||
FlowFacts::ActionType::Form));
|
||||
} else {
|
||||
@@ -234,6 +237,12 @@ static auto ResolveUnformed(Nonnull<const Statement*> statement,
|
||||
FlowFacts::ActionType::Check));
|
||||
break;
|
||||
}
|
||||
case StatementKind::IncrementDecrement: {
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
ResolveUnformed(&cast<IncrementDecrement>(statement)->argument(),
|
||||
flow_facts, FlowFacts::ActionType::Check));
|
||||
break;
|
||||
}
|
||||
case StatementKind::ExpressionStatement: {
|
||||
const auto& exp_stmt = cast<ExpressionStatement>(*statement);
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
|
||||
@@ -4090,6 +4090,36 @@ auto TypeChecker::TypeCheckGenericBinding(GenericBinding& binding,
|
||||
return Success();
|
||||
}
|
||||
|
||||
// Get the builtin interface that should be used for the given kind of
|
||||
// assignment operator.
|
||||
static Builtins::Builtin GetBuiltinInterfaceForAssignOperator(
|
||||
AssignOperator op) {
|
||||
switch (op) {
|
||||
case AssignOperator::Plain:
|
||||
return Builtins::AssignWith;
|
||||
case AssignOperator::Add:
|
||||
return Builtins::AddAssignWith;
|
||||
case AssignOperator::Sub:
|
||||
return Builtins::SubAssignWith;
|
||||
case AssignOperator::Mul:
|
||||
return Builtins::MulAssignWith;
|
||||
case AssignOperator::Div:
|
||||
return Builtins::DivAssignWith;
|
||||
case AssignOperator::Mod:
|
||||
return Builtins::ModAssignWith;
|
||||
case AssignOperator::And:
|
||||
return Builtins::BitAndAssignWith;
|
||||
case AssignOperator::Or:
|
||||
return Builtins::BitOrAssignWith;
|
||||
case AssignOperator::Xor:
|
||||
return Builtins::BitXorAssignWith;
|
||||
case AssignOperator::ShiftLeft:
|
||||
return Builtins::LeftShiftAssignWith;
|
||||
case AssignOperator::ShiftRight:
|
||||
return Builtins::RightShiftAssignWith;
|
||||
}
|
||||
}
|
||||
|
||||
auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
|
||||
const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
@@ -4232,11 +4262,38 @@ auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
|
||||
return ProgramError(assign.source_loc())
|
||||
<< "Cannot assign to rvalue '" << assign.lhs() << "'";
|
||||
}
|
||||
if (assign.op() == AssignOperator::Plain &&
|
||||
IsSameType(&assign.lhs().static_type(), &assign.rhs().static_type(),
|
||||
impl_scope)) {
|
||||
// TODO: Interface lookup.
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<Expression*> converted_rhs,
|
||||
ImplicitlyConvert("assignment", impl_scope, &assign.rhs(),
|
||||
&assign.lhs().static_type()));
|
||||
assign.set_rhs(converted_rhs);
|
||||
} else {
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<Expression*> rewritten,
|
||||
BuildBuiltinMethodCall(
|
||||
impl_scope, &assign.lhs(),
|
||||
BuiltinInterfaceName{
|
||||
GetBuiltinInterfaceForAssignOperator(assign.op()),
|
||||
{&assign.rhs().static_type()}},
|
||||
BuiltinMethodCall{"Op", {&assign.rhs()}}));
|
||||
assign.set_rewritten_form(rewritten);
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
case StatementKind::IncrementDecrement: {
|
||||
auto& inc_dec = cast<IncrementDecrement>(*s);
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<Expression*> converted_rhs,
|
||||
ImplicitlyConvert("assignment", impl_scope, &assign.rhs(),
|
||||
&assign.lhs().static_type()));
|
||||
assign.set_rhs(converted_rhs);
|
||||
Nonnull<Expression*> rewritten,
|
||||
BuildBuiltinMethodCall(
|
||||
impl_scope, &inc_dec.argument(),
|
||||
BuiltinInterfaceName{
|
||||
inc_dec.is_increment() ? Builtins::Inc : Builtins::Dec, {}},
|
||||
BuiltinMethodCall{"Op"}));
|
||||
inc_dec.set_rewritten_form(rewritten);
|
||||
return Success();
|
||||
}
|
||||
case StatementKind::ExpressionStatement: {
|
||||
@@ -4380,6 +4437,7 @@ auto TypeChecker::ExpectReturnOnAllPaths(
|
||||
case StatementKind::Run:
|
||||
case StatementKind::Await:
|
||||
case StatementKind::Assign:
|
||||
case StatementKind::IncrementDecrement:
|
||||
case StatementKind::ExpressionStatement:
|
||||
case StatementKind::While:
|
||||
case StatementKind::For:
|
||||
|
||||
+193
-169
@@ -31,92 +31,104 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
%s AFTER_OPERAND
|
||||
|
||||
/* table-begin */
|
||||
ABSTRACT "abstract"
|
||||
ADDR "addr"
|
||||
ALIAS "alias"
|
||||
AMPERSAND "&"
|
||||
AND "and"
|
||||
API "api"
|
||||
ARROW "->"
|
||||
AS "as"
|
||||
AUTO "auto"
|
||||
AWAIT "__await"
|
||||
BASE "base"
|
||||
BOOL "bool"
|
||||
BREAK "break"
|
||||
CARET "^"
|
||||
CASE "case"
|
||||
CHOICE "choice"
|
||||
CLASS "class"
|
||||
COLON ":"
|
||||
COLON_BANG ":!"
|
||||
COMMA ","
|
||||
CONSTRAINT "constraint"
|
||||
CONTINUATION "__continuation"
|
||||
CONTINUATION_TYPE "__Continuation"
|
||||
CONTINUE "continue"
|
||||
DEFAULT "default"
|
||||
DESTRUCTOR "destructor"
|
||||
DOUBLE_ARROW "=>"
|
||||
ELSE "else"
|
||||
EQUAL "="
|
||||
EQUAL_EQUAL "=="
|
||||
EXTENDS "extends"
|
||||
EXTERNAL "external"
|
||||
FALSE "false"
|
||||
FN "fn"
|
||||
FN_TYPE "__Fn"
|
||||
FOR "for"
|
||||
FORALL "forall"
|
||||
GREATER ">"
|
||||
GREATER_EQUAL ">="
|
||||
GREATER_GREATER ">>"
|
||||
IF "if"
|
||||
IMPL "impl"
|
||||
IMPORT "import"
|
||||
IN "in"
|
||||
INTERFACE "interface"
|
||||
IS "is"
|
||||
LEFT_CURLY_BRACE "{"
|
||||
LEFT_PARENTHESIS "("
|
||||
LEFT_SQUARE_BRACKET "["
|
||||
LESS "<"
|
||||
LESS_EQUAL "<="
|
||||
LESS_LESS "<<"
|
||||
LET "let"
|
||||
LIBRARY "library"
|
||||
MATCH "match"
|
||||
MATCH_FIRST "__match_first"
|
||||
MINUS "-"
|
||||
MIX "__mix"
|
||||
MIXIN "__mixin"
|
||||
NOT "not"
|
||||
NOT_EQUAL "!="
|
||||
OR "or"
|
||||
PACKAGE "package"
|
||||
PERCENT "%"
|
||||
PERIOD "."
|
||||
PIPE "|"
|
||||
PLUS "+"
|
||||
RETURN "return"
|
||||
RETURNED "returned"
|
||||
RIGHT_CURLY_BRACE "}"
|
||||
RIGHT_PARENTHESIS ")"
|
||||
RIGHT_SQUARE_BRACKET "]"
|
||||
RUN "__run"
|
||||
SELF "Self"
|
||||
SEMICOLON ";"
|
||||
SLASH "/"
|
||||
STRING "String"
|
||||
THEN "then"
|
||||
TRUE "true"
|
||||
TYPE "type"
|
||||
UNDERSCORE "_"
|
||||
UNIMPL_EXAMPLE "__unimplemented_example_infix"
|
||||
VAR "var"
|
||||
VIRTUAL "virtual"
|
||||
WHERE "where"
|
||||
WHILE "while"
|
||||
ABSTRACT "abstract"
|
||||
ADDR "addr"
|
||||
ALIAS "alias"
|
||||
AMPERSAND "&"
|
||||
AMPERSAND_EQUAL "&="
|
||||
AND "and"
|
||||
API "api"
|
||||
ARROW "->"
|
||||
AS "as"
|
||||
AUTO "auto"
|
||||
AWAIT "__await"
|
||||
BASE "base"
|
||||
BOOL "bool"
|
||||
BREAK "break"
|
||||
CARET "^"
|
||||
CARET_EQUAL "^="
|
||||
CASE "case"
|
||||
CHOICE "choice"
|
||||
CLASS "class"
|
||||
COLON ":"
|
||||
COLON_BANG ":!"
|
||||
COMMA ","
|
||||
CONSTRAINT "constraint"
|
||||
CONTINUATION "__continuation"
|
||||
CONTINUATION_TYPE "__Continuation"
|
||||
CONTINUE "continue"
|
||||
DEFAULT "default"
|
||||
DESTRUCTOR "destructor"
|
||||
DOUBLE_ARROW "=>"
|
||||
ELSE "else"
|
||||
EQUAL "="
|
||||
EQUAL_EQUAL "=="
|
||||
EXTENDS "extends"
|
||||
EXTERNAL "external"
|
||||
FALSE "false"
|
||||
FN "fn"
|
||||
FN_TYPE "__Fn"
|
||||
FOR "for"
|
||||
FORALL "forall"
|
||||
GREATER ">"
|
||||
GREATER_EQUAL ">="
|
||||
GREATER_GREATER ">>"
|
||||
GREATER_GREATER_EQUAL ">>="
|
||||
IF "if"
|
||||
IMPL "impl"
|
||||
IMPORT "import"
|
||||
IN "in"
|
||||
INTERFACE "interface"
|
||||
IS "is"
|
||||
LEFT_CURLY_BRACE "{"
|
||||
LEFT_PARENTHESIS "("
|
||||
LEFT_SQUARE_BRACKET "["
|
||||
LESS "<"
|
||||
LESS_EQUAL "<="
|
||||
LESS_LESS "<<"
|
||||
LESS_LESS_EQUAL "<<="
|
||||
LET "let"
|
||||
LIBRARY "library"
|
||||
MATCH "match"
|
||||
MATCH_FIRST "__match_first"
|
||||
MINUS "-"
|
||||
MINUS_EQUAL "-="
|
||||
MINUS_MINUS "--"
|
||||
MIX "__mix"
|
||||
MIXIN "__mixin"
|
||||
NOT "not"
|
||||
NOT_EQUAL "!="
|
||||
OR "or"
|
||||
PACKAGE "package"
|
||||
PERCENT "%"
|
||||
PERCENT_EQUAL "%="
|
||||
PERIOD "."
|
||||
PIPE "|"
|
||||
PIPE_EQUAL "|="
|
||||
PLUS "+"
|
||||
PLUS_EQUAL "+="
|
||||
PLUS_PLUS "++"
|
||||
RETURN "return"
|
||||
RETURNED "returned"
|
||||
RIGHT_CURLY_BRACE "}"
|
||||
RIGHT_PARENTHESIS ")"
|
||||
RIGHT_SQUARE_BRACKET "]"
|
||||
RUN "__run"
|
||||
SELF "Self"
|
||||
SEMICOLON ";"
|
||||
SLASH "/"
|
||||
SLASH_EQUAL "/="
|
||||
STAR_EQUAL "*="
|
||||
STRING "String"
|
||||
THEN "then"
|
||||
TRUE "true"
|
||||
TYPE "type"
|
||||
UNDERSCORE "_"
|
||||
UNIMPL_EXAMPLE "__unimplemented_example_infix"
|
||||
VAR "var"
|
||||
VIRTUAL "virtual"
|
||||
WHERE "where"
|
||||
WHILE "while"
|
||||
/* table-end */
|
||||
|
||||
/* This should be kept table-like, but isn't automatic due to spaces. */
|
||||
@@ -140,89 +152,101 @@ operand_start [(A-Za-z0-9_\"]
|
||||
%}
|
||||
|
||||
/* table-begin */
|
||||
{ABSTRACT} { return CARBON_SIMPLE_TOKEN(ABSTRACT); }
|
||||
{ADDR} { return CARBON_SIMPLE_TOKEN(ADDR); }
|
||||
{ALIAS} { return CARBON_SIMPLE_TOKEN(ALIAS); }
|
||||
{AMPERSAND} { return CARBON_SIMPLE_TOKEN(AMPERSAND); }
|
||||
{AND} { return CARBON_SIMPLE_TOKEN(AND); }
|
||||
{API} { return CARBON_SIMPLE_TOKEN(API); }
|
||||
{ARROW} { return CARBON_SIMPLE_TOKEN(ARROW); }
|
||||
{AS} { return CARBON_SIMPLE_TOKEN(AS); }
|
||||
{AUTO} { return CARBON_SIMPLE_TOKEN(AUTO); }
|
||||
{AWAIT} { return CARBON_SIMPLE_TOKEN(AWAIT); }
|
||||
{BASE} { return CARBON_SIMPLE_TOKEN(BASE); }
|
||||
{BOOL} { return CARBON_SIMPLE_TOKEN(BOOL); }
|
||||
{BREAK} { return CARBON_SIMPLE_TOKEN(BREAK); }
|
||||
{CARET} { return CARBON_SIMPLE_TOKEN(CARET); }
|
||||
{CASE} { return CARBON_SIMPLE_TOKEN(CASE); }
|
||||
{CHOICE} { return CARBON_SIMPLE_TOKEN(CHOICE); }
|
||||
{CLASS} { return CARBON_SIMPLE_TOKEN(CLASS); }
|
||||
{COLON_BANG} { return CARBON_SIMPLE_TOKEN(COLON_BANG); }
|
||||
{COLON} { return CARBON_SIMPLE_TOKEN(COLON); }
|
||||
{COMMA} { return CARBON_SIMPLE_TOKEN(COMMA); }
|
||||
{CONSTRAINT} { return CARBON_SIMPLE_TOKEN(CONSTRAINT); }
|
||||
{CONTINUATION_TYPE} { return CARBON_SIMPLE_TOKEN(CONTINUATION_TYPE); }
|
||||
{CONTINUATION} { return CARBON_SIMPLE_TOKEN(CONTINUATION); }
|
||||
{CONTINUE} { return CARBON_SIMPLE_TOKEN(CONTINUE); }
|
||||
{DEFAULT} { return CARBON_SIMPLE_TOKEN(DEFAULT); }
|
||||
{DESTRUCTOR} { return CARBON_SIMPLE_TOKEN(DESTRUCTOR); }
|
||||
{DOUBLE_ARROW} { return CARBON_SIMPLE_TOKEN(DOUBLE_ARROW); }
|
||||
{ELSE} { return CARBON_SIMPLE_TOKEN(ELSE); }
|
||||
{EQUAL_EQUAL} { return CARBON_SIMPLE_TOKEN(EQUAL_EQUAL); }
|
||||
{EQUAL} { return CARBON_SIMPLE_TOKEN(EQUAL); }
|
||||
{EXTENDS} { return CARBON_SIMPLE_TOKEN(EXTENDS); }
|
||||
{EXTERNAL} { return CARBON_SIMPLE_TOKEN(EXTERNAL); }
|
||||
{FALSE} { return CARBON_SIMPLE_TOKEN(FALSE); }
|
||||
{FN_TYPE} { return CARBON_SIMPLE_TOKEN(FN_TYPE); }
|
||||
{FN} { return CARBON_SIMPLE_TOKEN(FN); }
|
||||
{FORALL} { return CARBON_SIMPLE_TOKEN(FORALL); }
|
||||
{FOR} { return CARBON_SIMPLE_TOKEN(FOR); }
|
||||
{GREATER_EQUAL} { return CARBON_SIMPLE_TOKEN(GREATER_EQUAL); }
|
||||
{GREATER_GREATER} { return CARBON_SIMPLE_TOKEN(GREATER_GREATER); }
|
||||
{GREATER} { return CARBON_SIMPLE_TOKEN(GREATER); }
|
||||
{IF} { return CARBON_SIMPLE_TOKEN(IF); }
|
||||
{IMPL} { return CARBON_SIMPLE_TOKEN(IMPL); }
|
||||
{IMPORT} { return CARBON_SIMPLE_TOKEN(IMPORT); }
|
||||
{INTERFACE} { return CARBON_SIMPLE_TOKEN(INTERFACE); }
|
||||
{IN} { return CARBON_SIMPLE_TOKEN(IN); }
|
||||
{IS} { return CARBON_SIMPLE_TOKEN(IS); }
|
||||
{LEFT_CURLY_BRACE} { return CARBON_SIMPLE_TOKEN(LEFT_CURLY_BRACE); }
|
||||
{LEFT_PARENTHESIS} { return CARBON_SIMPLE_TOKEN(LEFT_PARENTHESIS); }
|
||||
{LEFT_SQUARE_BRACKET} { return CARBON_SIMPLE_TOKEN(LEFT_SQUARE_BRACKET); }
|
||||
{LESS_EQUAL} { return CARBON_SIMPLE_TOKEN(LESS_EQUAL); }
|
||||
{LESS_LESS} { return CARBON_SIMPLE_TOKEN(LESS_LESS); }
|
||||
{LESS} { return CARBON_SIMPLE_TOKEN(LESS); }
|
||||
{LET} { return CARBON_SIMPLE_TOKEN(LET); }
|
||||
{LIBRARY} { return CARBON_SIMPLE_TOKEN(LIBRARY); }
|
||||
{MATCH_FIRST} { return CARBON_SIMPLE_TOKEN(MATCH_FIRST); }
|
||||
{MATCH} { return CARBON_SIMPLE_TOKEN(MATCH); }
|
||||
{MINUS} { return CARBON_SIMPLE_TOKEN(MINUS); }
|
||||
{MIXIN} { return CARBON_SIMPLE_TOKEN(MIXIN); }
|
||||
{MIX} { return CARBON_SIMPLE_TOKEN(MIX); }
|
||||
{NOT_EQUAL} { return CARBON_SIMPLE_TOKEN(NOT_EQUAL); }
|
||||
{NOT} { return CARBON_SIMPLE_TOKEN(NOT); }
|
||||
{OR} { return CARBON_SIMPLE_TOKEN(OR); }
|
||||
{PACKAGE} { return CARBON_SIMPLE_TOKEN(PACKAGE); }
|
||||
{PERCENT} { return CARBON_SIMPLE_TOKEN(PERCENT); }
|
||||
{PERIOD} { return CARBON_SIMPLE_TOKEN(PERIOD); }
|
||||
{PIPE} { return CARBON_SIMPLE_TOKEN(PIPE); }
|
||||
{PLUS} { return CARBON_SIMPLE_TOKEN(PLUS); }
|
||||
{RETURNED} { return CARBON_SIMPLE_TOKEN(RETURNED); }
|
||||
{RETURN} { return CARBON_SIMPLE_TOKEN(RETURN); }
|
||||
{RUN} { return CARBON_SIMPLE_TOKEN(RUN); }
|
||||
{SELF} { return CARBON_SIMPLE_TOKEN(SELF); }
|
||||
{SEMICOLON} { return CARBON_SIMPLE_TOKEN(SEMICOLON); }
|
||||
{SLASH} { return CARBON_SIMPLE_TOKEN(SLASH); }
|
||||
{STRING} { return CARBON_SIMPLE_TOKEN(STRING); }
|
||||
{THEN} { return CARBON_SIMPLE_TOKEN(THEN); }
|
||||
{TRUE} { return CARBON_SIMPLE_TOKEN(TRUE); }
|
||||
{TYPE} { return CARBON_SIMPLE_TOKEN(TYPE); }
|
||||
{UNDERSCORE} { return CARBON_SIMPLE_TOKEN(UNDERSCORE); }
|
||||
{UNIMPL_EXAMPLE} { return CARBON_SIMPLE_TOKEN(UNIMPL_EXAMPLE); }
|
||||
{VAR} { return CARBON_SIMPLE_TOKEN(VAR); }
|
||||
{VIRTUAL} { return CARBON_SIMPLE_TOKEN(VIRTUAL); }
|
||||
{WHERE} { return CARBON_SIMPLE_TOKEN(WHERE); }
|
||||
{WHILE} { return CARBON_SIMPLE_TOKEN(WHILE); }
|
||||
{ABSTRACT} { return CARBON_SIMPLE_TOKEN(ABSTRACT); }
|
||||
{ADDR} { return CARBON_SIMPLE_TOKEN(ADDR); }
|
||||
{ALIAS} { return CARBON_SIMPLE_TOKEN(ALIAS); }
|
||||
{AMPERSAND_EQUAL} { return CARBON_SIMPLE_TOKEN(AMPERSAND_EQUAL); }
|
||||
{AMPERSAND} { return CARBON_SIMPLE_TOKEN(AMPERSAND); }
|
||||
{AND} { return CARBON_SIMPLE_TOKEN(AND); }
|
||||
{API} { return CARBON_SIMPLE_TOKEN(API); }
|
||||
{ARROW} { return CARBON_SIMPLE_TOKEN(ARROW); }
|
||||
{AS} { return CARBON_SIMPLE_TOKEN(AS); }
|
||||
{AUTO} { return CARBON_SIMPLE_TOKEN(AUTO); }
|
||||
{AWAIT} { return CARBON_SIMPLE_TOKEN(AWAIT); }
|
||||
{BASE} { return CARBON_SIMPLE_TOKEN(BASE); }
|
||||
{BOOL} { return CARBON_SIMPLE_TOKEN(BOOL); }
|
||||
{BREAK} { return CARBON_SIMPLE_TOKEN(BREAK); }
|
||||
{CARET_EQUAL} { return CARBON_SIMPLE_TOKEN(CARET_EQUAL); }
|
||||
{CARET} { return CARBON_SIMPLE_TOKEN(CARET); }
|
||||
{CASE} { return CARBON_SIMPLE_TOKEN(CASE); }
|
||||
{CHOICE} { return CARBON_SIMPLE_TOKEN(CHOICE); }
|
||||
{CLASS} { return CARBON_SIMPLE_TOKEN(CLASS); }
|
||||
{COLON_BANG} { return CARBON_SIMPLE_TOKEN(COLON_BANG); }
|
||||
{COLON} { return CARBON_SIMPLE_TOKEN(COLON); }
|
||||
{COMMA} { return CARBON_SIMPLE_TOKEN(COMMA); }
|
||||
{CONSTRAINT} { return CARBON_SIMPLE_TOKEN(CONSTRAINT); }
|
||||
{CONTINUATION_TYPE} { return CARBON_SIMPLE_TOKEN(CONTINUATION_TYPE); }
|
||||
{CONTINUATION} { return CARBON_SIMPLE_TOKEN(CONTINUATION); }
|
||||
{CONTINUE} { return CARBON_SIMPLE_TOKEN(CONTINUE); }
|
||||
{DEFAULT} { return CARBON_SIMPLE_TOKEN(DEFAULT); }
|
||||
{DESTRUCTOR} { return CARBON_SIMPLE_TOKEN(DESTRUCTOR); }
|
||||
{DOUBLE_ARROW} { return CARBON_SIMPLE_TOKEN(DOUBLE_ARROW); }
|
||||
{ELSE} { return CARBON_SIMPLE_TOKEN(ELSE); }
|
||||
{EQUAL_EQUAL} { return CARBON_SIMPLE_TOKEN(EQUAL_EQUAL); }
|
||||
{EQUAL} { return CARBON_SIMPLE_TOKEN(EQUAL); }
|
||||
{EXTENDS} { return CARBON_SIMPLE_TOKEN(EXTENDS); }
|
||||
{EXTERNAL} { return CARBON_SIMPLE_TOKEN(EXTERNAL); }
|
||||
{FALSE} { return CARBON_SIMPLE_TOKEN(FALSE); }
|
||||
{FN_TYPE} { return CARBON_SIMPLE_TOKEN(FN_TYPE); }
|
||||
{FN} { return CARBON_SIMPLE_TOKEN(FN); }
|
||||
{FORALL} { return CARBON_SIMPLE_TOKEN(FORALL); }
|
||||
{FOR} { return CARBON_SIMPLE_TOKEN(FOR); }
|
||||
{GREATER_EQUAL} { return CARBON_SIMPLE_TOKEN(GREATER_EQUAL); }
|
||||
{GREATER_GREATER_EQUAL} { return CARBON_SIMPLE_TOKEN(GREATER_GREATER_EQUAL); }
|
||||
{GREATER_GREATER} { return CARBON_SIMPLE_TOKEN(GREATER_GREATER); }
|
||||
{GREATER} { return CARBON_SIMPLE_TOKEN(GREATER); }
|
||||
{IF} { return CARBON_SIMPLE_TOKEN(IF); }
|
||||
{IMPL} { return CARBON_SIMPLE_TOKEN(IMPL); }
|
||||
{IMPORT} { return CARBON_SIMPLE_TOKEN(IMPORT); }
|
||||
{INTERFACE} { return CARBON_SIMPLE_TOKEN(INTERFACE); }
|
||||
{IN} { return CARBON_SIMPLE_TOKEN(IN); }
|
||||
{IS} { return CARBON_SIMPLE_TOKEN(IS); }
|
||||
{LEFT_CURLY_BRACE} { return CARBON_SIMPLE_TOKEN(LEFT_CURLY_BRACE); }
|
||||
{LEFT_PARENTHESIS} { return CARBON_SIMPLE_TOKEN(LEFT_PARENTHESIS); }
|
||||
{LEFT_SQUARE_BRACKET} { return CARBON_SIMPLE_TOKEN(LEFT_SQUARE_BRACKET); }
|
||||
{LESS_EQUAL} { return CARBON_SIMPLE_TOKEN(LESS_EQUAL); }
|
||||
{LESS_LESS_EQUAL} { return CARBON_SIMPLE_TOKEN(LESS_LESS_EQUAL); }
|
||||
{LESS_LESS} { return CARBON_SIMPLE_TOKEN(LESS_LESS); }
|
||||
{LESS} { return CARBON_SIMPLE_TOKEN(LESS); }
|
||||
{LET} { return CARBON_SIMPLE_TOKEN(LET); }
|
||||
{LIBRARY} { return CARBON_SIMPLE_TOKEN(LIBRARY); }
|
||||
{MATCH_FIRST} { return CARBON_SIMPLE_TOKEN(MATCH_FIRST); }
|
||||
{MATCH} { return CARBON_SIMPLE_TOKEN(MATCH); }
|
||||
{MINUS_EQUAL} { return CARBON_SIMPLE_TOKEN(MINUS_EQUAL); }
|
||||
{MINUS_MINUS} { return CARBON_SIMPLE_TOKEN(MINUS_MINUS); }
|
||||
{MINUS} { return CARBON_SIMPLE_TOKEN(MINUS); }
|
||||
{MIXIN} { return CARBON_SIMPLE_TOKEN(MIXIN); }
|
||||
{MIX} { return CARBON_SIMPLE_TOKEN(MIX); }
|
||||
{NOT_EQUAL} { return CARBON_SIMPLE_TOKEN(NOT_EQUAL); }
|
||||
{NOT} { return CARBON_SIMPLE_TOKEN(NOT); }
|
||||
{OR} { return CARBON_SIMPLE_TOKEN(OR); }
|
||||
{PACKAGE} { return CARBON_SIMPLE_TOKEN(PACKAGE); }
|
||||
{PERCENT_EQUAL} { return CARBON_SIMPLE_TOKEN(PERCENT_EQUAL); }
|
||||
{PERCENT} { return CARBON_SIMPLE_TOKEN(PERCENT); }
|
||||
{PERIOD} { return CARBON_SIMPLE_TOKEN(PERIOD); }
|
||||
{PIPE_EQUAL} { return CARBON_SIMPLE_TOKEN(PIPE_EQUAL); }
|
||||
{PIPE} { return CARBON_SIMPLE_TOKEN(PIPE); }
|
||||
{PLUS_EQUAL} { return CARBON_SIMPLE_TOKEN(PLUS_EQUAL); }
|
||||
{PLUS_PLUS} { return CARBON_SIMPLE_TOKEN(PLUS_PLUS); }
|
||||
{PLUS} { return CARBON_SIMPLE_TOKEN(PLUS); }
|
||||
{RETURNED} { return CARBON_SIMPLE_TOKEN(RETURNED); }
|
||||
{RETURN} { return CARBON_SIMPLE_TOKEN(RETURN); }
|
||||
{RUN} { return CARBON_SIMPLE_TOKEN(RUN); }
|
||||
{SELF} { return CARBON_SIMPLE_TOKEN(SELF); }
|
||||
{SEMICOLON} { return CARBON_SIMPLE_TOKEN(SEMICOLON); }
|
||||
{SLASH_EQUAL} { return CARBON_SIMPLE_TOKEN(SLASH_EQUAL); }
|
||||
{SLASH} { return CARBON_SIMPLE_TOKEN(SLASH); }
|
||||
{STAR_EQUAL} { return CARBON_SIMPLE_TOKEN(STAR_EQUAL); }
|
||||
{STRING} { return CARBON_SIMPLE_TOKEN(STRING); }
|
||||
{THEN} { return CARBON_SIMPLE_TOKEN(THEN); }
|
||||
{TRUE} { return CARBON_SIMPLE_TOKEN(TRUE); }
|
||||
{TYPE} { return CARBON_SIMPLE_TOKEN(TYPE); }
|
||||
{UNDERSCORE} { return CARBON_SIMPLE_TOKEN(UNDERSCORE); }
|
||||
{UNIMPL_EXAMPLE} { return CARBON_SIMPLE_TOKEN(UNIMPL_EXAMPLE); }
|
||||
{VAR} { return CARBON_SIMPLE_TOKEN(VAR); }
|
||||
{VIRTUAL} { return CARBON_SIMPLE_TOKEN(VIRTUAL); }
|
||||
{WHERE} { return CARBON_SIMPLE_TOKEN(WHERE); }
|
||||
{WHILE} { return CARBON_SIMPLE_TOKEN(WHILE); }
|
||||
/* table-end */
|
||||
|
||||
/* More modern Bisons provide make_EOF. */
|
||||
|
||||
@@ -121,6 +121,8 @@
|
||||
%type <std::vector<Nonnull<Declaration*>>> interface_body
|
||||
%type <std::vector<Nonnull<Declaration*>>> impl_body
|
||||
%type <Nonnull<Statement*>> statement
|
||||
%type <Nonnull<Statement*>> assign_statement
|
||||
%type <AssignOperator> assign_operator
|
||||
%type <Nonnull<If*>> if_statement
|
||||
%type <std::optional<Nonnull<Block*>>> optional_else
|
||||
%type <std::pair<Nonnull<Expression*>, bool>> return_expression
|
||||
@@ -207,6 +209,7 @@
|
||||
ADDR
|
||||
ALIAS
|
||||
AMPERSAND
|
||||
AMPERSAND_EQUAL
|
||||
AND
|
||||
API
|
||||
ARROW
|
||||
@@ -217,6 +220,7 @@
|
||||
BOOL
|
||||
BREAK
|
||||
CARET
|
||||
CARET_EQUAL
|
||||
CASE
|
||||
CHOICE
|
||||
CLASS
|
||||
@@ -243,6 +247,7 @@
|
||||
GREATER
|
||||
GREATER_EQUAL
|
||||
GREATER_GREATER
|
||||
GREATER_GREATER_EQUAL
|
||||
IF
|
||||
IMPL
|
||||
IMPORT
|
||||
@@ -255,21 +260,29 @@
|
||||
LESS
|
||||
LESS_EQUAL
|
||||
LESS_LESS
|
||||
LESS_LESS_EQUAL
|
||||
LET
|
||||
LIBRARY
|
||||
MATCH
|
||||
MATCH_FIRST
|
||||
MINUS
|
||||
MINUS_EQUAL
|
||||
MINUS_MINUS
|
||||
MIX
|
||||
MIXIN
|
||||
NOT
|
||||
NOT_EQUAL
|
||||
OR
|
||||
OR_EQUAL
|
||||
PACKAGE
|
||||
PERCENT
|
||||
PERCENT_EQUAL
|
||||
PERIOD
|
||||
PIPE
|
||||
PIPE_EQUAL
|
||||
PLUS
|
||||
PLUS_EQUAL
|
||||
PLUS_PLUS
|
||||
RETURN
|
||||
RETURNED
|
||||
RIGHT_CURLY_BRACE
|
||||
@@ -279,6 +292,8 @@
|
||||
SELF
|
||||
SEMICOLON
|
||||
SLASH
|
||||
SLASH_EQUAL
|
||||
STAR_EQUAL
|
||||
STRING
|
||||
THEN
|
||||
TRUE
|
||||
@@ -927,8 +942,7 @@ clause_list:
|
||||
}
|
||||
;
|
||||
statement:
|
||||
statement_expression EQUAL expression SEMICOLON
|
||||
{ $$ = arena->New<Assign>(context.source_loc(), $1, $3); }
|
||||
assign_statement
|
||||
| VAR pattern SEMICOLON
|
||||
{
|
||||
$$ = arena->New<VariableDefinition>(
|
||||
@@ -989,6 +1003,38 @@ statement:
|
||||
| FOR LEFT_PARENTHESIS variable_declaration IN type_expression RIGHT_PARENTHESIS block
|
||||
{ $$ = arena->New<For>(context.source_loc(), $3, $5, $7); }
|
||||
;
|
||||
assign_statement:
|
||||
statement_expression assign_operator expression SEMICOLON
|
||||
{ $$ = arena->New<Assign>(context.source_loc(), $1, $2, $3); }
|
||||
| PLUS_PLUS expression SEMICOLON
|
||||
{ $$ = arena->New<IncrementDecrement>(context.source_loc(), $2, true); }
|
||||
| MINUS_MINUS expression SEMICOLON
|
||||
{ $$ = arena->New<IncrementDecrement>(context.source_loc(), $2, false); }
|
||||
;
|
||||
assign_operator:
|
||||
EQUAL
|
||||
{ $$ = AssignOperator::Plain; }
|
||||
| PLUS_EQUAL
|
||||
{ $$ = AssignOperator::Add; }
|
||||
| SLASH_EQUAL
|
||||
{ $$ = AssignOperator::Div; }
|
||||
| STAR_EQUAL
|
||||
{ $$ = AssignOperator::Mul; }
|
||||
| PERCENT_EQUAL
|
||||
{ $$ = AssignOperator::Mod; }
|
||||
| MINUS_EQUAL
|
||||
{ $$ = AssignOperator::Sub; }
|
||||
| AMPERSAND_EQUAL
|
||||
{ $$ = AssignOperator::And; }
|
||||
| PIPE_EQUAL
|
||||
{ $$ = AssignOperator::Or; }
|
||||
| CARET_EQUAL
|
||||
{ $$ = AssignOperator::Xor; }
|
||||
| LESS_LESS_EQUAL
|
||||
{ $$ = AssignOperator::ShiftLeft; }
|
||||
| GREATER_GREATER_EQUAL
|
||||
{ $$ = AssignOperator::ShiftRight; }
|
||||
;
|
||||
if_statement:
|
||||
IF LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block optional_else
|
||||
{ $$ = arena->New<If>(context.source_loc(), $3, $5, $6); }
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
// error
|
||||
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary *
|
||||
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON
|
||||
x : i32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ fn Main() -> i32 {
|
||||
// Error: can't use keyword `Self` as the name of a variable.
|
||||
// TODO: Current error message is unclear, better would be to say
|
||||
// something like: unexpected `Self`, expecting identifier
|
||||
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary *
|
||||
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
|
||||
var Self : i32 = 0;
|
||||
return Self;
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
// Error: Can't use keyword `Self` as the name of a local.
|
||||
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/let/fail_local_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary *
|
||||
// CHECK:STDERR: SYNTAX ERROR: {{.*}}/explorer/testdata/let/fail_local_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL
|
||||
let Self: auto = 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+10
-2
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 12
|
||||
// CHECK:STDOUT: 12
|
||||
// CHECK:STDOUT: 19
|
||||
// CHECK:STDOUT: 26
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -18,5 +21,10 @@ external impl A as Add {
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
var b: A = {.n = 7};
|
||||
return (a + b).n;
|
||||
a = a + b;
|
||||
Print("{0}", a.n);
|
||||
a += b;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a + b).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: Before: 1
|
||||
// CHECK:STDOUT: Interface: 2
|
||||
// CHECK:STDOUT: Op: 3
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
class C {
|
||||
var n: i32;
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var c: C = {.n = 1};
|
||||
Print("Before: {0}", c.n);
|
||||
c.(AssignWith({.n: i32}).Op)({.n = 2});
|
||||
Print("Interface: {0}", c.n);
|
||||
c = {.n = 3};
|
||||
Print("Op: {0}", c.n);
|
||||
return 0;
|
||||
}
|
||||
+11
-4
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 1
|
||||
// CHECK:STDOUT: 5
|
||||
// CHECK:STDOUT: 4
|
||||
// CHECK:STDOUT: 0
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -16,7 +19,11 @@ external impl A as BitAndWith(i32) where .Result = A {
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
a = a & 1;
|
||||
return a.n;
|
||||
var a: A = {.n = 13};
|
||||
a = a & 7;
|
||||
Print("{0}", a.n);
|
||||
a &= -2;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a & 3).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+11
-4
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 5
|
||||
// CHECK:STDOUT: 3
|
||||
// CHECK:STDOUT: 7
|
||||
// CHECK:STDOUT: 15
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -16,7 +19,11 @@ external impl A as BitOrWith(i32) where .Result = A {
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 4};
|
||||
a = a | 1;
|
||||
return a.n;
|
||||
var a: A = {.n = 1};
|
||||
a = a | 2;
|
||||
Print("{0}", a.n);
|
||||
a |= 5;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a | 12).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+10
-3
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 4
|
||||
// CHECK:STDOUT: 6
|
||||
// CHECK:STDOUT: 0
|
||||
// CHECK:STDOUT: -1
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -17,6 +20,10 @@ external impl A as BitXorWith(i32) where .Result = A {
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
a = a ^ 1;
|
||||
return a.n;
|
||||
a = a ^ 3;
|
||||
Print("{0}", a.n);
|
||||
a ^= 6;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a ^ -1).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+10
-3
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 2
|
||||
// CHECK:STDOUT: 6
|
||||
// CHECK:STDOUT: 3
|
||||
// CHECK:STDOUT: 1
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -16,7 +19,11 @@ external impl A as DivWith(i32) where .Result = A {
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 8};
|
||||
var a: A = {.n = 19};
|
||||
a = a / 3;
|
||||
return a.n;
|
||||
Print("{0}", a.n);
|
||||
a /= 2;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a / 2).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
// 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
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: 6
|
||||
// CHECK:STDOUT: 5
|
||||
// CHECK:STDOUT: 6
|
||||
// CHECK:STDOUT: 5
|
||||
// CHECK:STDOUT: 6
|
||||
// CHECK:STDOUT: 5
|
||||
// CHECK:STDOUT: 6
|
||||
// CHECK:STDOUT: 5
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
class A { var n: i32; }
|
||||
|
||||
external impl A as Inc {
|
||||
fn Op[addr self: Self*]() { ++self->n; }
|
||||
}
|
||||
external impl A as Dec {
|
||||
fn Op[addr self: Self*]() { --self->n; }
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
++a.n;
|
||||
Print("{0}", a.n);
|
||||
--a.n;
|
||||
Print("{0}", a.n);
|
||||
++a;
|
||||
Print("{0}", a.n);
|
||||
--a;
|
||||
Print("{0}", a.n);
|
||||
a.n.(Inc.Op)();
|
||||
Print("{0}", a.n);
|
||||
a.n.(Dec.Op)();
|
||||
Print("{0}", a.n);
|
||||
a.(Inc.Op)();
|
||||
Print("{0}", a.n);
|
||||
a.(Dec.Op)();
|
||||
Print("{0}", a.n);
|
||||
return 0;
|
||||
}
|
||||
+11
-4
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 1
|
||||
// CHECK:STDOUT: 7
|
||||
// CHECK:STDOUT: 3
|
||||
// CHECK:STDOUT: 0
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -16,7 +19,11 @@ external impl A as ModWith(i32) where .Result = A {
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
a = a % 2;
|
||||
return a.n;
|
||||
var a: A = {.n = 15};
|
||||
a = a % 8;
|
||||
Print("{0}", a.n);
|
||||
a %= 4;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a % 3).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+9
-2
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 10
|
||||
// CHECK:STDOUT: 10
|
||||
// CHECK:STDOUT: 30
|
||||
// CHECK:STDOUT: 210
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -18,5 +21,9 @@ external impl A as MulWith(i32) where .Result = A {
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
a = a * 2;
|
||||
return a.n;
|
||||
Print("{0}", a.n);
|
||||
a *= 3;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a * 7).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+8
@@ -5,6 +5,8 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: 8
|
||||
// CHECK:STDOUT: 4
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
@@ -21,5 +23,11 @@ fn Main() -> i32 {
|
||||
if (not (-1 >> 1 == -1)) { return 9; }
|
||||
if (not (-2 >> 1 == -1)) { return 10; }
|
||||
|
||||
var n: i32 = 1;
|
||||
n <<= 3;
|
||||
Print("{0}", n);
|
||||
n >>= 1;
|
||||
Print("{0}", n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+9
-2
@@ -5,7 +5,10 @@
|
||||
// AUTOUPDATE
|
||||
// RUN: %{explorer-run}
|
||||
// RUN: %{explorer-run-trace}
|
||||
// CHECK:STDOUT: result: 4
|
||||
// CHECK:STDOUT: 4
|
||||
// CHECK:STDOUT: 3
|
||||
// CHECK:STDOUT: 2
|
||||
// CHECK:STDOUT: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
@@ -18,5 +21,9 @@ external impl A as SubWith(i32) where .Result = A {
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 5};
|
||||
a = a - 1;
|
||||
return a.n;
|
||||
Print("{0}", a.n);
|
||||
a -= 1;
|
||||
Print("{0}", a.n);
|
||||
Print("{0}", (a - 1).n);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
var p: auto = {.x = 0, .y = 0};
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_assign_different_types.carbon:[[@LINE+1]]: type error in assignment: '{.y: i32}' is not implicitly convertible to '{.x: i32, .y: i32}'
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/struct/fail_assign_different_types.carbon:[[@LINE+1]]: could not find implementation of interface AssignWith(U = {.y: i32}) for {.x: i32, .y: i32}
|
||||
p = {.y = 0};
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
// 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
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// RUN: %{not} %{explorer-run}
|
||||
// RUN: %{not} %{explorer-run-trace}
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
var x: i32;
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/unformed/static/fail_compound_assign.carbon:[[@LINE+1]]: use of uninitialized variable x
|
||||
x += 1;
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// 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
|
||||
//
|
||||
// AUTOUPDATE
|
||||
// RUN: %{not} %{explorer-run}
|
||||
// RUN: %{not} %{explorer-run-trace}
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
var x: i32;
|
||||
// CHECK:STDERR: COMPILATION ERROR: {{.*}}/explorer/testdata/unformed/static/fail_increment.carbon:[[@LINE+1]]: use of uninitialized variable x
|
||||
++x;
|
||||
return x;
|
||||
}
|
||||
Reference in New Issue
Block a user