blob: a497c67451743effabed0b075d0510c60f7492ac [file] [log] [blame]
// 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