aboutsummaryrefslogtreecommitdiff
path: root/build2/test/script/parser
blob: 2dc14c894e45c6f446e802b4d3340d0dd37249c4 (plain)
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// file      : build2/test/script/parser -*- C++ -*-
// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef BUILD2_TEST_SCRIPT_PARSER
#define BUILD2_TEST_SCRIPT_PARSER

#include <build2/types>
#include <build2/utility>

#include <build2/parser>
#include <build2/diagnostics>

#include <build2/test/script/token>
#include <build2/test/script/script>

namespace build2
{
  namespace test
  {
    namespace script
    {
      class lexer;
      class runner;

      class parser: protected build2::parser
      {
      public:
        // Issue diagnostics and throw failed in case of an error.
        //
        void
        pre_parse (script&);

        void
        pre_parse (istream&, script&);

        void
        parse (script& s, runner& r)
        {
          parse (s, s, r);
        }

        // Recursive descent parser.
        //
        // Each parse function receives the token/type from which it should
        // start consuming. On return the token/type should contain the first
        // token that has not been consumed. For *_line() functions this is
        // the newline.
        //
      protected:
        void
        parse (scope&, script&, runner&);

        token
        pre_parse_scope_body ();

        void
        parse_scope_body ();

        description
        pre_parse_leading_description (token&, token_type&);

        description
        parse_trailing_description (token&, token_type&);

        bool
        pre_parse_line (token&, token_type&,
                        optional<description>&,
                        lines* = nullptr,
                        bool one = false);

        void
        parse_lines (lines::iterator, lines::iterator, size_t&, bool);

        bool
        pre_parse_if_else (token&, token_type&,
                           optional<description>&,
                           lines&);

        void
        parse_directive_line (token&, token_type&);

        void
        perform_include (names, location);

        value
        parse_variable_line (token&, token_type&);

        // Ordered sequence of here-document redirects that we can expect to
        // see after the command line.
        //
        struct here_doc
        {
          size_t expr;  // Index in command_expr.
          size_t pipe;  // Index in command_pipe.
          size_t redir; // Redirect (0 - in, 1 - out, 2 - err).

          string end;
          bool no_newline;
        };
        using here_docs = vector<here_doc>;

        pair<command_expr, here_docs>
        parse_command_line (token&, token_type&);

        command_exit
        parse_command_exit (token&, token_type&);

        void
        parse_here_documents (token&, token_type&,
                              pair<command_expr, here_docs>&);

        string
        parse_here_document (token&, token_type&, const string&, bool);

        // Customization hooks.
        //
      protected:
        virtual lookup
        lookup_variable (name&&, string&&, const location&) override;

        // Number of quoted tokens since last reset. Note that this includes
        // the peeked token, if any.
        //
      protected:
        size_t
        quoted () const;

        void
        reset_quoted (token& current);

        size_t replay_quoted_;

        // Insert id into the id map checking for duplicates.
        //
      protected:
        const string&
        insert_id (string, location);

      protected:
        using base_parser = build2::parser;

        script* script_;

        // Pre-parse state.
        //
        using id_map = std::unordered_map<string, location>;
        using include_set = std::set<path>;

        group* group_;
        id_map* id_map_;
        include_set* include_set_; // Testscripts already included in this
                                   // scope. Must be absolute and normalized.
        lexer* lexer_;
        string id_prefix_; // Auto-derived id prefix.

        // Parse state.
        //
        runner* runner_;
        scope* scope_;
      };
    }
  }
}

#endif // BUILD2_TEST_SCRIPT_PARSER