Goose  Diff

Differences From Artifact [2e9039a0ba]:

  • File bs/builtins/statements/using.cpp — part of check-in [c4abb2a3ed] at 2019-08-10 14:26:37 on branch trunk — Refactored the lexer (and the resolver) to output Terms associated with location Ids. (user: achavasse size: 5271)

To Artifact [0c632c0b41]:

  • File bs/builtins/statements/using.cpp — part of check-in [2eb6c1fa43] at 2019-08-10 17:01:13 on branch trunk — Implemented the very first draft of the DiagnosticsManager and converted the using statement to use it. (user: achavasse size: 6314)

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

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 << "expected an identifier after 'using'.\n";
                return false;
            }

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

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

            const auto* eq = get_if< StringId >( &eqTerm->first );
            if( !eq || *eq != "="_sid )
            {
                cout << "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< TermLoc > toks;







>
>



>
|






|






|






|







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

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

            auto nameTerm = p.resolver()->consume();
            if( !nameTerm )
            {
                // TODO: use the current parsing position before consume() as the location.
                dm.emitErrorMessage( 0, "expected an identifier." );
                return false;
            }

            const auto* name = get_if< StringId >( &nameTerm->first );
            if( !name )
            {
                dm.emitErrorMessage( nameTerm->second, "expected an identifier." );
                return false;
            }

            auto eqTerm = p.resolver()->consumeUnresolved();
            if( !eqTerm )
            {
                dm.emitErrorMessage( 0, "expected '='." );
                return false;
            }

            const auto* eq = get_if< StringId >( &eqTerm->first );
            if( !eq || *eq != "="_sid )
            {
                dm.emitErrorMessage( eqTerm->second, "expected '='." );
                return false;
            }

            p.resolver()->consumeNewLines();

            // Store all the units following the equal sign until the next semicolon or newline.
            vector< TermLoc > toks;
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

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

            if( toks.empty() )
            {

                cout << "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
            // context in which it has been declared.
            auto localIdentity = AppendToVectorTerm( context.identity(), nameTerm->first );
            context.env()->addVisibilityRule( context.identity(), localIdentity );

            variant< vector< TermLoc >, Term > content = move( toks );
            auto nameSid = *name;

            bool bInUse = false;

            auto UsingValProvider = [content, localIdentity, bInUse, nameSid]( Env& e, const Term& identity, const Term& contextId, Term& result ) mutable
            {


                if( holds_alternative< vector< TermLoc > >( content ) )
                {
                    if( bInUse )
                    {



                        cout << "error: \"using " << nameSid << "\": recursive expression.\n";
                        return Env::Status::NoMatch;
                    }

                    bInUse = true;

                    Context localContext( e.shared_from_this(), localIdentity );
                    auto tokProvider = lex::MakeVectorAdapter( get< vector< TermLoc > >( content ) );
                    auto r = make_shared< parse::Resolver >( tokProvider, localContext );
                    Parser p( r );

                    if( !p.parseExpression() )
                    {




                        cout << "error: \"using " << nameSid << "\": invalid expression.\n";
                        return Env::Status::NoMatch;
                    }

                    auto result = p.peekLastValue();
                    if( !result )
                    {

                        cout << "error: \"using " << nameSid << "\": invalid expression.\n";
                        return Env::Status::NoMatch;
                    }

                    if( !result->isConstant() )
                    {


                        cout << "error: \"using " << nameSid << "\": expression doesn't evaluate to a constant.\n";
                        return Env::Status::NoMatch;
                    }

                    content = ValueToIRExpr( *result );
                    bInUse = false;
                }








>
|



















>
>




>
>
>
|












>
>
>
>
|






>
|





>
>
|







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
139
140
141
142
143

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

            if( toks.empty() )
            {
                // TODO maybe use the current location after consuming the equal sign as the location here
                dm.emitErrorMessage( eqTerm->second, "expected an expression." );
                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
            // context in which it has been declared.
            auto localIdentity = AppendToVectorTerm( context.identity(), nameTerm->first );
            context.env()->addVisibilityRule( context.identity(), localIdentity );

            variant< vector< TermLoc >, Term > content = move( toks );
            auto nameSid = *name;

            bool bInUse = false;

            auto UsingValProvider = [content, localIdentity, bInUse, nameSid]( Env& e, const Term& identity, const Term& contextId, Term& result ) mutable
            {
                auto& dm = DiagnosticsManager::GetInstance();

                if( holds_alternative< vector< TermLoc > >( content ) )
                {
                    if( bInUse )
                    {
                        // TODO: decide what location to use here. Perhaps the name's location?
                        // We just want to indicate which using expression is at fault here, the most
                        // useful part of that diagnosis is going to be the context.
                        dm.emitErrorMessage( 0, "recursive using expression." );
                        return Env::Status::NoMatch;
                    }

                    bInUse = true;

                    Context localContext( e.shared_from_this(), localIdentity );
                    auto tokProvider = lex::MakeVectorAdapter( get< vector< TermLoc > >( content ) );
                    auto r = make_shared< parse::Resolver >( tokProvider, localContext );
                    Parser p( r );

                    if( !p.parseExpression() )
                    {
                        // TODO: use the name's location. This is a fallback message in case
                        // the oparsing somehow didn't emit a more useful one that caused that
                        // one to be silenced.
                        // TODO: Also perhaps return a poison value instead of nothing?
                        dm.emitErrorMessage( 0, "invalid expression." );
                        return Env::Status::NoMatch;
                    }

                    auto result = p.peekLastValue();
                    if( !result )
                    {
                        // TODO same remarks as above.
                        dm.emitErrorMessage( 0, "invalid expression." );
                        return Env::Status::NoMatch;
                    }

                    if( !result->isConstant() )
                    {
                        // TODO same remarks as above re: location ans poisoning,
                        // that message is actually important though.
                        dm.emitErrorMessage( 0, "using expression doesn't evaluate to a constant." );
                        return Env::Status::NoMatch;
                    }

                    content = ValueToIRExpr( *result );
                    bInUse = false;
                }