Goose  Check-in [5fd301c5f9]

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

Overview
Comment:Parser: refactored function and template function parsing to go through a common code path to build function types.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 5fd301c5f90f3d50a354c8a396c09fb706739c7890a879c28dd253059636cd62
User & Date: achavasse 2019-07-07 10:33:19.908
Context
2019-07-07
16:22
Parser: parse function type modifiers. check-in: 105ba83ebf user: achavasse tags: trunk
10:33
Parser: refactored function and template function parsing to go through a common code path to build function types. check-in: 5fd301c5f9 user: achavasse tags: trunk
2019-07-06
13:27
Cleanup: remove a superfluous argument from BuildFunc(). check-in: f0724b61e5 user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/types/func/build.cpp.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
            return true;
        } );

        return FuncType( domain, ValueToIRExpr( returnType ),
            TERM( make_shared< Vector >( tvt.persistent(), false ) ) );
    }

    Value BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& params, const pvec& unparsedBody, Context& out_bodyContext )
    {
        auto funcType = BuildFuncType( domain, returnType, params );
        return BuildFunc( c, funcType, funcIdentity, params, unparsedBody, out_bodyContext );
    }

    Value BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& params, const pvec& unparsedBody, Context& out_bodyContext )
    {
        // TODO: instead of a normal import rule, we should use a custom visibility
        // rule that deals with variables from the parent context in a special way:
        // If the function body tries to access variables from the parent function,
        // we should invoke an overridable global function that can transform both the
        // variable object and the function type. This way, we can implement/customize
        // smart lexical captures from inside the language itself (and at a minimum, have







|

|
|


|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
            return true;
        } );

        return FuncType( domain, ValueToIRExpr( returnType ),
            TERM( make_shared< Vector >( tvt.persistent(), false ) ) );
    }

    Value BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const pvec& unparsedBody, Context& out_bodyContext )
    {
        auto funcType = BuildFuncType( domain, returnType, paramsDecl );
        return BuildFunc( c, funcType, funcIdentity, paramsDecl, unparsedBody, out_bodyContext );
    }

    Value BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& paramsDecl, const pvec& unparsedBody, Context& out_bodyContext )
    {
        // TODO: instead of a normal import rule, we should use a custom visibility
        // rule that deals with variables from the parent context in a special way:
        // If the function body tries to access variables from the parent function,
        // we should invoke an overridable global function that can transform both the
        // variable object and the function type. This way, we can implement/customize
        // smart lexical captures from inside the language itself (and at a minimum, have
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        c.env()->addTransitiveImport(
            InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ),
            InjectDomainIntoIdentity( identity, ANYTERM( domain2 ) ) );

        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        vector< uint32_t > paramVarIds;
        paramVarIds.reserve( TupleSize( params ) );

        ForEachInTuple( params, [&]( auto&& param )
        {
            if( !IsDecl( param ) )
            {
                paramVarIds.emplace_back( llr::InvalidVarId );
                return true;
            }








|

|







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
        c.env()->addTransitiveImport(
            InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ),
            InjectDomainIntoIdentity( identity, ANYTERM( domain2 ) ) );

        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        vector< uint32_t > paramVarIds;
        paramVarIds.reserve( TupleSize( paramsDecl ) );

        ForEachInTuple( paramsDecl, [&]( auto&& param )
        {
            if( !IsDecl( param ) )
            {
                paramVarIds.emplace_back( llr::InvalidVarId );
                return true;
            }

Changes to bs/builtins/types/func/build.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef EMPATHY_BUILTINS_FUNC_BUILD_H
#define EMPATHY_BUILTINS_FUNC_BUILD_H

namespace empathy::builtins
{
    extern FuncType BuildFuncType( const Term& domain, const Value& returnType, const Value& params );

    extern Value BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& params, const pvec& unparsedBody, Context& out_bodyContext );
    extern Value BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& params, const pvec& unparsedBody,
        Context& out_bodyContext );

    extern Term BuildCallPatternFromFuncType( const Value& funcType );
}

#endif







|
|






1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef EMPATHY_BUILTINS_FUNC_BUILD_H
#define EMPATHY_BUILTINS_FUNC_BUILD_H

namespace empathy::builtins
{
    extern FuncType BuildFuncType( const Term& domain, const Value& returnType, const Value& params );

    extern Value BuildFunc( const Context& c, const Term& funcIdentity, const Term& domain, const Value& returnType, const Value& paramsDecl, const pvec& unparsedBody, Context& out_bodyContext );
    extern Value BuildFunc( const Context& c, const FuncType& funcType, const Term& funcIdentity, const Value& paramsDecl, const pvec& unparsedBody,
        Context& out_bodyContext );

    extern Term BuildCallPatternFromFuncType( const Value& funcType );
}

#endif
Changes to bs/builtins/types/template/build.cpp.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

        return TVEC(
            tft.domain(),
            TERM( make_shared< Vector >( vt.persistent(), false ) ),
            *rtSig );
    }

    optional< Value > BuildTFunc( const Context& c, const Term& identity, const Term& domain, const Value& returnType, const Value& params, pvec&& body )
    {
        auto funcType = BuildTFuncType( domain, returnType, params );

        auto sig = BuildTFuncSignature( c, funcType );
        if( !sig )
            return nullopt;

        return ToValue( TFunc( move( funcType ), *sig, identity, move( body ) ) );
    }

    optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType )
    {
        const auto& ftype = FromValue< TFuncType >( tfuncType );
        assert( ftype );








|

<
<
|



|







57
58
59
60
61
62
63
64
65


66
67
68
69
70
71
72
73
74
75
76
77

        return TVEC(
            tft.domain(),
            TERM( make_shared< Vector >( vt.persistent(), false ) ),
            *rtSig );
    }

    optional< Value > BuildTFunc( const Context& c, const TFuncType& tft, const Term& identity, const Value& params, pvec&& body )
    {


        auto sig = BuildTFuncSignature( c, tft );
        if( !sig )
            return nullopt;

        return ToValue( TFunc( tft, *sig, identity, move( body ) ) );
    }

    optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType )
    {
        const auto& ftype = FromValue< TFuncType >( tfuncType );
        assert( ftype );

Changes to bs/builtins/types/template/build.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef EMPATHY_BUILTINS_TEMPLATE_BUILD_H
#define EMPATHY_BUILTINS_TEMPLATE_BUILD_H

namespace empathy::builtins
{
    extern optional< TDecl > BuildTDecl( const Context& c, const Term& typeTExpr, const StringId& name );
    extern TFuncType BuildTFuncType( const Term& domain, const Value& returnType, const Value& params );
    extern optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft );
    extern optional< Value > BuildTFunc( const Context& c, const Term& identity, const Term& domain, const Value& returnType, const Value& params, pvec&& body );

    extern optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType );
}

#endif








|





1
2
3
4
5
6
7
8
9
10
11
12
13
14
#ifndef EMPATHY_BUILTINS_TEMPLATE_BUILD_H
#define EMPATHY_BUILTINS_TEMPLATE_BUILD_H

namespace empathy::builtins
{
    extern optional< TDecl > BuildTDecl( const Context& c, const Term& typeTExpr, const StringId& name );
    extern TFuncType BuildTFuncType( const Term& domain, const Value& returnType, const Value& params );
    extern optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft );
    extern optional< Value > BuildTFunc( const Context& c, const TFuncType& tft, const Term& identity, const Value& params, pvec&& body );

    extern optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType );
}

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

6
7
8
9
10
11
12
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





>







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

target_link_libraries( empathy-parse
    empathy-lex
Changes to bs/parse/func.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
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

118
119
120
121
122
123
124
125
126
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"

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

bool Parser::parseFunctionExpression( const Value& returnType, const Value& params )
{
    // Check if the params are valid, and whether they might actually be template params.
    switch( CheckParamListKind( params ) )
    {
        case ParamListKind::Invalid:
            cout << "function expression: invalid param list.\n";
            return false;

        case ParamListKind::Template:

            return parseTemplateFunctionExpression( returnType, params );

        case ParamListKind::Regular:
            break;
    }

    // Check if a brace block follows, in which case this is a function declaration. Otherwise, it's just a function type.
    auto next = m_resolver->lookAheadUnresolved();
    if( !next )
    {
        // TODO syntax for domain specifier
        pushValue( ToValue( BuildFuncType( DomainCompileTime(), returnType, params ) ) );
        return true;
    }

    auto decomp = Decompose( *next, Val< Delimiter >() );
    if( !decomp || *decomp != Delimiter::OpenBrace )
    {
        // TODO syntax for domain specifier
        pushValue( ToValue( BuildFuncType( DomainCompileTime(), returnType, params ) ) );
        return true;
    }

    return parseFunctionDeclExpr( returnType, params );
}

bool Parser::parseFunctionDeclExpr( const Value& returnType, const Value& params )
{


    auto pBody = getFuncBody();
    if( !pBody )
        return false;

    const auto& c = m_resolver->context();
    auto identity = AppendToVectorTerm( c.identity(), TERM( StringId( m_resolver->context().env()->GetUniqueId() ) ) );

    auto bodyContext = m_resolver->context();
    // TODO syntax for domain specifier
    auto func = BuildFunc( m_resolver->context(),
        identity, DomainCompileTime(), returnType, params, move( pBody ), bodyContext );

    if( !CompileFunc( c, func ) )
        return false;

    pushValue( move( func ) );
    return true;
}

bool Parser::parseFunctionDeclaration( const Value& decl, const Value& params )
{
    auto d = FromValue< Decl >( decl );




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

    // We want all functions to always be visible in the compile time domain, so we can retrieve
    // them when they are not present in other domains. OverloadSets themselves should only
    // live in the CompileTime domain as well. This is why we set the function identity's domain to CompileTime.
    funcIdentity = InjectDomainIntoIdentity( funcIdentity, DomainCompileTime() );

    auto func = parseFunctionDeclaration( funcIdentity, *ValueFromIRExpr( d->type() ), params );
    if( !func )
        return false;

    // 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 >( funcIdentity );
    pOvlSet->add( c, *func );

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

    return true;
}

optional< Value > Parser::parseFunctionDeclaration( const Term& identity, const Value& returnType, const Value& params )
{
    // Check if the params are valid, and whether they might actually be template params.
    switch( CheckParamListKind( params ) )
    {
        case ParamListKind::Invalid:
            cout << "function declaration: invalid param list.\n";
            return nullopt;

        case ParamListKind::Template:
            return parseTemplateFunction( identity, returnType, params );

        case ParamListKind::Regular:
            break;
    }

    auto pBody = getFuncBody();
    if( !pBody )
        return nullopt;

    auto& c = m_resolver->context();

    auto bodyContext = c;


    // TODO syntax for domain specifier
    return BuildFunc( c, identity, DomainCompileTime(), returnType, params, move( pBody ), bodyContext );
}

pvec Parser::getFuncBody()
{
    auto next = m_resolver->lookAheadUnresolved();
    if( !next )
    {








|

<
<
<
|
<
|

<
>
|
<
<
<
<





|
<






|
<



|


|

>
>








|
|
|








|


>
>
>









|















|

<
<
<
<
<
<
|
<
|
<
<
<
<






<


>
|
|







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
90






91

92




93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"

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

bool Parser::parseFunctionExpression( const Value& returnType, const Value& paramsDecl )
{



    if( !parseFuncType( returnType, paramsDecl ) )

        return false;


    if( IsTExpr( *peekLastValue() ) )
        return parseTemplateFunctionExpression( paramsDecl );





    // Check if a brace block follows, in which case this is a function declaration. Otherwise, it's just a function type.
    auto next = m_resolver->lookAheadUnresolved();
    if( !next )
    {
        // Just leave the type as is, nothing to do.

        return true;
    }

    auto decomp = Decompose( *next, Val< Delimiter >() );
    if( !decomp || *decomp != Delimiter::OpenBrace )
    {
        // Just leave the type as is, nothing to do.

        return true;
    }

    return parseFunctionDeclExpr( paramsDecl );
}

bool Parser::parseFunctionDeclExpr( const Value& paramsDecl )
{
    auto funcType = *FromValue< FuncType >( *popValue() );

    auto pBody = getFuncBody();
    if( !pBody )
        return false;

    const auto& c = m_resolver->context();
    auto identity = AppendToVectorTerm( c.identity(), TERM( StringId( m_resolver->context().env()->GetUniqueId() ) ) );

    auto bodyContext = m_resolver->context();

    auto func = BuildFunc( m_resolver->context(), funcType,
        identity, paramsDecl, move( pBody ), bodyContext );

    if( !CompileFunc( c, func ) )
        return false;

    pushValue( move( func ) );
    return true;
}

bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
    auto d = FromValue< Decl >( decl );

    if( !parseFuncType( *ValueFromIRExpr( d->type() ), paramsDecl ) )
        return false;

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

    // We want all functions to always be visible in the compile time domain, so we can retrieve
    // them when they are not present in other domains. OverloadSets themselves should only
    // live in the CompileTime domain as well. This is why we set the function identity's domain to CompileTime.
    funcIdentity = InjectDomainIntoIdentity( funcIdentity, DomainCompileTime() );

    auto func = parseFunctionDeclaration( funcIdentity, paramsDecl );
    if( !func )
        return false;

    // 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 >( funcIdentity );
    pOvlSet->add( c, *func );

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

    return true;
}

optional< Value > Parser::parseFunctionDeclaration( const Term& identity, const Value& paramsDecl )
{






    if( IsTExpr( *peekLastValue() ) )

        return parseTemplateFunction( identity, paramsDecl );





    auto pBody = getFuncBody();
    if( !pBody )
        return nullopt;

    auto& c = m_resolver->context();

    auto bodyContext = c;

    auto funcType = *FromValue< FuncType >( *popValue() );

    return BuildFunc( c, funcType, identity, paramsDecl, move( pBody ), bodyContext );
}

pvec Parser::getFuncBody()
{
    auto next = m_resolver->lookAheadUnresolved();
    if( !next )
    {
Added bs/parse/functype.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
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"

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

bool Parser::parseFuncType( const Value& returnType, const Value& paramsDecl )
{
    // Check if the params are valid, and whether they might actually be template params.
    switch( CheckParamListKind( paramsDecl ) )
    {
        case ParamListKind::Invalid:
            cout << "function expression: invalid param list.\n";
            return false;

        case ParamListKind::Template:
            pushValue( ToValue( BuildTFuncType( DomainCompileTime(), returnType, paramsDecl ) ) );
            break;

        case ParamListKind::Regular:
            pushValue( ToValue( BuildFuncType( DomainCompileTime(), returnType, paramsDecl ) ) );
            break;
    }

    // TODO recursive parsing call to handle modifiers such as domain specifiers

    return true;
}

bool Parser::parseTFuncType( const Value& returnType, const Value& paramsDecl )
{
    pushValue( ToValue( BuildTFuncType( DomainCompileTime(), returnType, paramsDecl ) ) );

    // TODO recursive parsing call to handle modifiers such as domain specifiers

    return true;
}
Changes to bs/parse/overload.cpp.
23
24
25
26
27
28
29
30
31



32
33
34
35
36
37
38
39


40
41
42
43
44
45
46
}

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

    auto params = parseParenBlock();
    if( !params )



        return false;

    optional< Value > func;

    if( rt.isType() )
        func = parseFunctionDeclaration( pOvlSet->identity(), rt, *params );
    else if( IsTExpr( rt ) )
        func = parseTemplateFunction( pOvlSet->identity(), rt, *params );



    if( !func )
        return false;

    const auto& c = m_resolver->context();
    if( !pOvlSet->add( c, *func ) )
    {







|
|
>
>
>




<
<
|
|
>
>







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
}

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

    auto paramsDecl = parseParenBlock();
    if( !paramsDecl )
        return false;

    if( !parseFuncType( rt, *paramsDecl ) )
        return false;

    optional< Value > func;



    if( IsTExpr( *peekLastValue() ) )
        func = parseTemplateFunction( pOvlSet->identity(), *paramsDecl );
    else
        func = parseFunctionDeclaration( pOvlSet->identity(), *paramsDecl );

    if( !func )
        return false;

    const auto& c = m_resolver->context();
    if( !pOvlSet->add( c, *func ) )
    {
Changes to bs/parse/parser.h.
108
109
110
111
112
113
114



115
116
117
118
119
120
121
122

123
124
125
126
127
128
129
130
131
            optional< Value > parseParenBlock();

            optional< uint32_t > getPostfixParenBlockPrecedence();
            bool parsePostfixParenBlock( uint32_t prec );

            bool parseBraceBlock();




            // Functions
            bool parseFunctionExpression( const Value& returnType, const Value& params );
            bool parseFunctionDeclExpr( const Value& returnType, const Value& params );
            bool parseFunctionDeclaration( const Value& decl, const Value& params );
            optional< Value > parseFunctionDeclaration( const Term& identity, 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 Term& identity, 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;







>
>
>

|
|
|
|


|
>
|
|







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
            optional< Value > parseParenBlock();

            optional< uint32_t > getPostfixParenBlockPrecedence();
            bool parsePostfixParenBlock( uint32_t prec );

            bool parseBraceBlock();

            bool parseFuncType( const Value& returnType, const Value& paramsDecl );
            bool parseTFuncType( const Value& returnType, const Value& paramsDecl );

            // Functions
            bool parseFunctionExpression( const Value& returnType, const Value& paramsDecl );
            bool parseFunctionDeclExpr( const Value& paramsDecl );
            bool parseFunctionDeclaration( const Value& decl, const Value& paramsDecl );
            optional< Value > parseFunctionDeclaration( const Term& identity, const Value& paramsDecl );

            // Template functions
            bool parseTemplateFunctionExpression( const Value& returnType, const Value& paramsDecl );
            bool parseTemplateFunctionExpression( const Value& paramsDecl );
            bool parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl );
            optional< Value > parseTemplateFunction( const Term& identity, const Value& paramsDecl );

            // 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;
Changes to bs/parse/tfunc.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
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
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"

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

bool Parser::parseTemplateFunctionExpression( const Value& returnType, const Value& params )
{
    // Check if the params are valid
    if( CheckParamListKind( params ) == ParamListKind::Invalid )
    {
        cout << "function template expression: invalid param list.\n";
        return false;
    }



    // Check if a brace block follows, in which case this is a function declaration. Otherwise, it's just a function type.
    auto next = m_resolver->lookAheadUnresolved();
    if( !next )
    {
        // TODO syntax for domain specifier
        pushValue( ToValue( BuildTFuncType( DomainCompileTime(), returnType, params ) ) );
        return true;
    }

    auto decomp = Decompose( *next, Val< Delimiter >() );
    if( !decomp || *decomp != Delimiter::OpenBrace )
    {
        // TODO syntax for domain specifier
        pushValue( ToValue( BuildTFuncType( DomainCompileTime(), returnType, params ) ) );
        return true;
    }

    const auto& c = m_resolver->context();
    auto tfuncIdentity = AppendToVectorTerm( c.identity(),
        TERM( StringId( m_resolver->context().env()->GetUniqueId() ) ) );

    auto tfunc = parseTemplateFunction( tfuncIdentity,
        returnType, params );

    if( !tfunc )
        return false;

    pushValue( *tfunc );
    return true;
}

bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& params )
{
    auto d = FromValue< TNamedDecl >( tnamedDecl );




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

    // We want all functions to always be visible in the compile time domain, so we can retrieve
    // them when they are not present in other domains. OverloadSets themselves should only
    // live in the CompileTime domain as well. This is why we set the function identity's domain to CompileTime.
    tfuncIdentity = InjectDomainIntoIdentity( tfuncIdentity, DomainCompileTime() );

    auto tfunc = parseTemplateFunction( tfuncIdentity, *ValueFromIRExpr( d->type() ), params );
    if( !tfunc )
        return false;

    // 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 >( tfuncIdentity );
    pOvlSet->add( c, *tfunc );

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

    return true;
}

optional< Value > Parser::parseTemplateFunction( const Term& identity, const Value& returnType, const Value& params )
{
    auto pBody = getFuncBody();
    if( !pBody )
        return nullopt;

    auto& c = m_resolver->context();


    // TODO syntax for domain specifier
    return BuildTFunc( c, identity, DomainCompileTime(), returnType, params, move( pBody ) );
}








|

|
|
|
<
|
|

>
>




|
<






|
<







|
<








|


>
>
>









|















|






>


|

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
#include "parse.h"
#include "builtins/builtins.h"
#include "precedence.h"

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

bool Parser::parseTemplateFunctionExpression( const Value& returnType, const Value& paramsDecl )
{
    if( !parseTFuncType( returnType, paramsDecl ) )
        return false;


    return parseTemplateFunctionExpression( paramsDecl );
}

bool Parser::parseTemplateFunctionExpression( const Value& paramsDecl )
{
    // Check if a brace block follows, in which case this is a function declaration. Otherwise, it's just a function type.
    auto next = m_resolver->lookAheadUnresolved();
    if( !next )
    {
        // Just leave the type as is, nothing to do.

        return true;
    }

    auto decomp = Decompose( *next, Val< Delimiter >() );
    if( !decomp || *decomp != Delimiter::OpenBrace )
    {
        // Just leave the type as is, nothing to do.

        return true;
    }

    const auto& c = m_resolver->context();
    auto tfuncIdentity = AppendToVectorTerm( c.identity(),
        TERM( StringId( m_resolver->context().env()->GetUniqueId() ) ) );

    auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );


    if( !tfunc )
        return false;

    pushValue( *tfunc );
    return true;
}

bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
    auto d = FromValue< TNamedDecl >( tnamedDecl );

    if( !parseTFuncType( *ValueFromIRExpr( d->type() ), paramsDecl ) )
        return false;

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

    // We want all functions to always be visible in the compile time domain, so we can retrieve
    // them when they are not present in other domains. OverloadSets themselves should only
    // live in the CompileTime domain as well. This is why we set the function identity's domain to CompileTime.
    tfuncIdentity = InjectDomainIntoIdentity( tfuncIdentity, DomainCompileTime() );

    auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );
    if( !tfunc )
        return false;

    // 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 >( tfuncIdentity );
    pOvlSet->add( c, *tfunc );

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

    return true;
}

optional< Value > Parser::parseTemplateFunction( const Term& identity, const Value& paramsDecl )
{
    auto pBody = getFuncBody();
    if( !pBody )
        return nullopt;

    auto& c = m_resolver->context();
    auto tFuncType = *FromValue< TFuncType >( *popValue() );

    // TODO syntax for domain specifier
    return BuildTFunc( c, tFuncType, identity, paramsDecl, move( pBody ) );
}