2个版本
0.1.0-alpha-1 | 2023年5月25日 |
---|
#8 in #keeping
14KB
176 代码行(不含注释)
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