use crate::facts::{
Declaration, DeclarationKind, Facts, Import, ImportBinding, Reference, ReferenceKind, Span,
};
use crate::syntax::Language;
use crate::token::{Mode, Token, TokenKind, Tokenizer};
#[must_use]
pub fn extract(source: &str, language: Language) -> Facts {
let tokens = Tokenizer::new(source, language)
.mode(Mode::Lite)
.collect::<Vec<_>>();
let mut state = Extractor {
source,
tokens: &tokens,
language,
rules: Rules::of(language),
facts: Facts::default(),
scopes: Vec::new(),
depth: 0,
};
state.run();
state.facts
}
struct Rules {
declarations: &'static [(&'static str, DeclarationKind)],
imports: &'static [&'static str],
modifiers: &'static [&'static str],
braced_members: bool,
grouped_declarations: bool,
typed_functions: bool,
exported_keyword: Option<&'static str>,
scope_keywords: &'static [&'static str],
}
impl Rules {
const fn of(language: Language) -> Self {
match language {
Language::Rust => Self::rust(),
Language::Swift => Self::swift(),
Language::Go => Self::go(),
Language::Java | Language::CSharp => Self::managed(),
Language::Solidity => Self::solidity(),
_ => Self::c_family(),
}
}
const fn rust() -> Self {
Self {
declarations: &[
("fn", DeclarationKind::Function),
("struct", DeclarationKind::Struct),
("enum", DeclarationKind::Enum),
("trait", DeclarationKind::Trait),
("type", DeclarationKind::TypeAlias),
("const", DeclarationKind::Constant),
("static", DeclarationKind::Constant),
("mod", DeclarationKind::Module),
],
imports: &["use", "mod"],
modifiers: &["pub", "async", "unsafe", "extern", "default"],
braced_members: false,
grouped_declarations: false,
typed_functions: false,
exported_keyword: Some("pub"),
scope_keywords: &["impl"],
}
}
const fn swift() -> Self {
Self {
declarations: &[
("func", DeclarationKind::Function),
("class", DeclarationKind::Class),
("struct", DeclarationKind::Struct),
("actor", DeclarationKind::Class),
("enum", DeclarationKind::Enum),
("protocol", DeclarationKind::Interface),
("typealias", DeclarationKind::TypeAlias),
("associatedtype", DeclarationKind::TypeAlias),
("let", DeclarationKind::Constant),
("var", DeclarationKind::Variable),
("init", DeclarationKind::Method),
("subscript", DeclarationKind::Method),
],
imports: &["import"],
modifiers: &[
"public",
"private",
"internal",
"fileprivate",
"open",
"static",
"final",
"override",
"mutating",
"nonmutating",
"lazy",
"weak",
"unowned",
"required",
"convenience",
"indirect",
"dynamic",
"optional",
"async",
"throws",
],
braced_members: false,
grouped_declarations: false,
typed_functions: false,
exported_keyword: Some("public"),
scope_keywords: &["extension"],
}
}
const fn go() -> Self {
Self {
declarations: &[
("func", DeclarationKind::Function),
("type", DeclarationKind::Struct),
("const", DeclarationKind::Constant),
("var", DeclarationKind::Variable),
],
imports: &["import"],
modifiers: &[],
braced_members: false,
grouped_declarations: true,
typed_functions: false,
exported_keyword: None,
scope_keywords: &[],
}
}
const fn managed() -> Self {
Self {
declarations: &[
("class", DeclarationKind::Class),
("interface", DeclarationKind::Interface),
("enum", DeclarationKind::Enum),
("record", DeclarationKind::Struct),
("struct", DeclarationKind::Struct),
],
imports: &["import", "using"],
modifiers: &[
"public",
"private",
"protected",
"static",
"final",
"abstract",
"sealed",
"internal",
"override",
"async",
"virtual",
"readonly",
],
braced_members: true,
grouped_declarations: false,
typed_functions: false,
exported_keyword: Some("public"),
scope_keywords: &[],
}
}
const fn solidity() -> Self {
Self {
declarations: &[
("contract", DeclarationKind::Class),
("library", DeclarationKind::Class),
("interface", DeclarationKind::Interface),
("struct", DeclarationKind::Struct),
("enum", DeclarationKind::Enum),
("function", DeclarationKind::Function),
("constructor", DeclarationKind::Method),
("modifier", DeclarationKind::Function),
("event", DeclarationKind::Field),
("error", DeclarationKind::Struct),
],
imports: &["import"],
modifiers: &[
"abstract", "virtual", "override", "public", "private", "internal", "external",
"pure", "view", "payable",
],
braced_members: false,
grouped_declarations: false,
typed_functions: false,
exported_keyword: Some("public"),
scope_keywords: &[],
}
}
const fn c_family() -> Self {
Self {
declarations: &[
("struct", DeclarationKind::Struct),
("class", DeclarationKind::Class),
("enum", DeclarationKind::Enum),
("namespace", DeclarationKind::Module),
],
imports: &["#include", "include"],
modifiers: &["static", "inline", "extern", "const", "virtual"],
braced_members: true,
grouped_declarations: false,
typed_functions: true,
exported_keyword: None,
scope_keywords: &[],
}
}
}
struct Scope {
name: String,
depth: Option<i32>,
declaration: Option<usize>,
type_body: bool,
test_only: bool,
}
struct Extractor<'source, 'tokens> {
source: &'source str,
tokens: &'tokens [Token],
language: Language,
rules: Rules,
facts: Facts,
scopes: Vec<Scope>,
depth: i32,
}
mod calls;
mod declarations;
mod fields;
mod imports;
mod scopes;
mod traversal;
#[cfg(test)]
mod tests;