Goose  Artifact [548cf199ba]

Artifact 548cf199bab72e22dabe286b33658cb465d3146d07e7815f9c1a08a847f18a1b:

  • File bs/builtins/operators/arith.cpp — part of check-in [1ad61a2717] at 2021-11-11 20:05:58 on branch trunk — Refactored the code builder: it is now carried around as a Value, and accessed through a bunch of extension points, so we can have different builders (and even user defined ones) later to make classes etc. (user: zlodo size: 7695)

#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
#include "tuple.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;
using namespace goose::parse;

namespace goose::builtins
{
    void SetupArithOps( Env& e )
    {
        BuildParseRule( e, "+"_sid,
            PrefixOp( "operator_unary_plus"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),
                ForType< BigInt >( []< typename O >( auto&& c, O&& operand ) -> Value
                {
                    return forward< O >( operand );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
                []< typename O >( auto&& c, O&& operand ) -> Value
                {
                    return forward< O >( operand );
                } )
            ),
            LeftAssInfixOp( "operator_add"_sid, precedence::AddSubOp,
                BuildGenericTupleOperator(),
                ForType< BigInt, Add >(),
                ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    return BuildComputedValue( lhs.type(),
                        Add( lhs, rhs ) );
                } )
            )
        );

        BuildParseRule( e, "-"_sid,
            PrefixOp( "operator_unary_minus"_sid, precedence::UnaryOps,
                BuildGenericTupleOperator(),
                ForType< BigInt >( []( auto&& c, auto&& operand ) -> Value
                {
                    return BuildComputedValue( GetValueType< BigInt >(),
                        Sub( ToValue( BigInt() ), operand ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
                []( auto&& c, auto&& operand ) -> Value
                {
                    auto opTypeVal = *EIRToValue( operand.type() );
                    auto opType = *FromValue< IntegerType >( opTypeVal );
                    return BuildComputedValue( operand.type(),
                        Sub( Value( operand.type(), APSInt( opType.m_numBits, false ) ),
                            operand ) );
                } )
            ),
            LeftAssInfixOp( "operator_sub"_sid, precedence::AddSubOp,
                BuildGenericTupleOperator(),
                ForType< BigInt, Sub >(),
                ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    return BuildComputedValue( lhs.type(),
                        Sub( lhs, rhs ) );
                } )
            )
        );

        BuildParseRule( e, "*"_sid,
            LeftAssInfixOp( "operator_multiply"_sid, precedence::MulDivOp,
                BuildGenericTupleOperator(),
                ForType< BigInt, Mul >(),
                ForType< CustomPattern< IntegerType, IntegerType::Pattern > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    return BuildComputedValue( lhs.type(),
                        Mul( lhs, rhs ) );
                } )
            )
        );

        BuildParseRule( e, "/"_sid,
            LeftAssInfixOp( "operator_divide"_sid, precedence::MulDivOp,
                BuildGenericTupleOperator(),
                ForType< BigInt, SDiv >(),
                ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    using namespace goose::builtins::exprhelpers;

                    auto cfg = GetCFG( c );
                    assert( cfg );

                    // Build a zero constant of the same type as the denominator
                    // to construct the assertion expression.
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        SDiv( lhs, rhs ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    using namespace goose::builtins::exprhelpers;

                    auto cfg = GetCFG( c );
                    assert( cfg );

                    // Build a zero constant of the same type as the denominator
                    // to construct the assertion expression.
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        UDiv( lhs, rhs ) );
                } )
            )
        );

        BuildParseRule( e, "%"_sid,
            LeftAssInfixOp( "operator_modulo"_sid, precedence::MulDivOp,
                BuildGenericTupleOperator(),
                ForType< BigInt, SRem >(),
                ForType< CustomPattern< IntegerType, IntegerType::PatternSigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    using namespace goose::builtins::exprhelpers;

                    auto cfg = GetCFG( c );
                    assert( cfg );

                    // Build a zero constant of the same type as the denominator
                    // to construct the assertion expression.
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        SRem( lhs, rhs ) );
                } ),
                ForType< CustomPattern< IntegerType, IntegerType::PatternUnsigned > >(
                []( auto&& c, auto&& lhs, auto&& rhs ) -> Value
                {
                    using namespace goose::builtins::exprhelpers;

                    auto cfg = GetCFG( c );
                    assert( cfg );

                    // Build a zero constant of the same type as the denominator
                    // to construct the assertion expression.
                    auto zeroValue = Value( rhs.type(), APSInt::get( 0 ) );
                    auto cond = Neq( rhs, zeroValue );

                    DiagnosticsManager::GetInstance().defineCustomDiagnostic(
                        cond.locationId(), "assert"_sid, "the divisor may be 0." );

                    cfg->currentBB()->emplace_back(
                        cir::Assert( move( cond ) )
                    );

                    return BuildComputedValue( lhs.type(),
                        URem( lhs, rhs ) );
                } )
            )
        );
    }
}