#pragma once #include <string> #include <memory> #include <vector> #include <arbor/util/either.hpp> #include <arbor/util/optional.hpp> namespace pyarb { enum class tok { nil, real, // real number integer, // integer name, // name lparen, // left parenthesis '(' rparen, // right parenthesis ')' string, // string, written as "spelling" eof, // end of file/input error // special error state marker }; std::ostream& operator<<(std::ostream&, const tok&); struct token { int column; tok kind; std::string spelling; }; std::ostream& operator<<(std::ostream&, const token&); std::vector<token> tokenize(const char* line); struct s_expr { template <typename U> struct s_pair { U head = U(); U tail = U(); s_pair(U l, U r): head(std::move(l)), tail(std::move(r)) {} }; // This value_wrapper is used to wrap the shared pointer template <typename T> struct value_wrapper{ using state_t = std::unique_ptr<T>; state_t state; value_wrapper() = default; value_wrapper(const T& v): state(std::make_unique<T>(v)) {} value_wrapper(T&& v): state(std::make_unique<T>(std::move(v))) {} value_wrapper(const value_wrapper& other): state(std::make_unique<T>(other.get())) {} value_wrapper& operator=(const value_wrapper& other) { state = std::make_unique<T>(other.get()); return *this; } value_wrapper(value_wrapper&& other) = default; friend std::ostream& operator<<(std::ostream& o, const value_wrapper& w) { return o << *w.state; } operator T() const { return *state; } const T& get() const { return *state; } T& get() { return *state; } }; // An s_expr can be one of // 1. an atom // 2. a pair of s_expr (head and tail) // The s_expr uses a util::either to represent these two possible states, // which requires using an incomplete definition of s_expr, requiring // with a std::shared_ptr. using pair_type = s_pair<value_wrapper<s_expr>>; arb::util::either<token, pair_type> state = token{-1, tok::nil, "nil"}; s_expr(const s_expr& s): state(s.state) {} s_expr() = default; s_expr(token t): state(std::move(t)) {} s_expr(s_expr l, s_expr r): state(pair_type(std::move(l), std::move(r))) {} bool is_atom() const; const token& atom() const; operator bool() const; const s_expr& head() const; const s_expr& tail() const; s_expr& head(); s_expr& tail(); friend std::ostream& operator<<(std::ostream& o, const s_expr& x); }; std::size_t length(const s_expr& l); int location(const s_expr& l); s_expr parse(const char* line); s_expr parse(const std::string& line); bool test_identifier(const char* in); } // namespace pyarb