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:
Junhee Cho
2022-09-19 15:02:29 -07:00
committed by GitHub
parent 57cc4c6dec
commit 69d4363ea5
15 changed files with 89 additions and 8 deletions
+1
View File
@@ -65,6 +65,7 @@ message OperatorExpression {
Greater = 22;
GreaterEq = 23;
NotEq = 24;
Div = 25;
}
optional Operator op = 1;
repeated Expression arguments = 2;
+4
View File
@@ -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;
+2
View File
@@ -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 "-";
+1
View File
@@ -123,6 +123,7 @@ enum class Operator {
BitShiftRight,
Complement,
Deref,
Div,
Eq,
Less,
LessEq,
+10
View File
@@ -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; }
}
+2
View File
@@ -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:
+7 -5
View File
@@ -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] = {};
};
+3
View File
@@ -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());
+2
View File
@@ -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:
+6
View File
@@ -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
View File
@@ -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;
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}