mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Adds division to multiplicative expression. (#2091)
* Multiplication and division have the same priority. * A new builtin interface DivWith is added. * In some tests expecting a compilation error (syntax error), the error message now says it is expecting SLASH or binary *.
This commit is contained in:
@@ -65,6 +65,7 @@ message OperatorExpression {
|
||||
Greater = 22;
|
||||
GreaterEq = 23;
|
||||
NotEq = 24;
|
||||
Div = 25;
|
||||
}
|
||||
optional Operator op = 1;
|
||||
repeated Expression arguments = 2;
|
||||
|
||||
@@ -117,6 +117,10 @@ static auto OperatorToCarbon(const Fuzzing::OperatorExpression& operator_expr,
|
||||
BinaryOperatorToCarbon(arg0, " * ", arg1, out);
|
||||
break;
|
||||
|
||||
case Fuzzing::OperatorExpression::Div:
|
||||
BinaryOperatorToCarbon(arg0, " / ", arg1, out);
|
||||
break;
|
||||
|
||||
case Fuzzing::OperatorExpression::Mod:
|
||||
BinaryOperatorToCarbon(arg0, " % ", arg1, out);
|
||||
break;
|
||||
|
||||
@@ -123,6 +123,8 @@ auto ToString(Operator op) -> std::string_view {
|
||||
return "<<";
|
||||
case Operator::BitShiftRight:
|
||||
return ">>";
|
||||
case Operator::Div:
|
||||
return "/";
|
||||
case Operator::Neg:
|
||||
case Operator::Sub:
|
||||
return "-";
|
||||
|
||||
@@ -123,6 +123,7 @@ enum class Operator {
|
||||
BitShiftRight,
|
||||
Complement,
|
||||
Deref,
|
||||
Div,
|
||||
Eq,
|
||||
Less,
|
||||
LessEq,
|
||||
|
||||
@@ -317,6 +317,13 @@ interface MulWith(U:! Type) {
|
||||
}
|
||||
// TODO: constraint Mul { ... }
|
||||
|
||||
interface DivWith(U:! Type) {
|
||||
// TODO: = Self
|
||||
let Result:! Type;
|
||||
fn Op[me: Self](other: U) -> Result;
|
||||
}
|
||||
// TODO: constraint Div { ... }
|
||||
|
||||
interface ModWith(U:! Type) {
|
||||
// TODO: = Self
|
||||
let Result:! Type;
|
||||
@@ -337,6 +344,9 @@ external impl i32 as SubWith(i32) where .Result == i32 {
|
||||
external impl i32 as MulWith(i32) where .Result == i32 {
|
||||
fn Op[me: i32](other: i32) -> i32 { return me * other; }
|
||||
}
|
||||
external impl i32 as DivWith(i32) where .Result == i32 {
|
||||
fn Op[me: i32](other: i32) -> i32 { return me / other; }
|
||||
}
|
||||
external impl i32 as ModWith(i32) where .Result == i32 {
|
||||
fn Op[me: i32](other: i32) -> i32 { return me % other; }
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ static auto OperatorToProtoEnum(const Operator op)
|
||||
return Fuzzing::OperatorExpression::GreaterEq;
|
||||
case Operator::Mul:
|
||||
return Fuzzing::OperatorExpression::Mul;
|
||||
case Operator::Div:
|
||||
return Fuzzing::OperatorExpression::Div;
|
||||
case Operator::Mod:
|
||||
return Fuzzing::OperatorExpression::Mod;
|
||||
case Operator::Or:
|
||||
|
||||
@@ -40,6 +40,7 @@ class Builtins {
|
||||
AddWith,
|
||||
SubWith,
|
||||
MulWith,
|
||||
DivWith,
|
||||
ModWith,
|
||||
|
||||
// Bitwise and shift.
|
||||
@@ -64,6 +65,7 @@ class Builtins {
|
||||
static constexpr Builtin AddWith = Builtin::AddWith;
|
||||
static constexpr Builtin SubWith = Builtin::SubWith;
|
||||
static constexpr Builtin MulWith = Builtin::MulWith;
|
||||
static constexpr Builtin DivWith = Builtin::DivWith;
|
||||
static constexpr Builtin ModWith = Builtin::ModWith;
|
||||
static constexpr Builtin BitComplement = Builtin::BitComplement;
|
||||
static constexpr Builtin BitAndWith = Builtin::BitAndWith;
|
||||
@@ -88,11 +90,11 @@ 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",
|
||||
"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"};
|
||||
|
||||
std::optional<Nonnull<const Declaration*>> builtins_[NumBuiltins] = {};
|
||||
};
|
||||
|
||||
@@ -192,6 +192,9 @@ auto Interpreter::EvalPrim(Operator op, Nonnull<const Value*> static_type,
|
||||
case Operator::Mul:
|
||||
return arena_->New<IntValue>(cast<IntValue>(*args[0]).value() *
|
||||
cast<IntValue>(*args[1]).value());
|
||||
case Operator::Div:
|
||||
return arena_->New<IntValue>(cast<IntValue>(*args[0]).value() /
|
||||
cast<IntValue>(*args[1]).value());
|
||||
case Operator::Mod:
|
||||
return arena_->New<IntValue>(cast<IntValue>(*args[0]).value() %
|
||||
cast<IntValue>(*args[1]).value());
|
||||
|
||||
@@ -2061,6 +2061,8 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
return handle_binary_arithmetic(Builtins::SubWith);
|
||||
case Operator::Mul:
|
||||
return handle_binary_arithmetic(Builtins::MulWith);
|
||||
case Operator::Div:
|
||||
return handle_binary_arithmetic(Builtins::DivWith);
|
||||
case Operator::Mod:
|
||||
return handle_binary_arithmetic(Builtins::ModWith);
|
||||
case Operator::BitwiseAnd:
|
||||
|
||||
@@ -487,6 +487,12 @@ multiplicative_expression:
|
||||
context.source_loc(), Operator::Mul,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
| multiplicative_lhs SLASH simple_binary_operand
|
||||
{
|
||||
$$ = arena->New<OperatorExpression>(
|
||||
context.source_loc(), Operator::Div,
|
||||
std::vector<Nonnull<Expression*>>({$1, $3}));
|
||||
}
|
||||
;
|
||||
additive_operand:
|
||||
simple_binary_operand
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
// error
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_missing_var.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary *
|
||||
x : i32;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,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: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL or SEMICOLON
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/basic_syntax/fail_var_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary *
|
||||
var Self : i32 = 0;
|
||||
return Self;
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
// Error: Can't use keyword `Self` as the name of a local.
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting EQUAL
|
||||
// CHECK: COMPILATION ERROR: {{.*}}/explorer/testdata/let/fail_local_named_self.carbon:[[@LINE+1]]: syntax error, unexpected COLON, expecting SLASH or binary *
|
||||
let Self: auto = 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// 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
|
||||
//
|
||||
// RUN: %{explorer} %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
|
||||
// AUTOUPDATE: %{explorer} %s
|
||||
// CHECK: result: 2
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
class A { var n: i32; }
|
||||
|
||||
external impl A as DivWith(i32) where .Result == A {
|
||||
fn Op[me: Self](rhs: i32) -> A { return {.n = me.n / rhs}; }
|
||||
}
|
||||
|
||||
fn Main() -> i32 {
|
||||
var a: A = {.n = 8};
|
||||
a = a / 3;
|
||||
return a.n;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// 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
|
||||
//
|
||||
// RUN: %{explorer} %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes=false %s
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- %s 2>&1 | \
|
||||
// RUN: %{FileCheck} --match-full-lines --allow-unused-prefixes %s
|
||||
// AUTOUPDATE: %{explorer} %s
|
||||
// CHECK: Interface: 2
|
||||
// CHECK: Op: 2
|
||||
// CHECK: result: 0
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
fn Main() -> i32 {
|
||||
var lhs: i32 = 8;
|
||||
var rhs: i32 = 3;
|
||||
// Make sure that both the interface and operator work with i32. These rely on
|
||||
// builtin arithmetic more directly.
|
||||
Print("Interface: {0}", lhs.(DivWith(i32).Op)(rhs));
|
||||
Print("Op: {0}", lhs / rhs);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user