| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| #ifndef RUST_IMPORTS_H |
| #define RUST_IMPORTS_H |
| |
| #include "rust-system.h" |
| #include "rust-location.h" |
| #include "rust-proc-macro.h" |
| |
| namespace Rust { |
| |
| extern void |
| add_search_path (const std::string &path); |
| |
| class Import |
| { |
| public: |
| // The Stream class is an interface used to read the data. The |
| // caller should instantiate a child of this class. |
| class Stream |
| { |
| public: |
| Stream (); |
| virtual ~Stream (); |
| |
| // Set the position, for error messages. |
| void set_pos (int pos) { this->pos_ = pos; } |
| |
| // Return whether we have seen an error. |
| bool saw_error () const { return this->saw_error_; } |
| |
| // Record that we've seen an error. |
| void set_saw_error () { this->saw_error_ = true; } |
| |
| // Return the next character (a value from 0 to 0xff) without |
| // advancing. Returns -1 at end of stream. |
| int peek_char (); |
| |
| // Look for LENGTH characters, setting *BYTES to point to them. |
| // Returns false if the bytes are not available. Does not |
| // advance. |
| bool peek (size_t length, const char **bytes) |
| { |
| return this->do_peek (length, bytes); |
| } |
| |
| // Return the next character (a value from 0 to 0xff) and advance |
| // the read position by 1. Returns -1 at end of stream. |
| int get_char () |
| { |
| int c = this->peek_char (); |
| this->advance (1); |
| return c; |
| } |
| |
| // Return true if at the end of the stream. |
| bool at_eof () { return this->peek_char () == -1; } |
| |
| // Return true if the next bytes match STR. |
| bool match_c_string (const char *str) |
| { |
| return this->match_bytes (str, strlen (str)); |
| } |
| |
| // Return true if the next LENGTH bytes match BYTES. |
| bool match_bytes (const char *bytes, size_t length); |
| |
| // Give an error if the next bytes do not match STR. Advance the |
| // read position by the length of STR. |
| void require_c_string (location_t location, const char *str) |
| { |
| this->require_bytes (location, str, strlen (str)); |
| } |
| |
| // Given an error if the next LENGTH bytes do not match BYTES. |
| // Advance the read position by LENGTH. |
| void require_bytes (location_t, const char *bytes, size_t length); |
| |
| // Advance the read position by SKIP bytes. |
| void advance (size_t skip) |
| { |
| this->do_advance (skip); |
| this->pos_ += skip; |
| } |
| |
| // Return the current read position. This returns int because it |
| // is more convenient in error reporting. FIXME. |
| int pos () { return static_cast<int> (this->pos_); } |
| |
| // This function should set *BYTES to point to a buffer holding |
| // the LENGTH bytes at the current read position. It should |
| // return false if the bytes are not available. This should not |
| // change the current read position. |
| virtual bool do_peek (size_t length, const char **bytes) = 0; |
| |
| // This function should advance the current read position LENGTH |
| // bytes. |
| virtual void do_advance (size_t skip) = 0; |
| |
| private: |
| // The current read position. |
| size_t pos_; |
| // True if we've seen an error reading from this stream. |
| bool saw_error_; |
| }; |
| |
| // Find import data. This searches the file system for FILENAME and |
| // returns a pointer to a Stream object to read the data that it |
| // exports. LOCATION is the location of the import statement. |
| // RELATIVE_IMPORT_PATH is used as a prefix for a relative import. |
| static std::pair<std::unique_ptr<Stream>, std::vector<ProcMacro::Procmacro>> |
| open_package (const std::string &filename, location_t location, |
| const std::string &relative_import_path); |
| |
| static std::pair<std::unique_ptr<Stream>, std::vector<ProcMacro::Procmacro>> |
| try_package_in_directory (const std::string &, location_t); |
| |
| // Constructor. |
| Import (std::unique_ptr<Stream>, location_t); |
| |
| // The location of the import statement. |
| location_t location () const { return this->location_; } |
| |
| // Return the next character. |
| int peek_char () { return this->stream_->peek_char (); } |
| |
| // Return the next character and advance. |
| int get_char () { return this->stream_->get_char (); } |
| |
| // Read LENGTH characters into *OUT and advance past them. On |
| // EOF reports an error and sets *OUT to an empty string. |
| void read (size_t length, std::string *out); |
| |
| // Return true at the end of the stream. |
| bool at_eof () { return this->stream_->at_eof (); } |
| |
| // Return whether the next bytes match STR. |
| bool match_c_string (const char *str) |
| { |
| return this->stream_->match_c_string (str); |
| } |
| |
| // Require that the next bytes match STR. |
| void require_c_string (const char *str) |
| { |
| this->stream_->require_c_string (this->location_, str); |
| } |
| |
| // Advance the stream SKIP bytes. |
| void advance (size_t skip) { this->stream_->advance (skip); } |
| |
| // Stream position, for error reporting. |
| int pos () { return this->stream_->pos (); } |
| |
| // Clear the stream when it is no longer accessible. |
| void clear_stream () { this->stream_ = NULL; } |
| |
| private: |
| static int try_suffixes (std::string *); |
| |
| static std::unique_ptr<Stream> find_export_data (const std::string &filename, |
| int fd, location_t); |
| |
| static std::unique_ptr<Stream> |
| find_object_export_data (const std::string &filename, int fd, off_t offset, |
| location_t); |
| |
| static bool is_archive_magic (const char *); |
| |
| static std::unique_ptr<Stream> |
| find_archive_export_data (const std::string &filename, int fd, location_t); |
| |
| // The stream from which to read import data. |
| std::unique_ptr<Stream> stream_; |
| // The location of the import statement we are processing. |
| location_t location_; |
| }; |
| |
| // Read import data from a string. |
| |
| class Stream_from_string : public Import::Stream |
| { |
| public: |
| Stream_from_string (const std::string &str) : str_ (str), pos_ (0) {} |
| |
| bool do_peek (size_t length, const char **bytes) |
| { |
| if (this->pos_ + length > this->str_.length ()) |
| return false; |
| *bytes = this->str_.data () + this->pos_; |
| return true; |
| } |
| |
| void do_advance (size_t len) { this->pos_ += len; } |
| |
| private: |
| // The string of data we are reading. |
| std::string str_; |
| // The current position within the string. |
| size_t pos_; |
| }; |
| |
| // Read import data from a buffer allocated using malloc. |
| |
| class Stream_from_buffer : public Import::Stream |
| { |
| public: |
| Stream_from_buffer (char *buf, size_t length) |
| : buf_ (buf), length_ (length), pos_ (0) |
| {} |
| |
| ~Stream_from_buffer () { free (this->buf_); } |
| |
| bool do_peek (size_t length, const char **bytes) |
| { |
| if (this->pos_ + length > this->length_) |
| return false; |
| *bytes = this->buf_ + this->pos_; |
| return true; |
| } |
| |
| void do_advance (size_t len) { this->pos_ += len; } |
| |
| private: |
| // The data we are reading. |
| char *buf_; |
| // The length of the buffer. |
| size_t length_; |
| // The current position within the buffer. |
| size_t pos_; |
| }; |
| |
| // Read import data from an open file descriptor. |
| |
| class Stream_from_file : public Import::Stream |
| { |
| public: |
| Stream_from_file (int fd); |
| |
| ~Stream_from_file (); |
| |
| bool do_peek (size_t, const char **); |
| |
| void do_advance (size_t); |
| |
| private: |
| // No copying. |
| Stream_from_file (const Stream_from_file &); |
| Stream_from_file &operator= (const Stream_from_file &); |
| |
| // The file descriptor. |
| int fd_; |
| // Data read from the file. |
| std::string data_; |
| }; |
| |
| } // namespace Rust |
| |
| #endif // RUST_IMPORTS_H |