Goose  Diff

Differences From Artifact [c04a827ece]:

  • File bs/builtins/statements/using.cpp — part of check-in [0b6a7a10ee] at 2019-02-14 20:35:29 on branch trunk — Fix using statement not skipping newline markers before the expression. (user: achavasse size: 4590)

To Artifact [db91a636d3]:

  • File bs/builtins/statements/using.cpp — part of check-in [23e0cd5dc7] at 2019-02-18 21:54:23 on branch trunk — Parser:
    • Make the resolver skip newlines by default, and provide an additional "raw" api to retrieve unresolved tokens without skipping newlines.
    • Parsing rules now only return a bool to indicate whether they were successful, and can push any number of values themselves as needed.
    • Stop trying to shoehorn implicit separators in the pratt parser. Instead, use the pratt parser only for expressions, and use a different parsing loop for sequences of expressions (ie for brace blocks and top level).
    (user: achavasse size: 4665)

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

using namespace empathy;
using namespace empathy::ir;
using namespace empathy::parse;

namespace empathy::builtins
{
    void SetupUsingStmt( Env& e )
    {
        auto handleUsing = []( Parser& p, const Term& t, uint32_t prec ) -> optional< Value >
        {
            p.resolver()->consumeNewLines();
            auto nameTerm = p.resolver()->consume();
            if( !nameTerm )
            {
                cout << t.location() << ": expected an identifier after 'using'.\n";
                return nullopt;
            }

            const auto* name = get_if< StringId >( &nameTerm->content() );
            if( !name )
            {
                cout << nameTerm->location() << ": expected an identifier after 'using'.\n";
                return nullopt;
            }

            p.resolver()->consumeNewLines();
            auto eqTerm = p.resolver()->consumeUnresolved();
            if( !eqTerm )
            {
                cout << eqTerm->location() << ": expected '=' after 'using " << name->c_str() << "'.\n";
                return nullopt;
            }

            const auto* eq = get_if< StringId >( &eqTerm->content() );
            if( !eq || *eq != "="_sid )
            {
                cout << eqTerm->location() << ": expected '=' after 'using " << name->c_str() << "'.\n";
                return nullopt;
            }

            p.resolver()->consumeNewLines();

            // Store all the units following the equal sign until the next semicolon or newline.
            vector< Term > toks;
            while( !p.resolver()->eos() )
            {
                const auto& tok = p.resolver()->lookAheadUnresolved();
                if( !tok )
                    break;

                const auto* delim = get_if< Delimiter >( &tok->content() );
                if( delim && *delim == Delimiter::Newline )


                    break;


                const auto* id = get_if< StringId >( &tok->content() );
                if( id && *id == ";"_sid )
                    break;

                auto g = p.resolver()->consumeUnit();
                move( g.begin(), g.end(), back_inserter( toks ) );
            }

            if( toks.empty() )
            {
                cout << eqTerm->location() << ": expected an expression after 'using " << name->c_str() << " ='.\n";
                return nullopt;
            }

            const auto& context = p.resolver()->context();

            // Create a local identity for the constant, from which the current identity will be visible.
            // This is to avoid anything declared from within the using expression to leak outside,
            // and also to make sure that whenever it will be parsed, it will have access to the current












|

<




|






|


<




|






|








|





>
>

>












|







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

using namespace empathy;
using namespace empathy::ir;
using namespace empathy::parse;

namespace empathy::builtins
{
    void SetupUsingStmt( Env& e )
    {
        auto handleUsing = []( Parser& p, const Term& t, uint32_t prec )
        {

            auto nameTerm = p.resolver()->consume();
            if( !nameTerm )
            {
                cout << t.location() << ": expected an identifier after 'using'.\n";
                return false;
            }

            const auto* name = get_if< StringId >( &nameTerm->content() );
            if( !name )
            {
                cout << nameTerm->location() << ": expected an identifier after 'using'.\n";
                return false;
            }


            auto eqTerm = p.resolver()->consumeUnresolved();
            if( !eqTerm )
            {
                cout << eqTerm->location() << ": expected '=' after 'using " << name->c_str() << "'.\n";
                return false;
            }

            const auto* eq = get_if< StringId >( &eqTerm->content() );
            if( !eq || *eq != "="_sid )
            {
                cout << eqTerm->location() << ": expected '=' after 'using " << name->c_str() << "'.\n";
                return false;
            }

            p.resolver()->consumeNewLines();

            // Store all the units following the equal sign until the next semicolon or newline.
            vector< Term > toks;
            while( !p.resolver()->eos() )
            {
                const auto& tok = p.resolver()->lookAheadRaw();
                if( !tok )
                    break;

                const auto* delim = get_if< Delimiter >( &tok->content() );
                if( delim && *delim == Delimiter::Newline )
                {
                    p.resolver()->consumeRaw();
                    break;
                }

                const auto* id = get_if< StringId >( &tok->content() );
                if( id && *id == ";"_sid )
                    break;

                auto g = p.resolver()->consumeUnit();
                move( g.begin(), g.end(), back_inserter( toks ) );
            }

            if( toks.empty() )
            {
                cout << eqTerm->location() << ": expected an expression after 'using " << name->c_str() << " ='.\n";
                return false;
            }

            const auto& context = p.resolver()->context();

            // Create a local identity for the constant, from which the current identity will be visible.
            // This is to avoid anything declared from within the using expression to leak outside,
            // and also to make sure that whenever it will be parsed, it will have access to the current
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
                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 );







                    auto result = p.parse();
                    if( !result )
                    {
                        cout << "invalid using expression.\n";
                        return Env::Status::NoMatch;
                    }

                    content = ValueToIRExpr( *result );
                }

                result = get< Term >( content );
                return Env::Status::Success;
            };

            context.env()->storeValue( localIdentity, ANYTERM( c ),
                make_shared< Env::ValueProvider >( move( UsingValProvider ) ) );

            // Parse whatever follows the using statement
            return Parser( p.resolver() ).parse( prec );
        };

        Rule r( handleUsing );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( TVEC( TSID( e0 ), TSID( using ) ), ANYTERM( x ), ruleTerm );
    }
}







>
>
>
>
>
>
|
















<
|








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

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

                    content = ValueToIRExpr( *result );
                }

                result = get< Term >( content );
                return Env::Status::Success;
            };

            context.env()->storeValue( localIdentity, ANYTERM( c ),
                make_shared< Env::ValueProvider >( move( UsingValProvider ) ) );


            return true;
        };

        Rule r( handleUsing );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        e.storeValue( TVEC( TSID( e0 ), TSID( using ) ), ANYTERM( x ), ruleTerm );
    }
}