aboutsummaryrefslogtreecommitdiff
path: root/build/parser
blob: ca27890db7b343d886da9658ce3f3ed46a5716aa (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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// file      : build/parser -*- C++ -*-
// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
// license   : MIT; see accompanying LICENSE file

#ifndef BUILD_PARSER
#define BUILD_PARSER

#include <string>
#include <iosfwd>
#include <utility> // move()

#include <build/types>
#include <build/token>
#include <build/spec>
#include <build/variable>    // list_value
#include <build/diagnostics>

namespace build
{
  class scope;
  class target;
  class lexer;

  class parser
  {
  public:
    typedef build::names names_type;
    typedef build::variable variable_type;

    parser (): fail (&path_) {}

    // Issue diagnostics and throw failed in case of an error.
    //
    void
    parse_buildfile (std::istream&, const path&, scope& root, scope& base);

    buildspec
    parse_buildspec (std::istream&, const std::string& name);

    token
    parse_variable (lexer&, scope&, std::string name, token_type kind);

    names_type
    parse_export_stub (std::istream& is, const path& p, scope& r, scope& b)
    {
      parse_buildfile (is, p, r, b);
      return std::move (export_value_);
    }

    // Recursive descent parser.
    //
  protected:
    void
    clause (token&, token_type&);

    void
    print (token&, token_type&);

    void
    source (token&, token_type&);

    void
    include (token&, token_type&);

    void
    import (token&, token_type&);

    void
    export_ (token&, token_type&);

    void
    using_ (token&, token_type&);

    void
    define (token&, token_type&);

    void
    if_else (token&, token_type&);

    void
    variable (token&, token_type&, std::string name, token_type kind);

    std::string
    variable_name (names_type&&, const location&);

    names_type
    variable_value (token&, token_type&, const variable_type&);

    names_type
    eval (token&, token_type&);

    // If chunk is true, then parse the smallest but complete, name-wise,
    // chunk of input. Note that in this case you may still end up with
    // multiple names, for example, {foo bar}.
    //
    names_type
    names (token& t, token_type& tt, bool chunk = false)
    {
      names_type ns;
      names (t, tt, ns, chunk, 0, nullptr, nullptr, nullptr);
      return ns;
    }

    void
    names (token&, token_type&,
           names_type&,
           bool chunk,
           std::size_t pair,
           const std::string* prj,
           const dir_path* dir,
           const std::string* type);

    size_t
    names_trailer (token&, token_type&,
                   names_type&,
                   size_t pair,
                   const std::string* prj,
                   const dir_path* dir,
                   const std::string* type);

    // Skip until newline or eos.
    //
    void
    skip_line (token&, token_type&);

    // Skip until block-closing } or eos, taking into account nested blocks.
    //
    void
    skip_block (token&, token_type&);

    // Buildspec.
    //
    buildspec
    buildspec_clause (token&, token_type&, token_type end);

    // Utilities.
    //
  protected:

    // Switch to a new current scope. Note that this function might
    // also have to switch to a new root scope if the new current
    // scope is in another project. So both must be saved and
    // restored.
    //
    void
    switch_scope (const dir_path&);

    void
    process_default_target (token&);

    // Enter buildfile as a target.
    //
    void
    enter_buildfile (const path&);

    // Lexer.
    //
  protected:
    token_type
    next (token&, token_type&);

    token_type
    peek ();

    const token&
    peeked () const
    {
      assert (peeked_);
      return peek_;
    }

    // Diagnostics.
    //
  protected:
    const fail_mark<failed> fail;

  protected:
    const std::string* path_; // Path processed by diag_relative().
    lexer* lexer_;
    target* target_; // Current target, if any.
    scope* scope_;   // Current base scope (out_base).
    scope* root_;    // Current root scope (out_root).
    target* default_target_;
    names_type export_value_;

    token peek_ {token_type::eos, false, 0, 0};
    bool peeked_ {false};
  };
}

#endif // BUILD_PARSER