Skip to content
This repository has been archived by the owner on Jun 3, 2021. It is now read-only.

Make the top-level API much easier to use #431

Merged
merged 1 commit into from
May 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/data/lex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,9 +427,7 @@ pub(crate) mod test {
}
/// Create a new preprocessor with `s` as the input, but without a trailing newline
pub(crate) fn cpp_no_newline(s: &str) -> PreProcessor {
let mut files: Files = Default::default();
let id = files.add("<test suite>", String::new().into());
PreProcessorBuilder::new(s, id, Box::leak(Box::new(files))).build()
PreProcessorBuilder::new(s).build()
}

#[test]
Expand Down
78 changes: 42 additions & 36 deletions src/lex/cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ use std::convert::TryFrom;
use std::path::{Path, PathBuf};
use std::rc::Rc;

use codespan::FileId;

use super::{Lexer, Token};
use crate::arch::TARGET;
use crate::data::error::CppError;
Expand All @@ -20,24 +18,18 @@ use crate::Files;
///
/// Here is the example for `PreProcessor::new()` using the builder:
/// ```
/// use rcc::{Files, PreProcessorBuilder, Source};
/// use rcc::PreProcessorBuilder;
///
/// let mut files = Files::new();
/// let code = String::from("int main(void) { char *hello = \"hi\"; }\n").into();
/// let src = Source { path: "example.c".into(), code: std::rc::Rc::clone(&code) };
/// let file = files.add("example.c", src);
/// let cpp = PreProcessorBuilder::new(code, file, &mut files).build();
/// let cpp = PreProcessorBuilder::new("int main(void) { char *hello = \"hi\"; }\n").filename("example.c").build();
/// for token in cpp {
/// assert!(token.is_ok());
/// }
/// ```
pub struct PreProcessorBuilder<'a> {
/// The buffer for the starting file
buf: Rc<str>,
/// The starting file
file: FileId,
/// All known files, including files which have already been read.
files: &'a mut Files,
/// The name of the file
filename: PathBuf,
/// Whether to print each token before replacement
debug: bool,
/// The paths to search for `#include`d files
Expand All @@ -47,20 +39,19 @@ pub struct PreProcessorBuilder<'a> {
}

impl<'a> PreProcessorBuilder<'a> {
pub fn new<S: Into<Rc<str>>>(
buf: S,
file: FileId,
files: &'a mut Files,
) -> PreProcessorBuilder<'a> {
pub fn new<S: Into<Rc<str>>>(buf: S) -> PreProcessorBuilder<'a> {
PreProcessorBuilder {
debug: false,
files,
file,
filename: PathBuf::default(),
buf: buf.into(),
search_path: Vec::new(),
definitions: HashMap::new(),
}
}
pub fn filename<P: Into<PathBuf>>(mut self, name: P) -> Self {
self.filename = name.into();
self
}
pub fn debug(mut self, yes: bool) -> Self {
self.debug = yes;
self
Expand All @@ -75,12 +66,11 @@ impl<'a> PreProcessorBuilder<'a> {
}
pub fn build(self) -> PreProcessor<'a> {
PreProcessor::new(
self.file,
self.buf,
self.filename,
self.debug,
self.search_path,
self.definitions,
self.files,
)
}
}
Expand All @@ -104,13 +94,9 @@ impl<'a> PreProcessorBuilder<'a> {
/// Examples:
///
/// ```
/// use rcc::{Files, PreProcessor, Source};
/// use rcc::PreProcessor;
///
/// let mut files = Files::new();
/// let code = String::from("int main(void) { char *hello = \"hi\"; }\n").into();
/// let src = Source { path: "example.c".into(), code: std::rc::Rc::clone(&code) };
/// let file = files.add("example.c", src);
/// let cpp = PreProcessor::new(file, code, false, vec![], Default::default(), &mut files);
/// let cpp = PreProcessor::new("int main(void) { char *hello = \"hi\"; }\n", "example.c", false, vec![], Default::default());
/// for token in cpp {
/// assert!(token.is_ok());
/// }
Expand All @@ -122,7 +108,7 @@ pub struct PreProcessor<'a> {
/// Each lexer represents a separate source file that is currently being processed.
includes: Vec<Lexer>,
/// All known files, including files which have already been read.
files: &'a mut Files,
files: Files,
/// Note that this is a simple HashMap and not a Scope, because
/// the preprocessor has no concept of scope other than `undef`
definitions: HashMap<InternedStr, Definition>,
Expand Down Expand Up @@ -385,18 +371,12 @@ impl<'a> PreProcessor<'a> {
/// but will never delete a file.
///
/// The `debug` parameter specifies whether to print out tokens before replacement.
pub fn new<
'files: 'a,
'search: 'a,
I: IntoIterator<Item = Cow<'search, Path>>,
S: Into<Rc<str>>,
>(
file: FileId,
pub fn new<'search: 'a, I: IntoIterator<Item = Cow<'search, Path>>, S: Into<Rc<str>>>(
chars: S,
filename: impl Into<std::ffi::OsString>,
debug: bool,
user_search_path: I,
user_definitions: HashMap<InternedStr, Definition>,
files: &'files mut Files,
) -> Self {
let system_path = format!(
"{}-{}-{}",
Expand Down Expand Up @@ -424,6 +404,16 @@ impl<'a> PreProcessor<'a> {
Path::new("/usr/include").into(),
];
search_path.extend(user_search_path.into_iter());

let mut files = Files::new();
let chars = chars.into();
let filename = filename.into();
let source = crate::Source {
code: Rc::clone(&chars),
path: filename.clone().into(),
};
let file = files.add(filename, source);

Self {
first_lexer: Lexer::new(file, chars, debug),
includes: Default::default(),
Expand Down Expand Up @@ -459,6 +449,22 @@ impl<'a> PreProcessor<'a> {
std::mem::take(&mut self.error_handler.warnings)
}

/// Return a `Location` representing the end of the first file.
pub fn eof(&self) -> Location {
let lex = &self.first_lexer;
Location {
span: (lex.chars.len() as u32..lex.chars.len() as u32).into(),
file: lex.location.file,
}
}

/// Return all files loaded by the preprocessor, consuming it in the process.
///
/// Files can be loaded by C source using `#include` directives.
pub fn into_files(self) -> Files {
self.files
}

/* internal functions */
/// Return all tokens from the current position until the end of the current line.
///
Expand Down
Loading