Skip to content

Commit

Permalink
Fix source spans on simple macros
Browse files Browse the repository at this point in the history
  • Loading branch information
hansihe committed Sep 24, 2020
1 parent 3992935 commit 0cf790f
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 14 deletions.
23 changes: 19 additions & 4 deletions libeir_diagnostics/src/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,29 @@ impl CodeMap {
let seen_ref = self
.seen
.entry(path.clone())
.or_insert_with(|| self.insert_file(name, source));
.or_insert_with(|| self.insert_file(name, source, None));
*seen_ref.value()
} else {
self.insert_file(name, source)
self.insert_file(name, source, None)
}
}

fn insert_file(&self, name: FileName, source: String) -> SourceId {
/// Add a file to the map with the given source span as a parent.
/// This will not deduplicate the file in the map.
pub fn add_child(
&self,
name: impl Into<FileName>,
source: String,
parent: SourceSpan,
) -> SourceId {
self.insert_file(name.into(), source, Some(parent))
}

fn insert_file(&self, name: FileName, source: String, parent: Option<SourceSpan>) -> SourceId {
let file_id = self.next_file_id();
self.files.insert(
file_id,
Arc::new(SourceFile::new(file_id, name.into(), source)),
Arc::new(SourceFile::new(file_id, name.into(), source, parent)),
);
file_id
}
Expand All @@ -65,6 +76,10 @@ impl CodeMap {
}
}

pub fn parent(&self, file_id: SourceId) -> Option<SourceSpan> {
self.get(file_id).and_then(|f| f.parent())
}

pub fn name(&self, file_id: SourceId) -> Option<FileName> {
self.get(file_id).map(|f| f.name().clone())
}
Expand Down
8 changes: 7 additions & 1 deletion libeir_diagnostics/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ pub struct SourceFile {
name: FileName,
source: String,
line_starts: Vec<ByteIndex>,
parent: Option<SourceSpan>,
}
impl SourceFile {
crate fn new(id: SourceId, name: FileName, source: String) -> Self {
crate fn new(id: SourceId, name: FileName, source: String, parent: Option<SourceSpan>) -> Self {
let line_starts = codespan_reporting::files::line_starts(source.as_str())
.map(|i| ByteIndex::from(i as u32))
.collect();
Expand All @@ -43,6 +44,7 @@ impl SourceFile {
name,
source,
line_starts,
parent,
}
}

Expand All @@ -54,6 +56,10 @@ impl SourceFile {
self.id
}

pub fn parent(&self) -> Option<SourceSpan> {
self.parent
}

pub fn line_start(
&self,
line_index: LineIndex,
Expand Down
46 changes: 45 additions & 1 deletion libeir_diagnostics/src/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::ops::Range;

use codespan::{ByteIndex, ByteOffset, Span};

use super::{SourceId, SourceIndex};
use super::{CodeMap, SourceId, SourceIndex};

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SourceSpan {
Expand All @@ -20,6 +20,7 @@ impl SourceSpan {
#[inline]
pub fn new(start: SourceIndex, end: SourceIndex) -> Self {
let source_id = start.source_id();
println!("{} {}", start.index(), end.index());
assert_eq!(
source_id,
end.source_id(),
Expand All @@ -35,6 +36,49 @@ impl SourceSpan {
}
}

pub fn new_align<F>(
start: SourceIndex,
end: SourceIndex,
get_codemap: &Fn(&mut dyn FnOnce(&CodeMap)),
) -> SourceSpan {
let start_source = start.source_id();
let end_source = end.source_id();

if start_source == end_source {
Self::new(start, end)
} else {
let mut result = None;
get_codemap(&mut |codemap: &CodeMap| {
let mut idx = start_source;
loop {
if let Some(parent) = codemap.parent(idx) {
if idx == end_source {
result = Some(Self::new(parent.start(), end));
return;
}
idx = parent.source_id();
} else {
break;
}
}

let mut idx = end_source;
loop {
if let Some(parent) = codemap.parent(idx) {
if idx == start_source {
result = Some(Self::new(start, parent.end()));
return;
}
idx = parent.source_id();
} else {
break;
}
}
});
result.expect("source spans cannot be aligned!")
}
}

#[inline(always)]
pub fn source_id(&self) -> SourceId {
self.source_id
Expand Down
10 changes: 9 additions & 1 deletion libeir_syntax_erl/src/lower/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ pub fn string_to_binary(
mod tests {
use libeir_intern::Ident;

use super::tokenize_string_to_vec;
use super::{string_to_binary, tokenize_string_to_vec, Encoding, Endianness};

#[test]
fn string_literal_parse() {
Expand Down Expand Up @@ -545,4 +545,12 @@ mod tests {

assert!(tokenize_string_to_vec(Ident::from_str("\\^a\\^z")).unwrap() == vec![1, 26]);
}

#[test]
fn test_string_to_binary() {
assert!(
string_to_binary(Ident::from_str("abcå"), Encoding::Utf8, Endianness::Big).unwrap()
== vec![0x61, 0x62, 0x63, 0xc3, 0xa5]
)
}
}
13 changes: 7 additions & 6 deletions libeir_syntax_erl/src/preprocessor/preprocessor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,22 +204,23 @@ where
}

fn expand_userdefined_macro(&self, call: MacroCall) -> PResult<VecDeque<LexicalToken>> {
let span = call.span();
let definition = match self.macros.get(&call) {
None => return Err(PreprocessorError::UndefinedMacro { call }),
Some(def) => def,
};
match *definition {
MacroDef::Dynamic(ref replacement) => Ok(replacement.clone().into()),
MacroDef::String(ref s) => Ok(vec![LexicalToken(
SourceIndex::UNKNOWN,
span.start(),
Token::String(s.clone()),
SourceIndex::UNKNOWN,
span.end(),
)]
.into()),
MacroDef::Boolean(true) => Ok(vec![LexicalToken(
SourceIndex::UNKNOWN,
span.start(),
Token::Atom(symbols::True),
SourceIndex::UNKNOWN,
span.end(),
)]
.into()),
MacroDef::Boolean(false) => Ok(VecDeque::new()),
Expand Down Expand Up @@ -252,9 +253,9 @@ where
Ok(expanded)
}
MacroDef::DelayedSubstitution(subst) => Ok(vec![LexicalToken(
call.span().start(),
span.start(),
Token::DelayedSubstitution(subst),
call.span().end(),
span.end(),
)]
.into()),
}
Expand Down
2 changes: 1 addition & 1 deletion libeir_syntax_erl/src/preprocessor/token_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ where
path: path.to_owned(),
span: directive,
})?;
let id = self.codemap.add(path, content);
let id = self.codemap.add_child(path, content, directive);
let file = self.codemap.get(id).unwrap();
let source = Source::new(file);
let scanner = Scanner::new(source);
Expand Down

0 comments on commit 0cf790f

Please sign in to comment.