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
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 ) -> optional< Value >
        auto handleUsing = []( Parser& p, const Term& t, uint32_t prec )
        {
            p.resolver()->consumeNewLines();
            auto nameTerm = p.resolver()->consume();
            if( !nameTerm )
            {
                cout << t.location() << ": expected an identifier after 'using'.\n";
                return nullopt;
                return false;
            }

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

            p.resolver()->consumeNewLines();
            auto eqTerm = p.resolver()->consumeUnresolved();
            if( !eqTerm )
            {
                cout << eqTerm->location() << ": expected '=' after 'using " << name->c_str() << "'.\n";
                return nullopt;
                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 nullopt;
                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()->lookAheadUnresolved();
                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 nullopt;
                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
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.parse();
                    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 ) ) );

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

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