#location #source #track #original #keeping

location_info

跟踪事物原始源位置信息的库

2个版本

0.1.0-alpha-12023年5月25日

#8 in #keeping

Apache-2.0 OR MIT

14KB
176 代码行(不含注释)

location_info

一个跟踪输入源代码中事物来源位置的库。

请参阅https://docs.rs/location_info获取文档


lib.rs:

定义了一个类型来包装其相应的源代码位置,并方便创建和转换这些类型,同时不丢失位置信息。

设置

该crate对编译器的源代码位置表示进行了泛型处理,为了方便起见,为您的特定类型创建一个类型别名可能是个好主意。例如,如果您表示位置为文件ID和字节范围,您将编写

use location_info::{Location};

// Define the location type
#[derive(Clone)]
pub struct Span(usize, std::ops::Range<u64>);

impl Location for Span {
fn nowhere() -> Self {
// Here users of our compiler should never encounter thigns without valid
// source mapping, so we'll use a dummy value.
Span(0, 0..0)
}

fn between(Self(start_file, start_range): &Self, Self(end_file, end_range): &Self) -> Self {
assert!(start_file == end_file); // A location spanning multiple files is weird
Span(*start_file, start_range.start.min(end_range.start) .. start_range.end.max(end_range.end))
}
}

// Avoid having to specify the other generic parameter in your compiler
type Loc<T> = location_info::Loc<T, Span>;

对于您经常将其转换为位置的T类型,为您的Location类型实现From<T>可能也有帮助。例如,您的解析器中的令牌


enum TokenKind {
// ...
}
struct Token {
kind: TokenKind,
file: usize,
offset: std::ops::Range<u64>
}

impl From<&Token> for Span {
fn from(tok: &Token) -> Span {
Span(tok.file, tok.offset.clone())
}
}

使用

要使用此crate,将您想要跟踪源位置的值包装在Loc<T>中。例如,一个函数头部的AST节点可能看起来像

struct Identifier(String);
struct FnHead {
fn_keyword: Loc<()>,
name: Loc<Identifier>,
args: Loc<Vec<Loc<Identifier>>>
}

使用[WithLocation]中的方法附加位置信息。

use location_info::WithLocation;
enum TokenKind {
Fn,
Identifier(String),
OpenParen,
CloseParen,
}

fn parse_fn_head(tokens: &mut impl Iterator<Item=Token>) -> Result<Loc<FnHead>> {
let fn_keyword = parse_fn_keyword(tokens)?;
let name = parse_ident(tokens)?;

let open_paren = parse_open_paren(tokens)?;
let mut args_raw = vec![];
while let ident @ Loc{inner: Identifier(_), ..} = parse_ident(tokens)? {
args_raw.push(ident);
}
let close_paren = parse_close_paren(tokens)?;
// The span of the argument list is the span between open_paren and close_paren
let args = args_raw.between(&open_paren, &close_paren);

Ok(
FnHead {
// We don't want the token, just a Loc<()>, those can be created
// with ().at(...)
fn_keyword: ().at(&fn_keyword),
name,
args
}.between(&fn_keyword, &close_paren)
)
}

映射

创建位置信息后,通常需要能够转换内部结构,例如从一种IR降低到另一种IR时。[Loc]结构有几个映射到包含值的函数。

依赖项

~0.4–1MB
~23K SLoC