From df936237417f23efacd114a13a7584b564d0986b Mon Sep 17 00:00:00 2001 From: pmqtt <51272730+pmqtt@users.noreply.github.com> Date: Fri, 29 Jul 2022 19:39:30 +0200 Subject: [PATCH] Extends carbon to generate random number to make samples more interesting (#1643) Implements the Rand function to carbon Co-authored-by: m new --- common/fuzzing/carbon.proto | 1 + common/fuzzing/proto_to_carbon.cpp | 3 +++ explorer/ast/expression.cpp | 7 ++++++- explorer/ast/expression.h | 2 +- explorer/data/prelude.carbon | 4 ++++ explorer/fuzzing/ast_to_proto.cpp | 3 +++ explorer/interpreter/interpreter.cpp | 13 +++++++++++++ explorer/interpreter/type_checker.cpp | 17 +++++++++++++++++ explorer/testdata/random/random.carbon | 25 +++++++++++++++++++++++++ 9 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 explorer/testdata/random/random.carbon diff --git a/common/fuzzing/carbon.proto b/common/fuzzing/carbon.proto index a2a91f51e287..b5fb6b6f9bfa 100644 --- a/common/fuzzing/carbon.proto +++ b/common/fuzzing/carbon.proto @@ -91,6 +91,7 @@ message IntrinsicExpression { Print = 1; Alloc = 2; Dealloc = 3; + Rand = 4; } optional Intrinsic intrinsic = 1; optional TupleLiteralExpression argument = 2; diff --git a/common/fuzzing/proto_to_carbon.cpp b/common/fuzzing/proto_to_carbon.cpp index 60faad7cde33..c376236c3994 100644 --- a/common/fuzzing/proto_to_carbon.cpp +++ b/common/fuzzing/proto_to_carbon.cpp @@ -306,6 +306,9 @@ static auto ExpressionToCarbon(const Fuzzing::Expression& expression, case Fuzzing::IntrinsicExpression::Dealloc: out << "__intrinsic_delete"; break; + case Fuzzing::IntrinsicExpression::Rand: + out << "__intrinsic_rand"; + break; } TupleLiteralExpressionToCarbon(intrinsic.argument(), out); } break; diff --git a/explorer/ast/expression.cpp b/explorer/ast/expression.cpp index 1db464dae13f..24ef10208cb2 100644 --- a/explorer/ast/expression.cpp +++ b/explorer/ast/expression.cpp @@ -29,7 +29,8 @@ auto IntrinsicExpression::FindIntrinsic(std::string_view name, static const auto& intrinsic_map = *new std::map( {{"print", Intrinsic::Print}, {"new", Intrinsic::Alloc}, - {"delete", Intrinsic::Dealloc}}); + {"delete", Intrinsic::Dealloc}, + {"rand", Intrinsic::Rand}}); name.remove_prefix(std::strlen("__intrinsic_")); auto it = intrinsic_map.find(name); if (it == intrinsic_map.end()) { @@ -175,6 +176,7 @@ void Expression::Print(llvm::raw_ostream& out) const { out << "Print" << iexp.args(); break; } + out << "intrinsic_"; switch (iexp.intrinsic()) { case IntrinsicExpression::Intrinsic::Print: @@ -186,6 +188,9 @@ void Expression::Print(llvm::raw_ostream& out) const { case IntrinsicExpression::Intrinsic::Dealloc: out << "delete"; break; + case IntrinsicExpression::Intrinsic::Rand: + out << "rand"; + break; } out << iexp.args(); break; diff --git a/explorer/ast/expression.h b/explorer/ast/expression.h index acb8564eb4af..c73f7afa0471 100644 --- a/explorer/ast/expression.h +++ b/explorer/ast/expression.h @@ -664,7 +664,7 @@ class ValueLiteral : public Expression { class IntrinsicExpression : public Expression { public: - enum class Intrinsic { Print, Alloc, Dealloc }; + enum class Intrinsic { Print, Alloc, Dealloc, Rand }; // Returns the enumerator corresponding to the intrinsic named `name`, // or raises a fatal compile error if there is no such enumerator. diff --git a/explorer/data/prelude.carbon b/explorer/data/prelude.carbon index 5ff3ee134c8b..f64963a067bc 100644 --- a/explorer/data/prelude.carbon +++ b/explorer/data/prelude.carbon @@ -106,6 +106,10 @@ external impl i32 as ModWith(i32) where .Result == i32 { // __intrinsic_print(format_str); // } +fn Rand(low: i32, high: i32) -> i32{ + return __intrinsic_rand(low,high); +} + class Heap { fn New[T:! Type, me: Self](x : T) -> T* { return __intrinsic_new(x); diff --git a/explorer/fuzzing/ast_to_proto.cpp b/explorer/fuzzing/ast_to_proto.cpp index b9dfaacc8304..85306bef098e 100644 --- a/explorer/fuzzing/ast_to_proto.cpp +++ b/explorer/fuzzing/ast_to_proto.cpp @@ -239,6 +239,9 @@ static auto ExpressionToProto(const Expression& expression) case IntrinsicExpression::Intrinsic::Dealloc: intrinsic_proto->set_intrinsic(Fuzzing::IntrinsicExpression::Dealloc); break; + case IntrinsicExpression::Intrinsic::Rand: + intrinsic_proto->set_intrinsic(Fuzzing::IntrinsicExpression::Rand); + break; } *intrinsic_proto->mutable_argument() = TupleLiteralExpressionToProto(intrinsic.args()); diff --git a/explorer/interpreter/interpreter.cpp b/explorer/interpreter/interpreter.cpp index 35e2c71a99ae..345de85572db 100644 --- a/explorer/interpreter/interpreter.cpp +++ b/explorer/interpreter/interpreter.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,8 @@ using llvm::isa; namespace Carbon { +static std::mt19937 generator(12); + // Constructs an ActionStack suitable for the specified phase. static auto MakeTodo(Phase phase, Nonnull heap) -> ActionStack { switch (phase) { @@ -1156,6 +1159,16 @@ auto Interpreter::StepExp() -> ErrorOr { } // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H} switch (cast(exp).intrinsic()) { + case IntrinsicExpression::Intrinsic::Rand: { + const auto& args = cast(*act.results()[0]).elements(); + CARBON_CHECK(args.size() == 2); + + const auto& low = cast(*args[0]).value(); + const auto& high = cast(*args[1]).value(); + std::uniform_int_distribution<> distr(low, high); + int r = distr(generator); + return todo_.FinishAction(arena_->New(r)); + } case IntrinsicExpression::Intrinsic::Print: { const auto& args = cast(*act.results()[0]).elements(); CARBON_ASSIGN_OR_RETURN( diff --git a/explorer/interpreter/type_checker.cpp b/explorer/interpreter/type_checker.cpp index 8aaee77a7966..7fd1a23aa6a5 100644 --- a/explorer/interpreter/type_checker.cpp +++ b/explorer/interpreter/type_checker.cpp @@ -2203,6 +2203,23 @@ auto TypeChecker::TypeCheckExp(Nonnull e, CARBON_RETURN_IF_ERROR(TypeCheckExp(&intrinsic_exp.args(), impl_scope)); const auto& args = intrinsic_exp.args().fields(); switch (cast(*e).intrinsic()) { + case IntrinsicExpression::Intrinsic::Rand: { + if (args.size() != 2) { + return CompilationError(e->source_loc()) + << "Rand takes 2 arguments, received " << args.size(); + } + CARBON_RETURN_IF_ERROR(ExpectExactType( + e->source_loc(), "Rand argument 0", arena_->New(), + &args[0]->static_type(), impl_scope)); + + CARBON_RETURN_IF_ERROR(ExpectExactType( + e->source_loc(), "Rand argument 1", arena_->New(), + &args[1]->static_type(), impl_scope)); + + e->set_static_type(arena_->New()); + + return Success(); + } case IntrinsicExpression::Intrinsic::Print: // TODO: Remove Print special casing once we have variadics or // overloads. Here, that's the name Print instead of __intrinsic_print diff --git a/explorer/testdata/random/random.carbon b/explorer/testdata/random/random.carbon new file mode 100644 index 000000000000..bc33f42c69c5 --- /dev/null +++ b/explorer/testdata/random/random.carbon @@ -0,0 +1,25 @@ +// 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: 0 + +package ExplorerTest api; +fn test(para: i32)->Bool{ + return true; +} +fn Main() -> i32 { + var i : i32 = Rand(0,100); + var j : i32 = Rand(0,100); + if(i == j){ + Print("HALLO WELT"); + }else{ + Print("Nice!"); + } + return 0; +}