diff options
Diffstat (limited to 'libbuild2/script/lexer.hxx')
-rw-r--r-- | libbuild2/script/lexer.hxx | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/libbuild2/script/lexer.hxx b/libbuild2/script/lexer.hxx new file mode 100644 index 0000000..dbfdfcc --- /dev/null +++ b/libbuild2/script/lexer.hxx @@ -0,0 +1,139 @@ +// file : libbuild2/script/lexer.hxx -*- C++ -*- +// license : MIT; see accompanying LICENSE file + +#ifndef LIBBUILD2_SCRIPT_LEXER_HXX +#define LIBBUILD2_SCRIPT_LEXER_HXX + +#include <libbuild2/types.hxx> +#include <libbuild2/utility.hxx> + +#include <libbuild2/lexer.hxx> + +#include <libbuild2/script/token.hxx> + +namespace build2 +{ + namespace script + { + struct lexer_mode: build2::lexer_mode + { + using base_type = build2::lexer_mode; + + enum + { + command_expansion = base_type::value_next, + here_line_single, + here_line_double, + + value_next + }; + + lexer_mode () = default; + lexer_mode (value_type v): base_type (v) {} + lexer_mode (base_type v): base_type (v) {} + }; + + // Actual redirects (as tokens) for the the <, <<, <<<, and >, >>, >>> + // aliases. + // + struct redirect_aliases + { + optional<token_type> l; // < + optional<token_type> ll; // << + optional<token_type> lll; // <<< + optional<token_type> g; // > + optional<token_type> gg; // >> + optional<token_type> ggg; // >>> + + // If the token type is a redirect alias then return the token type it + // resolves to and the passed token type otherwise. Note that it's the + // caller's responsibility to make sure that the corresponding alias is + // present (normally by not recognizing absent aliases as tokens). + // + token_type + resolve (token_type t) const noexcept + { + switch (t) + { + case token_type::in_l: assert (l); return *l; + case token_type::in_ll: assert (ll); return *ll; + case token_type::in_lll: assert (lll); return *lll; + case token_type::out_g: assert (g); return *g; + case token_type::out_gg: assert (gg); return *gg; + case token_type::out_ggg: assert (ggg); return *ggg; + } + + return t; + } + }; + + class lexer: public build2::lexer + { + public: + using base_lexer = build2::lexer; + using base_mode = build2::lexer_mode; + + using redirect_aliases_type = script::redirect_aliases; + + // Note that none of the name, redirect aliases, and escape arguments + // are copied. + // + lexer (istream& is, + const path_name& name, + lexer_mode m, + const redirect_aliases_type& ra, + const char* escapes = nullptr) + : base_lexer (is, name, 1 /* line */, + nullptr /* escapes */, + false /* set_mode */), + redirect_aliases (ra) + { + mode (m, '\0', escapes); + } + + virtual void + mode (base_mode, + char = '\0', + optional<const char*> = nullopt, + uintptr_t = 0) override; + + // Number of quoted (double or single) tokens since last reset. + // + size_t + quoted () const {return quoted_;} + + void + reset_quoted (size_t q) {quoted_ = q;} + + virtual token + next () override; + + public: + const redirect_aliases_type& redirect_aliases; + + protected: + lexer (istream& is, const path_name& name, uint64_t line, + const char* escapes, + bool set_mode, + const redirect_aliases_type& ra) + : base_lexer (is, name, line, escapes, set_mode), + redirect_aliases (ra) {} + + // Return the next token if it is a command operator (|, ||, &&, + // redirect, or cleanup) and nullopt otherwise. + // + optional<token> + next_cmd_op (const xchar&, // The token first character (last got char). + bool sep); // The token is separated. + + private: + token + next_line (); + + protected: + size_t quoted_; + }; + } +} + +#endif // LIBBUILD2_SCRIPT_LEXER_HXX |