Goose  Check-in [a742f106d4]

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

Overview
Comment:
  • ir: terms can now contain a pointer to another term, for situations where a mutable terms needs to be shared by multiple expressions.
  • func: use a term pointer to store the function's content, so that we can distinguish a not-yet-parsed function from a non evaluated function value.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: a742f106d4f93d7e70c5bf3d667d92852d9c17f86a94a38607b4cf3d35e77f53
User & Date: achavasse 2019-03-23 13:08:49.415
Context
2019-03-23
13:45
Higher order functions: some fixes and cleanup, the simplest case (lambda function passed as parameter for a matching function type) works. check-in: 152d39532f user: achavasse tags: trunk
13:08
  • ir: terms can now contain a pointer to another term, for situations where a mutable terms needs to be shared by multiple expressions.
  • func: use a term pointer to store the function's content, so that we can distinguish a not-yet-parsed function from a non evaluated function value.
check-in: a742f106d4 user: achavasse tags: trunk
2019-03-22
21:42
Func: finally abandon the Term type which adds too much overhead and can be lived without, but instead store the signature directly as the param types, inside of the function type. check-in: 0618ab859e user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/CMakeLists.txt.
28
29
30
31
32
33
34

35
36
37
    operators/colon.cpp

    statements/using.cpp
)

target_link_libraries( empathy-builtins
    empathy-ir

    empathy-sema
    empathy-parse
)







>



28
29
30
31
32
33
34
35
36
37
38
    operators/colon.cpp

    statements/using.cpp
)

target_link_libraries( empathy-builtins
    empathy-ir
    empathy-llr
    empathy-sema
    empathy-parse
)
Changes to bs/builtins/builtins.h.
1
2
3
4

5
6
7
8
9
10
11
#ifndef EMPATHY_BUILTINS_H
#define EMPATHY_BUILTINS_H

#include "ir/ir.h"

#include "sema/sema.h"

namespace empathy::builtins
{
    using namespace ir;
    using namespace sema;
}




>







1
2
3
4
5
6
7
8
9
10
11
12
#ifndef EMPATHY_BUILTINS_H
#define EMPATHY_BUILTINS_H

#include "ir/ir.h"
#include "llr/llr.h"
#include "sema/sema.h"

namespace empathy::builtins
{
    using namespace ir;
    using namespace sema;
}
Changes to bs/builtins/statements/using.cpp.
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
            variant< vector< Term >, Term > content = move( toks );

            auto UsingValProvider = [content, localIdentity]( const Context& c, const Term& identity, const Term& contextId, Term& result ) mutable
            {
                if( holds_alternative< vector< Term > >( content ) )
                {
                    Context localContext( c.env(), localIdentity );
                    auto tokProvider = make_shared< lex::VectorAdapter >( get< vector< Term > >( content ) );
                    auto r = make_shared< parse::Resolver >( tokProvider, localContext );
                    Parser p( r );

                    if( !p.parseExpression() )
                    {
                        cout << "invalid using expression.\n";
                        return Env::Status::NoMatch;







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
            variant< vector< Term >, Term > content = move( toks );

            auto UsingValProvider = [content, localIdentity]( const Context& c, const Term& identity, const Term& contextId, Term& result ) mutable
            {
                if( holds_alternative< vector< Term > >( content ) )
                {
                    Context localContext( c.env(), localIdentity );
                    auto tokProvider = lex::MakeVectorAdapter( get< vector< Term > >( content ) );
                    auto r = make_shared< parse::Resolver >( tokProvider, localContext );
                    Parser p( r );

                    if( !p.parseExpression() )
                    {
                        cout << "invalid using expression.\n";
                        return Env::Status::NoMatch;
Changes to bs/builtins/types/func/build.cpp.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
            else if( param.isConstant() )
                tvt.push_back( ValueToIRExpr( param ) );

            return true;
        } );

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

    Value BuildFuncStructureAndContext( const Context& c, const StringId& id, const Value& returnType, const Value& params, Context& out_bodyContext )
    {
        auto funcType = ToValue( BuildFuncType( returnType, params ) );
        auto funcTypeTerm = ValueToIRExpr( funcType );
        auto funcIdentity = AppendToVectorTerm( c.identity(), TERM( id ), funcTypeTerm );







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
            else if( param.isConstant() )
                tvt.push_back( ValueToIRExpr( param ) );

            return true;
        } );

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

    Value BuildFuncStructureAndContext( const Context& c, const StringId& id, const Value& returnType, const Value& params, Context& out_bodyContext )
    {
        auto funcType = ToValue( BuildFuncType( returnType, params ) );
        auto funcTypeTerm = ValueToIRExpr( funcType );
        auto funcIdentity = AppendToVectorTerm( c.identity(), TERM( id ), funcTypeTerm );
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
            c.env()->storeValue( paramIdentity, ANYTERM( c ),
                ValueToIRExpr( Value( decl.type(), make_shared< llr::Element >( llr::GetVar( varId ) ) ) ) );

            return true;
        } );

        out_bodyContext = Context( c.env(), funcIdentity );
        ptr< void > pFuncLLR = make_shared< llr::Func >( funcIdentity, move( paramVarIds ) );

        return Value( ValueToIRExpr( funcType ), TERM( move( pFuncLLR ) ) );



    }

    Value BuildFunc( Value&& funcStructure, const optional< Value >& body )
    {
        const auto& content = funcStructure.val().content();


        const auto& p = get< ptr< void > >( content );





        const auto& pFuncStruct = static_pointer_cast< llr::Func >( p );

        ptr< void > pFuncLLR;

        if( !body || body->isConstant() )
            pFuncLLR = make_shared< llr::Func >( move( pFuncStruct->identity() ), move( pFuncStruct->paramVarIds() ), llr::Element() );
        else
            pFuncLLR = make_shared< llr::Func >( move( pFuncStruct->identity() ), move( pFuncStruct->paramVarIds() ), *body->llr() );

        return Value( move( funcStructure.type() ), TERM( move( pFuncLLR ) ) );
    }

    Value BuildFunc( Value&& funcStructure, vector< Term >&& body )
    {
        const auto& content = funcStructure.val().content();


        const auto& p = get< ptr< void > >( content );





        const auto& pFuncStruct = static_pointer_cast< llr::Func >( p );

        ptr< void > pFuncLLR = make_shared< llr::Func >( move( pFuncStruct->identity() ), move( pFuncStruct->paramVarIds() ), move( body ) );

        return Value( move( funcStructure.type() ), TERM( move( pFuncLLR ) ) );




    }

    Term BuildArgPatternFromFuncType( const Context& c, const Value& funcType )
    {
        const auto& ftype = *FromValue< FuncType >( funcType );

        immer::vector< Term > apv;







|

|
>
>
>




|
>
>
|
>
>
>
>
>
|




|

|

|


|

|
>
>
|
>
>
>
>
>
|

|

|
>
>
>
>







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
127
128
129
130
131
132
133
134
135
136
            c.env()->storeValue( paramIdentity, ANYTERM( c ),
                ValueToIRExpr( Value( decl.type(), make_shared< llr::Element >( llr::GetVar( varId ) ) ) ) );

            return true;
        } );

        out_bodyContext = Context( c.env(), funcIdentity );
        ptr< void > pFuncLLR = make_shared< llr::Func >( move( paramVarIds ) );

        return Value( ValueToIRExpr( funcType ), TVEC(
            move( funcIdentity ),
            TERM( move( pFuncLLR ) )
        ) );
    }

    Value BuildFunc( Value&& funcStructure, const optional< Value >& body )
    {
        auto decomp = Decompose( funcStructure.val(),
            Vec(
                SubTerm(),              // identity
                Val< ptr< void > >()    // llr
            )
        );
        assert( decomp );
        auto&& [identity,pLLR] = *decomp;

        const auto& pFuncStruct = static_pointer_cast< llr::Func >( pLLR );

        ptr< void > pFuncLLR;

        if( !body || body->isConstant() )
            pFuncLLR = make_shared< llr::Func >( move( pFuncStruct->paramVarIds() ), llr::Element() );
        else
            pFuncLLR = make_shared< llr::Func >( move( pFuncStruct->paramVarIds() ), *body->llr() );

        return Value( move( funcStructure.type() ), PTERM( move( pFuncLLR ) ) );
    }

    Value BuildFunc( Value&& funcStructure, Term&& body )
    {
        auto decomp = Decompose( funcStructure.val(),
            Vec(
                SubTerm(),              // identity
                Val< ptr< void > >()    // llr
            )
        );
        assert( decomp );
        auto&& [identity,pLLR] = *decomp;

        const auto& pFuncStruct = static_pointer_cast< llr::Func >( pLLR );

        ptr< void > pFuncLLR = make_shared< llr::Func >( move( pFuncStruct->paramVarIds() ), llr::Element() );

        return Value( move( funcStructure.type() ), PTERM( Vector::Make(
            move( identity ),
            move( body ),
            TERM( move( pFuncLLR ) )
        ) ) );
    }

    Term BuildArgPatternFromFuncType( const Context& c, const Value& funcType )
    {
        const auto& ftype = *FromValue< FuncType >( funcType );

        immer::vector< Term > apv;
Changes to bs/builtins/types/func/build.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef EMPATHY_BUILTINS_FUNC_BUILD_H
#define EMPATHY_BUILTINS_FUNC_BUILD_H

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

    extern Value BuildFuncStructureAndContext( const Context& c, const StringId& id, const Value& returnType, const Value& params, Context& out_bodyContext );
    extern Value BuildFuncStructureAndContext( const Context& c, const Term& funcIdentity, const Value& returnType, const Value& params, Context& out_bodyContext );
    extern Value BuildFuncStructureAndContext( const Context& c, const Value& funcType, const Term& funcIdentity, const Value& returnType, const Value& params, Context& out_bodyContext );
    extern Value BuildFunc( Value&& funcStructure, const optional< Value >& body );

    // Same as above, but the body is passed as a vector of tokens and will be parsed lazily.
    extern Value BuildFunc( Value&& funcStructure, vector< Term >&& body );

    extern Term BuildArgPatternFromFuncType( const Context& c, const Value& funcType );
}

#endif













|





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

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

    extern Value BuildFuncStructureAndContext( const Context& c, const StringId& id, const Value& returnType, const Value& params, Context& out_bodyContext );
    extern Value BuildFuncStructureAndContext( const Context& c, const Term& funcIdentity, const Value& returnType, const Value& params, Context& out_bodyContext );
    extern Value BuildFuncStructureAndContext( const Context& c, const Value& funcType, const Term& funcIdentity, const Value& returnType, const Value& params, Context& out_bodyContext );
    extern Value BuildFunc( Value&& funcStructure, const optional< Value >& body );

    // Same as above, but the body is passed as a vector of tokens and will be parsed lazily.
    extern Value BuildFunc( Value&& funcStructure, Term&& body );

    extern Term BuildArgPatternFromFuncType( const Context& c, const Value& funcType );
}

#endif
Changes to bs/builtins/types/func/func.cpp.
21
22
23
24
25
26
27










28
29
30
31
32
33
34
            )
        );
        assert( typeDecomp );
        auto&& [kind, rtype, ptypes] = *typeDecomp;

        return { TVEC( *Unquote( ptypes ), rtype ), rtype };
    }











    ParamListKind CheckParamListKind( const Value& tup )
    {
        if( !IsTuple( tup ) )
            return ParamListKind::Invalid;

        auto result = ParamListKind::Regular;







>
>
>
>
>
>
>
>
>
>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
            )
        );
        assert( typeDecomp );
        auto&& [kind, rtype, ptypes] = *typeDecomp;

        return { TVEC( *Unquote( ptypes ), rtype ), rtype };
    }

    ptr< llr::Func > GetFuncLLR( const Value& func )
    {
        auto decomp = Decompose( func.val(),
            PTerm( Val< ptr< void > >() )
        );
        assert( decomp );

        return static_pointer_cast< llr::Func >( *decomp );
    }

    ParamListKind CheckParamListKind( const Value& tup )
    {
        if( !IsTuple( tup ) )
            return ParamListKind::Invalid;

        auto result = ParamListKind::Regular;
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
        }

        return result;
    }

    void PerformLazyFuncParsing( const ptr< Env >& env, const Value& func )
    {


        const auto& content = func.val().content();





        const auto& pLLR = get< ptr< void > >( content );
        const auto& pFunc = static_pointer_cast< llr::Func >( pLLR );



        const auto* pToks = get_if< vector< Term > >( &pFunc->body() );
        if( !pToks )
            return;





        Context localContext( env, pFunc->identity() );
        auto tokProvider = make_shared< lex::VectorAdapter >( *pToks );
        auto r = make_shared< parse::Resolver >( tokProvider, localContext );
        Parser p( r );




        if( !p.parseExpression() )

            pFunc->body() = llr::Element();



        auto result  = p.result();
        if( !result || result->isConstant() )
            pFunc->body() = llr::Element();
        else
            pFunc->body() = *result->llr();
    }
}

namespace empathy::ir
{
    const Term& Bridge< FuncType >::Type()
    {
        static auto type = TSID( type );
        return type;
    }

    Value Bridge< FuncType >::ToValue( const FuncType& ft )
    {
        return Value( Type(), TVEC( TSID( func ), TSID( regular ),
            ft.returnType(), ft.paramTypes() ) );
    }

    optional< FuncType > Bridge< FuncType >::FromValue( const Value& v )
    {
        auto typeVal = ValueFromIRExpr( v.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "regular"_sid ),
                SubTerm(),  // return type
                SubTerm()  // param types
            )
        );

        if( !result )
            return nullopt;

        auto&& [rtype, params] = *result;
        return FuncType( move( rtype ), move( params ) );
    }
}







>
>
|
>
>
>
>
>
|
<
|
>
>
|
|


>
>
>
>
|
|



>
>
>

>

>
|
>
|


















|


















|


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
127
128
129
130
131
132
133
134
135
136
137
138
        }

        return result;
    }

    void PerformLazyFuncParsing( const ptr< Env >& env, const Value& func )
    {
        if( !func.isConstant() )
            return;

        auto decomp = Decompose( func.val(),
            PTerm(
                Vec(
                    SubTerm(),              // identity
                    Val< pvec >(),          // body toks
                    Val< ptr< void > >()    // llr

                )
            )
        );

        if( !decomp )
            return;

        auto&& [identity,pToks,pLLR] = *decomp;

        const auto& pFunc = static_pointer_cast< llr::Func >( pLLR );

        Context localContext( env, identity );
        auto tokProvider = lex::MakeVectorAdapter( pToks->terms() );
        auto r = make_shared< parse::Resolver >( tokProvider, localContext );
        Parser p( r );

        const auto& pFuncContent = get< ptr< Term > >( func.val().content() );
        *pFuncContent = TERM( pLLR );

        if( !p.parseExpression() )
        {
            pFunc->body() = llr::Element();
            return;
        }

        auto result = p.result();
        if( !result || result->isConstant() )
            pFunc->body() = llr::Element();
        else
            pFunc->body() = *result->llr();
    }
}

namespace empathy::ir
{
    const Term& Bridge< FuncType >::Type()
    {
        static auto type = TSID( type );
        return type;
    }

    Value Bridge< FuncType >::ToValue( const FuncType& ft )
    {
        return Value( Type(), TVEC( TSID( func ), TSID( regular ),
            ft.returnType(), Quote( ft.paramTypes() ) ) );
    }

    optional< FuncType > Bridge< FuncType >::FromValue( const Value& v )
    {
        auto typeVal = ValueFromIRExpr( v.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "regular"_sid ),
                SubTerm(),  // return type
                SubTerm()  // param types
            )
        );

        if( !result )
            return nullopt;

        auto&& [rtype, params] = *result;
        return FuncType( move( rtype ), Quote( params ) );
    }
}
Changes to bs/builtins/types/func/func.h.
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
    enum class ParamListKind
    {
        Regular,
        Template,
        Invalid
    };

    extern pair< Term, Term > GetFuncSigAndRType( const Value& v );


    // Given a tuple, determines whether it is a valid param list, and of which kind.
    extern ParamListKind CheckParamListKind( const Value& tup );

    template< typename F >
    void ForEachDeclInTuple( const Value& tup, F&& func );








|
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    enum class ParamListKind
    {
        Regular,
        Template,
        Invalid
    };

    extern pair< Term, Term > GetFuncSigAndRType( const Value& func );
    extern ptr< llr::Func > GetFuncLLR( const Value& func );

    // Given a tuple, determines whether it is a valid param list, and of which kind.
    extern ParamListKind CheckParamListKind( const Value& tup );

    template< typename F >
    void ForEachDeclInTuple( const Value& tup, F&& func );

Changes to bs/builtins/types/template/instantiate.cpp.
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

                ForEachInVectorTerm( tf->type().params(), [&]( auto&& param )
                {
                    TemplateSetup( bodyContext, uc, param );
                    return true;
                } );

                auto tokProvider = make_shared< lex::VectorAdapter >( *tf->toks() );
                auto r = make_shared< parse::Resolver >( tokProvider, bodyContext );
                Parser p( r );
                if( !p.parseExpression() )
                    return nullopt;

                instanceFunc = BuildFunc( move( funcStruct ), p.result() );
                c.env()->storeValue( instanceIdentity, ANYTERM( c ), ValueToIRExpr( *instanceFunc ) );







|







56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

                ForEachInVectorTerm( tf->type().params(), [&]( auto&& param )
                {
                    TemplateSetup( bodyContext, uc, param );
                    return true;
                } );

                auto tokProvider = lex::MakeVectorAdapter( *tf->toks() );
                auto r = make_shared< parse::Resolver >( tokProvider, bodyContext );
                Parser p( r );
                if( !p.parseExpression() )
                    return nullopt;

                instanceFunc = BuildFunc( move( funcStruct ), p.result() );
                c.env()->storeValue( instanceIdentity, ANYTERM( c ), ValueToIRExpr( *instanceFunc ) );
Changes to bs/execute/vm.cpp.
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
            cout << "Execute: args evaluation failed.\n";
            return nullopt;
        }

        return ExecuteBuiltinFuncCall( *func, TERM( newVec ) );
    }

    const auto& content = func->val().content();
    const auto& p = get< ptr< void > >( content );
    const auto& pFunc = static_pointer_cast< llr::Func >( p );

    const auto* pBody = get_if< Element >( &pFunc->body() );
    if( !pBody )
    {
        cout << "Execute: trying to call an unparsed function.\n";
        return nullopt;
    }

    Frame f;

    const auto& paramVarIds = pFunc->paramVarIds();

    assert( paramVarIds.size() == vec.length().minLength() );
    for( size_t i = 0; i < paramVarIds.size(); ++i )
    {
        if( paramVarIds[i] == llr::InvalidVarId )
            continue;

        auto val = ValueFromIRExpr( vec[i] );
        assert( val );

        auto newVal = Evaluate( *val, *this );
        if( !newVal )
        {
            cout << "Execute: args evaluation failed.\n";
            return nullopt;
        }

        f.setVar( paramVarIds[i], *newVal );
    }

    swap( m_frame, f );
    auto result = execute( *pBody );
    swap( m_frame, f );

    return result;
}

optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
    const auto& f = GetBuiltinFuncWrapper( func );
    return f( args );
}







<
<
|
<
<
<
<
<
<
<
<



>




















|










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
            cout << "Execute: args evaluation failed.\n";
            return nullopt;
        }

        return ExecuteBuiltinFuncCall( *func, TERM( newVec ) );
    }



    const auto& pFunc = GetFuncLLR( *func );








    Frame f;

    const auto& paramVarIds = pFunc->paramVarIds();

    assert( paramVarIds.size() == vec.length().minLength() );
    for( size_t i = 0; i < paramVarIds.size(); ++i )
    {
        if( paramVarIds[i] == llr::InvalidVarId )
            continue;

        auto val = ValueFromIRExpr( vec[i] );
        assert( val );

        auto newVal = Evaluate( *val, *this );
        if( !newVal )
        {
            cout << "Execute: args evaluation failed.\n";
            return nullopt;
        }

        f.setVar( paramVarIds[i], *newVal );
    }

    swap( m_frame, f );
    auto result = execute( pFunc->body() );
    swap( m_frame, f );

    return result;
}

optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
    const auto& f = GetBuiltinFuncWrapper( func );
    return f( args );
}
Changes to bs/ir/CMakeLists.txt.
1

2
3
4
5
6
7
8
add_library( empathy-ir

    tostring.cpp
    merge.cpp
    compare.cpp
    enumerate.cpp
    match.cpp
    graphviz.cpp
    value.cpp

>







1
2
3
4
5
6
7
8
9
add_library( empathy-ir
    term.cpp
    tostring.cpp
    merge.cpp
    compare.cpp
    enumerate.cpp
    match.cpp
    graphviz.cpp
    value.cpp
Changes to bs/ir/decompose.h.
25
26
27
28
29
30
31
















32
33
34
35
36
37
38
    };

    struct SubTerm
    {
        using return_type = Term;
    };

















    template< typename... T >
    struct VecDecompositionReturnTypeBuilder
    {};

    template< typename... TU >
    struct VecDecompositionReturnTypeBuilder< tuple< TU... > >
    {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
    };

    struct SubTerm
    {
        using return_type = Term;
    };

    template< typename S >
    struct PTermSpec
    {
        using return_type = typename S::return_type;

        template< typename T >
        PTermSpec( T&& spec ) :
            m_spec( forward< T >( spec ) )
        {}

        S m_spec;
    };

    template< typename S >
    auto PTerm( S&& spec );

    template< typename... T >
    struct VecDecompositionReturnTypeBuilder
    {};

    template< typename... TU >
    struct VecDecompositionReturnTypeBuilder< tuple< TU... > >
    {
68
69
70
71
72
73
74



75
76
77
78
79
    bool Decompose( const Term& t, const LiteralSpec< T >& spec );

    template< typename T >
    optional< reference_wrapper< const T > > Decompose( const Term& t, const Val< T >& spec );

    static inline const Term& Decompose( const Term& t, const SubTerm& spec );




    template< typename... S >
    optional< typename VectorSpec< S... >::return_type > Decompose( const Term& t, const VectorSpec< S... >& spec );
}

#endif







>
>
>





84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
    bool Decompose( const Term& t, const LiteralSpec< T >& spec );

    template< typename T >
    optional< reference_wrapper< const T > > Decompose( const Term& t, const Val< T >& spec );

    static inline const Term& Decompose( const Term& t, const SubTerm& spec );

    template< typename S >
    optional< typename PTermSpec< S >::return_type > Decompose( const Term& t, const PTermSpec< S >& spec );

    template< typename... S >
    optional< typename VectorSpec< S... >::return_type > Decompose( const Term& t, const VectorSpec< S... >& spec );
}

#endif
Changes to bs/ir/decompose.inl.
1
2
3
4
5
6
7
8
9
10






11
12
13
14
15
16
17
#ifndef EMPATHY_IR_DECOMPOSE_INL
#define EMPATHY_IR_DECOMPOSE_INL

namespace empathy::ir
{
    template< typename T >
    auto Lit( T&& val )
    {
        return LiteralSpec< T >( forward< T >( val ) );
    }







    template< typename... S >
    auto Vec( S&&... specs )
    {
        return VectorSpec< S... >( forward< S >( specs )... );
    }











>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef EMPATHY_IR_DECOMPOSE_INL
#define EMPATHY_IR_DECOMPOSE_INL

namespace empathy::ir
{
    template< typename T >
    auto Lit( T&& val )
    {
        return LiteralSpec< T >( forward< T >( val ) );
    }

    template< typename S >
    auto PTerm( S&& spec )
    {
        return PTermSpec< S >( forward< S >( spec ) );
    }

    template< typename... S >
    auto Vec( S&&... specs )
    {
        return VectorSpec< S... >( forward< S >( specs )... );
    }

75
76
77
78
79
80
81














82
83
84
85
86
87
88

            if constexpr( IS < ( sizeof... ( S ) - 1 ) )
                Decompose< IR + 1, IS + 1 >( terms, specs, result );

            return true;
        }
    }















    template< typename... S >
    optional< typename VectorSpec< S... >::return_type > Decompose( const Term& t, const VectorSpec< S... >& spec )
    {
        const auto* ppVec = get_if< pvec >( &t.content() );
        if( !ppVec )
            return nullopt;







>
>
>
>
>
>
>
>
>
>
>
>
>
>







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

            if constexpr( IS < ( sizeof... ( S ) - 1 ) )
                Decompose< IR + 1, IS + 1 >( terms, specs, result );

            return true;
        }
    }

    template< typename S >
    optional< typename PTermSpec< S >::return_type > Decompose( const Term& t, const PTermSpec< S >& spec )
    {
        const auto* ppTerm = get_if< ptr< Term > >( &t.content() );
        if( !ppTerm )
            return nullopt;

        const auto& pTerm = *ppTerm;
        if( !pTerm )
            return nullopt;

        return Decompose( *pTerm, spec.m_spec );
    }

    template< typename... S >
    optional< typename VectorSpec< S... >::return_type > Decompose( const Term& t, const VectorSpec< S... >& spec )
    {
        const auto* ppVec = get_if< pvec >( &t.content() );
        if( !ppVec )
            return nullopt;
Added bs/ir/term.cpp.




























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "ir.h"

namespace empathy::ir
{
    Term::Term( const ptr< Term >& pterm ) :
        m_content( pterm )
    {
        if( pterm )
        {
            m_location = pterm->location();
            m_faulty = pterm->isFaulty();
        }
    }
}
Changes to bs/ir/term.h.
1
2
3
4
5
6

7
8
9
10
11
12
13
#ifndef EMPATHY_IR_TERM_H
#define EMPATHY_IR_TERM_H

namespace empathy::ir
{
    class Vector;


    enum class Delimiter
    {
        Newline,

        OpenParen,
        OpenBrace,






>







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

namespace empathy::ir
{
    class Vector;
    class Term;

    enum class Delimiter
    {
        Newline,

        OpenParen,
        OpenBrace,
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
        uint64_t,
        string,
        StringId,
        Delimiter,
        AnyTerm,
        VecOfLength,
        ptr< void >,

        pvec
    >;

    class Term
    {
        template< typename V >
        friend class Trie;

        public:
            Term() {}

            template< typename L, typename C >
            Term( L&& location, C&& content );



            friend ostream& ToString( ostream& out, const Term& t );
            friend ostream& operator<<( ostream& out, const Term& t )
            {
                return ToString( out, t );
            }








>













>
>







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
        uint64_t,
        string,
        StringId,
        Delimiter,
        AnyTerm,
        VecOfLength,
        ptr< void >,
        ptr< Term >,
        pvec
    >;

    class Term
    {
        template< typename V >
        friend class Trie;

        public:
            Term() {}

            template< typename L, typename C >
            Term( L&& location, C&& content );

            Term( const ptr< Term >& pterm );

            friend ostream& ToString( ostream& out, const Term& t );
            friend ostream& operator<<( ostream& out, const Term& t )
            {
                return ToString( out, t );
            }

64
65
66
67
68
69
70

71
72
73
74
75
76
77
78
            TermVariant m_content;
            Location    m_location;
            bool        m_faulty = false;
    };
}

#define TERM( x )           ir::Term( ir::Location( make_shared< string >( __FILE__ ), __LINE__, 0 ), x )

#define TSTR( x )           TERM( string( x ) )
#define TSID( x )           TERM( #x##_sid )
#define ANYTERM( x )        TERM( ir::AnyTerm( #x##_sid ) )
#define VECOFLENGTH( x )    TERM( ir::VecOfLength( #x##_sid ) )
#define TVEC( ... )         TERM( ir::Vector::Make( __VA_ARGS__ ) )
#define REPEAT( x )         ir::Repetition( x )

#endif







>








68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
            TermVariant m_content;
            Location    m_location;
            bool        m_faulty = false;
    };
}

#define TERM( x )           ir::Term( ir::Location( make_shared< string >( __FILE__ ), __LINE__, 0 ), x )
#define PTERM( x )          make_shared< ir::Term >( ir::Location( make_shared< string >( __FILE__ ), __LINE__, 0 ), x )
#define TSTR( x )           TERM( string( x ) )
#define TSID( x )           TERM( #x##_sid )
#define ANYTERM( x )        TERM( ir::AnyTerm( #x##_sid ) )
#define VECOFLENGTH( x )    TERM( ir::VecOfLength( #x##_sid ) )
#define TVEC( ... )         TERM( ir::Vector::Make( __VA_ARGS__ ) )
#define REPEAT( x )         ir::Repetition( x )

#endif
Changes to bs/ir/tostring.cpp.
51
52
53
54
55
56
57












58
59
60
61
62
63
64
        return out << name;
    }

    ostream& ToString( ostream& out, const ptr< void >& x )
    {
        return out << "pvoid(" << x << ')';
    }













    ostream& ToString( ostream& out, const AnyTerm& v )
    {
        return out << "@AnyTerm(" << v.m_varName << ')';
    }

    ostream& ToString( ostream& out, const VecOfLength& v )







>
>
>
>
>
>
>
>
>
>
>
>







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
        return out << name;
    }

    ostream& ToString( ostream& out, const ptr< void >& x )
    {
        return out << "pvoid(" << x << ')';
    }

    ostream& ToString( ostream& out, const ptr< Term >& x )
    {
        out << "pterm( ";

        if( x )
            out << *x;
        else
            out << "nullptr";

        return out << " )";
    }

    ostream& ToString( ostream& out, const AnyTerm& v )
    {
        return out << "@AnyTerm(" << v.m_varName << ')';
    }

    ostream& ToString( ostream& out, const VecOfLength& v )
Changes to bs/ir/tostring.h.
8
9
10
11
12
13
14

15
16
17
18
19
    enum class Delimiter;

    extern ostream& ToString( ostream& out, const uint64_t& x );
    extern ostream& ToString( ostream& out, const string& x );
    extern ostream& ToString( ostream& out, const StringId& x );
    extern ostream& ToString( ostream& out, const Delimiter& x );
    extern ostream& ToString( ostream& out, const ptr< void >& x );

    extern ostream& ToString( ostream& out, const ptr< Vector >& v );
    extern ostream& ToString( ostream& out, const Term& t );
}

#endif







>





8
9
10
11
12
13
14
15
16
17
18
19
20
    enum class Delimiter;

    extern ostream& ToString( ostream& out, const uint64_t& x );
    extern ostream& ToString( ostream& out, const string& x );
    extern ostream& ToString( ostream& out, const StringId& x );
    extern ostream& ToString( ostream& out, const Delimiter& x );
    extern ostream& ToString( ostream& out, const ptr< void >& x );
    extern ostream& ToString( ostream& out, const ptr< Term >& x );
    extern ostream& ToString( ostream& out, const ptr< Vector >& v );
    extern ostream& ToString( ostream& out, const Term& t );
}

#endif
Changes to bs/ir/trie.h.
41
42
43
44
45
46
47




48
49
50
51
52
53
54
    template< typename U >
    struct TrieNode< VecOfLength, U > : public ValueTrieNode< VecOfLength, U >
    {};

    template< typename U >
    struct TrieNode< ptr< void >, U > : public ValueTrieNode< ptr< void >, U >
    {};





    struct TrieContainerNode;
    using TrieContainerBranch_t = variant< ptr< TrieContainerNode >, any >;

    template< typename U >
    struct TrieNode< pvec, U >
    {







>
>
>
>







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    template< typename U >
    struct TrieNode< VecOfLength, U > : public ValueTrieNode< VecOfLength, U >
    {};

    template< typename U >
    struct TrieNode< ptr< void >, U > : public ValueTrieNode< ptr< void >, U >
    {};

    template< typename U >
    struct TrieNode< ptr< Term >, U > : public ValueTrieNode< ptr< Term >, U >
    {};

    struct TrieContainerNode;
    using TrieContainerBranch_t = variant< ptr< TrieContainerNode >, any >;

    template< typename U >
    struct TrieNode< pvec, U >
    {
68
69
70
71
72
73
74

75
76
77
78
79
80
81
                ptr< TrieNode< uint64_t, U > >,
                ptr< TrieNode< string, U > >,
                ptr< TrieNode< StringId, U > >,
                ptr< TrieNode< Delimiter, U > >,
                ptr< TrieNode< AnyTerm, U > >,
                ptr< TrieNode< VecOfLength, U > >,
                ptr< TrieNode< ptr< void >, U > >,

                ptr< TrieNode< pvec, U > >
            >;

            const auto& branches() const { return m_branches; }
            auto& branches() { return m_branches; }

        private:







>







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
                ptr< TrieNode< uint64_t, U > >,
                ptr< TrieNode< string, U > >,
                ptr< TrieNode< StringId, U > >,
                ptr< TrieNode< Delimiter, U > >,
                ptr< TrieNode< AnyTerm, U > >,
                ptr< TrieNode< VecOfLength, U > >,
                ptr< TrieNode< ptr< void >, U > >,
                ptr< TrieNode< ptr< Term >, U > >,
                ptr< TrieNode< pvec, U > >
            >;

            const auto& branches() const { return m_branches; }
            auto& branches() { return m_branches; }

        private:
Changes to bs/lex/CMakeLists.txt.
1
2
3
4
5
6
7
8
9
10
11
add_library( empathy-lex
    lexer.cpp
    lookahead.cpp
    comment.cpp
    vectoradapter.cpp
)

target_link_libraries( empathy-lex
    empathy-util
    empathy-ir
)




<






1
2
3
4

5
6
7
8
9
10
add_library( empathy-lex
    lexer.cpp
    lookahead.cpp
    comment.cpp

)

target_link_libraries( empathy-lex
    empathy-util
    empathy-ir
)
Changes to bs/lex/lex.h.
9
10
11
12
13
14
15


16
17
    using namespace util;
    using namespace ir;
}

#include "tokenprovider.h"
#include "lexer.h"
#include "vectoradapter.h"



#endif







>
>


9
10
11
12
13
14
15
16
17
18
19
    using namespace util;
    using namespace ir;
}

#include "tokenprovider.h"
#include "lexer.h"
#include "vectoradapter.h"

#include "vectoradapter.inl"

#endif
Changes to bs/lex/vectoradapter.h.
1
2
3
4
5

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21






22
23
24
#ifndef EMPATHY_LEX_VECTORADAPTER_H
#define EMPATHY_LEX_VECTORADAPTER_H

namespace empathy::lex
{

    class VectorAdapter : public TokenProvider
    {
        public:
            VectorAdapter( const vector< ir::Term >& v ) :
                m_vector( v )
            {}

            virtual bool eos() const override;

            virtual optional< ir::Term > consume() override;
            virtual optional< ir::Term > lookAhead( size_t distance = 0 ) override;

        private:
            const vector< ir::Term >& m_vector;
            size_t m_index = 0;
    };






}

#endif





>



|









|


>
>
>
>
>
>



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
#ifndef EMPATHY_LEX_VECTORADAPTER_H
#define EMPATHY_LEX_VECTORADAPTER_H

namespace empathy::lex
{
    template< typename V >
    class VectorAdapter : public TokenProvider
    {
        public:
            VectorAdapter( const V& v ) :
                m_vector( v )
            {}

            virtual bool eos() const override;

            virtual optional< ir::Term > consume() override;
            virtual optional< ir::Term > lookAhead( size_t distance = 0 ) override;

        private:
            const V& m_vector;
            size_t m_index = 0;
    };

    template< typename V >
    auto MakeVectorAdapter( V&& vec )
    {
        return make_shared< VectorAdapter< V > >( forward< V >( vec ) );
    }
}

#endif
Name change from bs/lex/vectoradapter.cpp to bs/lex/vectoradapter.inl.
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



#include "lex.h"


using namespace empathy;
using namespace empathy::lex;


bool VectorAdapter::eos() const
{
    return m_index >= m_vector.size();
}


optional< ir::Term > VectorAdapter::consume()
{
    if( eos() )
        return nullopt;

    return m_vector[m_index++];
}


optional< ir::Term > VectorAdapter::lookAhead( size_t distance )
{
    if( ( m_index + distance ) >= m_vector.size() )
        return nullopt;

    return m_vector[m_index + distance];
}



|
>

<
|
|
>
|
|
|
|

>
|
|
|
|

|
|

>
|
|
|
|

|
|
>
>
>
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
#ifndef EMPATHY_LEX_VECTORADAPTER_INL
#define EMPATHY_LEX_VECTORADAPTER_INL


namespace empathy::lex
{
    template< typename V >
    bool VectorAdapter< V >::eos() const
    {
        return m_index >= m_vector.size();
    }

    template< typename V >
    optional< ir::Term > VectorAdapter< V >::consume()
    {
        if( eos() )
            return nullopt;

        return m_vector[m_index++];
    }

    template< typename V >
    optional< ir::Term > VectorAdapter< V >::lookAhead( size_t distance )
    {
        if( ( m_index + distance ) >= m_vector.size() )
            return nullopt;

        return m_vector[m_index + distance];
    }
}

#endif
Changes to bs/llr/call.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 "llr/llr.h"
#include "builtins/builtins.h"

using namespace empathy::builtins;

namespace empathy::llr
{
    bool Call::canBeExecuted() const
    {



        bool argsCanBeExecuted = true;
        ForEachInVectorTerm( m_args, [&]( auto&& arg )
        {
            if( !IsValueConstantOrExecutable( *ValueFromIRExpr( arg ) ) )
            {
                argsCanBeExecuted = false;
                return false;
            }

            return true;
        } );

        if( !argsCanBeExecuted )
            return false;

        if( IsBuiltinFunc( m_func ) )
            return true;

        const auto& content = m_func.val().content();
        const auto& p = get< ptr< void > >( content );
        const auto& pFunc = static_pointer_cast< llr::Func >( p );


        return pFunc->canBeExecuted();
    }

    bool Call::canBeEagerlyEvaluated() const
    {
        // Functions with void return type are assumed to have side effects
        // and therefore that they should never be eagerly evaluated.









>
>
>


















<
<
<

>







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

using namespace empathy::builtins;

namespace empathy::llr
{
    bool Call::canBeExecuted() const
    {
        if( !m_func.isConstant() )
            return false;

        bool argsCanBeExecuted = true;
        ForEachInVectorTerm( m_args, [&]( auto&& arg )
        {
            if( !IsValueConstantOrExecutable( *ValueFromIRExpr( arg ) ) )
            {
                argsCanBeExecuted = false;
                return false;
            }

            return true;
        } );

        if( !argsCanBeExecuted )
            return false;

        if( IsBuiltinFunc( m_func ) )
            return true;





        auto pFunc = GetFuncLLR( m_func );
        return pFunc->canBeExecuted();
    }

    bool Call::canBeEagerlyEvaluated() const
    {
        // Functions with void return type are assumed to have side effects
        // and therefore that they should never be eagerly evaluated.
Changes to bs/llr/func.h.
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
#ifndef EMPATHY_LLR_FUNC_H
#define EMPATHY_LLR_FUNC_H

namespace empathy::llr
{
    class Func
    {
        public:
            template< typename I, typename P >
            Func( I&& identity, P&& paramVarIds ) :
                m_identity( forward< I >( identity ) ),
                m_paramVarIds( forward< P >( paramVarIds ) )
            {}

            template< typename I, typename P, typename B >
            Func( I&& identity, P&& paramVarIds, B&& body ) :
                m_identity( forward< I >( identity ) ),
                m_paramVarIds( forward< P >( paramVarIds ) ),
                m_body( forward< B >( body ) )
            {}

            const auto& identity() const { return m_identity; }
            const auto& paramVarIds() const { return m_paramVarIds; }
            const auto& body() const { return m_body; }

            auto& body() { return m_body; }

            bool canBeExecuted() const;

        private:
            ir::Term m_identity;
            vector< uint32_t > m_paramVarIds;
            variant
            <
                Element,
                vector< ir::Term >
            > m_body;
    };
}

#endif








|
|
<



|
|
<




<








<

<
<
|
<
<




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
#ifndef EMPATHY_LLR_FUNC_H
#define EMPATHY_LLR_FUNC_H

namespace empathy::llr
{
    class Func
    {
        public:
            template< typename P >
            Func( P&& paramVarIds ) :

                m_paramVarIds( forward< P >( paramVarIds ) )
            {}

            template< typename P, typename B >
            Func( P&& paramVarIds, B&& body ) :

                m_paramVarIds( forward< P >( paramVarIds ) ),
                m_body( forward< B >( body ) )
            {}


            const auto& paramVarIds() const { return m_paramVarIds; }
            const auto& body() const { return m_body; }

            auto& body() { return m_body; }

            bool canBeExecuted() const;

        private:

            vector< uint32_t > m_paramVarIds;


            Element m_body;


    };
}

#endif
Changes to bs/parse/func.cpp.
117
118
119
120
121
122
123
124


125
126
127
128

129
        // TODO ERROR MGMT
        cout << "function body expected.\n";
        return nullopt;
    }

    m_resolver->consumeNewLines();

    vector< Term > body;


    auto g = m_resolver->consumeUnit();
    move( g.begin(), g.end(), back_inserter( body ) );

    return BuildFunc( move( funcStruct ), move( body ) );

}







|
>
>

|

|
>

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
        // TODO ERROR MGMT
        cout << "function body expected.\n";
        return nullopt;
    }

    m_resolver->consumeNewLines();

    immer::vector< Term > bodyv;
    auto bodyvt = bodyv.transient();

    auto g = m_resolver->consumeUnit();
    move( g.begin(), g.end(), back_inserter( bodyvt ) );

    return BuildFunc( move( funcStruct ),
        TERM( make_shared< Vector >( bodyvt.persistent(), false ) ) );
}
Changes to bs/sema/CMakeLists.txt.
21
22
23
24
25
26
27
28
29
30
31
32
33
    tpl-ruleset.cpp
    template.cpp
)

target_link_libraries( empathy-sema
    empathy-util
    empathy-ir
    empathy-llr
)

if( BUILD_TESTING )
    add_subdirectory( tests )
endif( BUILD_TESTING )







<





21
22
23
24
25
26
27

28
29
30
31
32
    tpl-ruleset.cpp
    template.cpp
)

target_link_libraries( empathy-sema
    empathy-util
    empathy-ir

)

if( BUILD_TESTING )
    add_subdirectory( tests )
endif( BUILD_TESTING )
Changes to bs/sema/sema.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
#ifndef EMPATHY_SEMA_H
#define EMPATHY_SEMA_H

#include "util/util.h"
#include "ir/ir.h"
#include "llr/llr.h"

namespace empathy::sema
{
    using namespace util;
    using namespace ir;
}






<







1
2
3
4
5

6
7
8
9
10
11
12
#ifndef EMPATHY_SEMA_H
#define EMPATHY_SEMA_H

#include "util/util.h"
#include "ir/ir.h"


namespace empathy::sema
{
    using namespace util;
    using namespace ir;
}