Goose  Check-in [9089b014a2]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Overloading: parse function overloading, and multiple fixes. Overloading now works.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 9089b014a270859cf7ee9bc679141984806c791a66ffdd4ef863bad44e5f2b30
User & Date: achavasse 2019-03-16 23:19:44.246
Context
2019-03-17
00:13
Functions: store the signature alongside the body rather than in the type, to be consistent with template functions. check-in: cce96c5a25 user: achavasse tags: trunk
2019-03-16
23:19
Overloading: parse function overloading, and multiple fixes. Overloading now works. check-in: 9089b014a2 user: achavasse tags: trunk
21:27
Overloading: the first time a function or function template declaration is encountered, it is stored in a new overloadset. check-in: 224370818a user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/types/overloadset/overloadset.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23


24
25
26
27
28




29
30
31


32
33
34
35
36
37
38
#include "builtins/builtins.h"

using namespace empathy::builtins;

void OverloadSet::add( const sema::Context& context, const Value& callee )
{
    auto pInvRule = GetInvocationRule( context, callee );
    assert( pInvRule );

    auto signature = pInvRule->getSignature( callee );
    assert( signature );

    auto result = Decompose( *signature,
        Vec(
            Val< pvec >(),
            SubTerm()
        )
    );

    assert( result );

    auto&& [params,rt] = *result;
    const auto& rtype = rt;



    m_trie = m_trie->merge( *params, [&]( auto&& rtTrie )
    {
        return Merge( rtTrie, rtype, [&]( auto&& ) -> Overload
        {




            return { pInvRule, callee };
        } );
    } );


}

OverloadSet::UniGen OverloadSet::unify( const Term& argsPat, const Term& rtPat, UnificationContext& uc ) const
{
    auto argDecomp = Decompose( argsPat,
        Val< pvec >()
    );




|


















>
>



|

>
>
>
>



>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include "builtins/builtins.h"

using namespace empathy::builtins;

bool OverloadSet::add( const sema::Context& context, const Value& callee )
{
    auto pInvRule = GetInvocationRule( context, callee );
    assert( pInvRule );

    auto signature = pInvRule->getSignature( callee );
    assert( signature );

    auto result = Decompose( *signature,
        Vec(
            Val< pvec >(),
            SubTerm()
        )
    );

    assert( result );

    auto&& [params,rt] = *result;
    const auto& rtype = rt;

    bool success = false;

    m_trie = m_trie->merge( *params, [&]( auto&& rtTrie )
    {
        return Merge( rtTrie, rtype, [&]( auto&& previous ) -> Overload
        {
            if( previous.callee )
                return move( previous );

            success = true;
            return { pInvRule, callee };
        } );
    } );

    return success;
}

OverloadSet::UniGen OverloadSet::unify( const Term& argsPat, const Term& rtPat, UnificationContext& uc ) const
{
    auto argDecomp = Decompose( argsPat,
        Val< pvec >()
    );
Changes to bs/builtins/types/overloadset/overloadset.h.
10
11
12
13
14
15
16






17
18
19
20
21
22
23
24
25
26
27


28
29
30
31
32
33
34
        public:
            struct Overload
            {
                ptr< InvocationRule > pInvRule;
                optional< Value > callee;
            };







            void add( const sema::Context& context, const Value& callee );

            using UniGen = Generator< tuple<
                Term,
                const Overload&,
                UnificationContext
            > >;

            UniGen unify( const Term& argsPat, const Term& rtPat, UnificationContext& uc ) const;

        private:


            using utrie_type = UTrie< Trie< Overload > >;
            ptr< utrie_type > m_trie = make_shared< utrie_type >();
    };

    extern bool IsOverloadSet( const Value& os );
}








>
>
>
>
>
>
|










>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
        public:
            struct Overload
            {
                ptr< InvocationRule > pInvRule;
                optional< Value > callee;
            };

            OverloadSet( const StringId& name ) :
                m_name( name )
            {}

            const auto& name() const { return m_name; }

            bool add( const sema::Context& context, const Value& callee );

            using UniGen = Generator< tuple<
                Term,
                const Overload&,
                UnificationContext
            > >;

            UniGen unify( const Term& argsPat, const Term& rtPat, UnificationContext& uc ) const;

        private:
            StringId m_name;

            using utrie_type = UTrie< Trie< Overload > >;
            ptr< utrie_type > m_trie = make_shared< utrie_type >();
    };

    extern bool IsOverloadSet( const Value& os );
}

Changes to bs/builtins/types/template/invoke.cpp.
19
20
21
22
23
24
25

26
27
28
29
30
31
32
                UnificationContext uc( env );

                optional< UnificationContext > bestUC;
                optional< Term > bestSol;
                bool ambiguous = false;

                auto callPat = TVEC( args.val(), sema::MkHole( "_"_sid ) );

                for( auto&& [s, uc] : Unify( tf->signature(), callPat, uc ) )
                {
                    if( uc.numUnknownValues() )
                        continue;

                    if( !bestSol || uc.score() > bestUC->score() )
                    {







>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
                UnificationContext uc( env );

                optional< UnificationContext > bestUC;
                optional< Term > bestSol;
                bool ambiguous = false;

                auto callPat = TVEC( args.val(), sema::MkHole( "_"_sid ) );

                for( auto&& [s, uc] : Unify( tf->signature(), callPat, uc ) )
                {
                    if( uc.numUnknownValues() )
                        continue;

                    if( !bestSol || uc.score() > bestUC->score() )
                    {
Changes to bs/builtins/types/template/tfunc.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"

using namespace empathy::builtins;
using namespace empathy::parse;

namespace empathy::ir
{
    const Term& Bridge< TFunc >::Type( const builtins::TFunc& tf )
    {
        static auto type = ValueToIRExpr( ::ToValue( tf.type() ) );
        return type;
    }

    Value Bridge< TFunc >::ToValue( const TFunc& tf )
    {
        return Value( Type( tf ), TVEC( tf.signature(), tf.identity(),
            TERM( static_pointer_cast< void >( tf.toks() ) ) ) );
    }









|

|
<







1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"

using namespace empathy::builtins;
using namespace empathy::parse;

namespace empathy::ir
{
    Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
    {
        return ValueToIRExpr( ::ToValue( tf.type() ) );

    }

    Value Bridge< TFunc >::ToValue( const TFunc& tf )
    {
        return Value( Type( tf ), TVEC( tf.signature(), tf.identity(),
            TERM( static_pointer_cast< void >( tf.toks() ) ) ) );
    }
Changes to bs/builtins/types/template/tfunc.h.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
}

namespace empathy::ir
{
    template<>
    struct Bridge< builtins::TFunc >
    {
        static const Term& Type( const builtins::TFunc& tf );
        static Value ToValue( const builtins::TFunc& tf );
        static optional< builtins::TFunc > FromValue( const Value& v );
    };
}

#endif







|






30
31
32
33
34
35
36
37
38
39
40
41
42
43
}

namespace empathy::ir
{
    template<>
    struct Bridge< builtins::TFunc >
    {
        static Term Type( const builtins::TFunc& tf );
        static Value ToValue( const builtins::TFunc& tf );
        static optional< builtins::TFunc > FromValue( const Value& v );
    };
}

#endif
Changes to bs/parse/CMakeLists.txt.
1
2
3
4
5
6
7

8
9
10
11
12
13
14
add_library( empathy-parse
    resolver.cpp
    parser.cpp
    rule-helpers.cpp
    blocks.cpp
    func.cpp
    tfunc.cpp

)

target_link_libraries( empathy-parse
    empathy-lex
    empathy-sema
    empathy-builtins
)







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
add_library( empathy-parse
    resolver.cpp
    parser.cpp
    rule-helpers.cpp
    blocks.cpp
    func.cpp
    tfunc.cpp
    overload.cpp
)

target_link_libraries( empathy-parse
    empathy-lex
    empathy-sema
    empathy-builtins
)
Changes to bs/parse/func.cpp.
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

    const auto& c = m_resolver->context();
    auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >();
    pOvlSet->add( c, *func );

    c.env()->storeValue( funcValIdentity, ANYTERM( c ),
        ValueToIRExpr( ToValue( pOvlSet ) ) );

    return true;
}







|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

    const auto& c = m_resolver->context();
    auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >( d->name() );
    pOvlSet->add( c, *func );

    c.env()->storeValue( funcValIdentity, ANYTERM( c ),
        ValueToIRExpr( ToValue( pOvlSet ) ) );

    return true;
}
Added bs/parse/overload.cpp.








































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"

using namespace empathy;
using namespace empathy::parse;
using namespace empathy::builtins;

optional< uint32_t > Parser::getInfixOverloadSetPrecedence()
{
    if( isInParenExpr() )
        return nullopt;

    auto next = m_resolver->lookAheadUnresolved( 1 );
    if( !next )
        return nullopt;

    auto decomp = Decompose( *next, Val< Delimiter >() );
    if( !decomp || *decomp != Delimiter::OpenParen )
        return nullopt;

    return precedence::Application;
}

bool Parser::parseInfixOverloadSet( const ptr< builtins::OverloadSet >& pOvlSet, uint32_t prec )
{
    auto rt = *pop();
    m_resolver->consume();

    auto params = parseParenBlock( Delimiter::OpenParen );
    if( !params )
        return false;

    optional< Value > func;

    if( rt.type() == TSID( type ) )
        func = parseFunctionDeclaration( pOvlSet->name(), rt, *params );
    else if( IsTExpr( rt ) )
        func = parseTemplateFunction( pOvlSet->name(), rt, *params );

    if( !func )
        return false;

    const auto& c = m_resolver->context();
    if( !pOvlSet->add( c, *func ) )
    {
        cout << "error: duplicate function overload\n";
        return false;
    }

    return true;
}
Changes to bs/parse/parser.cpp.
166
167
168
169
170
171
172



173
174
175
176
177
178
179
}

optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
    auto val = ValueFromIRExpr( t );
    if( !val )
        return nullopt;




    // If the term is an infix rule value, invoke its getPrecedence() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
        return nullopt;

    if( !rule->isInfix() )







>
>
>







166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
}

optional< uint32_t > Parser::getPrecedence( const Term& t, const pvec& vec )
{
    auto val = ValueFromIRExpr( t );
    if( !val )
        return nullopt;

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
        return getInfixOverloadSetPrecedence();

    // If the term is an infix rule value, invoke its getPrecedence() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
        return nullopt;

    if( !rule->isInfix() )
210
211
212
213
214
215
216



217
218
219
220
221
222
223
224
225
226
227
228
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromIRExpr( t );
    if( !val )
        return false;




    // If the term is an infix rule value, invoke its parseInfix() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
        return false;

    m_resolver->consume();

    if( !rule->isInfix() )
        return false;

    return rule->parseInfix( *this, t, prec );
}







>
>
>












213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromIRExpr( t );
    if( !val )
        return false;

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
        return parseInfixOverloadSet( FromValue< ptr< OverloadSet > >( *val ), prec );

    // If the term is an infix rule value, invoke its parseInfix() function.
    auto rule = FromValue< Rule >( *val );
    if( !rule )
        return false;

    m_resolver->consume();

    if( !rule->isInfix() )
        return false;

    return rule->parseInfix( *this, t, prec );
}
Changes to bs/parse/parser.h.
43
44
45
46
47
48
49





50
51
52
53
54
55
56
            {
                optional< Value > result;
                swap( result, m_lastValue );
                return result;
            }

            optional< Value > result();






        private:
            optional< uint32_t > getPrecedence( const Term& t );
            bool parsePrefix( const Term&, uint32_t precedence );
            bool parseInfix( const Term&, uint32_t precedence );

            // Default getPrecedence overload







>
>
>
>
>







43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
            {
                optional< Value > result;
                swap( result, m_lastValue );
                return result;
            }

            optional< Value > result();

            bool isInParenExpr() const
            {
                return m_introDelimiter && *m_introDelimiter == Delimiter::OpenParen;
            }

        private:
            optional< uint32_t > getPrecedence( const Term& t );
            bool parsePrefix( const Term&, uint32_t precedence );
            bool parseInfix( const Term&, uint32_t precedence );

            // Default getPrecedence overload
99
100
101
102
103
104
105




106
107
108
109
110
111
112
            optional< Value > parseFunctionDeclaration( const StringId& name, const Value& returnType, const Value& params );

            // Template functions
            bool parseTemplateFunctionExpression( const Value& returnType, const Value& params );
            bool parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& params );
            optional< Value > parseTemplateFunction( const StringId& name, const Value& returnType, const Value& params );





            // Resolver to fetch input terms from.
            ptr< Resolver > m_resolver;

            // The sequence under construction.
            ptr< llr::Seq > m_seq;

            // The last value that we have built,







>
>
>
>







104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
            optional< Value > parseFunctionDeclaration( const StringId& name, const Value& returnType, const Value& params );

            // Template functions
            bool parseTemplateFunctionExpression( const Value& returnType, const Value& params );
            bool parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& params );
            optional< Value > parseTemplateFunction( const StringId& name, const Value& returnType, const Value& params );

            // Overloading
            optional< uint32_t > getInfixOverloadSetPrecedence();
            bool parseInfixOverloadSet( const ptr< builtins::OverloadSet >& pOvlSet, uint32_t prec );

            // Resolver to fetch input terms from.
            ptr< Resolver > m_resolver;

            // The sequence under construction.
            ptr< llr::Seq > m_seq;

            // The last value that we have built,
Changes to bs/parse/tfunc.cpp.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

    const auto& c = m_resolver->context();
    auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >();
    pOvlSet->add( c, *tfunc );

    c.env()->storeValue( funcValIdentity, ANYTERM( c ),
        ValueToIRExpr( ToValue( pOvlSet ) ) );

    return true;
}







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

    const auto& c = m_resolver->context();
    auto funcValIdentity = AppendToVectorTerm( c.identity(), TERM( d->name() ) );

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >( d->name() );
    pOvlSet->add( c, *tfunc );

    c.env()->storeValue( funcValIdentity, ANYTERM( c ),
        ValueToIRExpr( ToValue( pOvlSet ) ) );

    return true;
}
Changes to lib/empathy.em.
1
2
3
4
5
6
7
8
9
10


11




12



13
14

15

16





17

18


19





20
21





22

23

24
25




26
27
28

29










30





31







// Front-end. This is the interpreted code entry point, directly
// executed by the empathy command.
//
// This will setup the prelude and drive the compilation
// process (through function calls exposed by empathy).

// For now it's just a playground to dump test code.

void gg( $T $meh, $T wut )
{


    huh( $meh )




    huh( wut )



}


void huh( ct_string s )

{





    Print( "-------" )

    Print( s )


    Print( s )





    Print( "-------" )
}







Print("fuck")

gg( Args(), "GGGGG" )





using blah = meh
using meh = Args()


Print( "aa" );










Print( blah )





Print("ccc")















|

>
>
|
>
>
>
>
|
>
>
>


>
|
>
|
>
>
>
>
>
|
>
|
>
>
|
>
>
>
>
>
|

>
>
>
>
>

>
|
>
|

>
>
>
>
|
|
|
>
|
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
|
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Front-end. This is the interpreted code entry point, directly
// executed by the empathy command.
//
// This will setup the prelude and drive the compilation
// process (through function calls exposed by empathy).

// For now it's just a playground to dump test code.

void testTmpl( ct_string foo )
{
    Print( foo );
}

void testTmpl( $T foo )
{
    Print( "whatever" )
}

void testTmpl( ct_int foo )
{
    Print( "integer" )
}

testTmpl( 123 )

testTmpl( "Test2" )

// TODO: The following call ought to print "whatever", but
// the value of Print fails to unify because it contains the function's signature, whose holes
// are left unresolved. The signature pattern should really not be stored in the type, but along with
// the function's body, like for templates.
// testTmpl( Print )

///////////////////////////////////////////////

void test( $T a, $U b )
{
    Print( "different types" )
}


void test( $T a, $T b )
{
    Print( "same types" )
}

test(1,2)
test("a", "b")
test(1,"a")
test("b",45)

///////////////////////////////////////////////


using args = Args()

void testFunc()
{
    Print( "testFunc: overload 1" )
}

void testFunc( ct_string foo )
{
    Print( "testFunc: overload 2" )
    Print( foo )
}

void testFunc( ct_int foo )
{
    Print( "testFunc: overload 3" )
}

void testFunc( ct_int foo, ct_string bar )
{
    Print( "testFunc: overload 4" )
    Print( bar )
}

void testFunc( ct_string foo, ct_int bar )
{
    Print( "testFunc: overload 5" )
    Print( foo )
}

testFunc( "gg" )
testFunc()
testFunc( 1234 )
testFunc( 12347, args )
testFunc( "meh", 878787 )