///|
/// Counting result for a set of files of one language.
pub(all) struct Counts {
mut files : Int32
mut lines : Int32
mut code : Int32
mut comments : Int32
mut blanks : Int32
blobs : Map[String, Counts]
}
///|
pub fn Counts::add(self : Counts, other : Counts) -> Unit {
self.files += other.files
self.lines += other.lines
self.code += other.code
self.comments += other.comments
self.blanks += other.blanks
for kv in other.blobs {
match self.blobs.get(kv.0) {
Some(existing) => existing.add(kv.1)
None => self.blobs.set(kv.0, kv.1.copy())
}
}
}
///|
/// Aggregation must not mutate a per-file report that shares this value.
pub fn Counts::copy(self : Counts) -> Counts {
let blobs : Map[String, Counts] = Map([])
for kv in self.blobs {
blobs.set(kv.0, kv.1.copy())
}
{
files: self.files,
lines: self.lines,
code: self.code,
comments: self.comments,
blanks: self.blanks,
blobs,
}
}
///|
pub fn Counts::new() -> Counts {
{ files: 0, lines: 0, code: 0, comments: 0, blanks: 0, blobs: Map([]), }
}
///|
priv enum Tok {
LineTok // line comment starter (includes doc comments)
BlockTok(String, String) // block comment (start, end)
StrTok(Int32) // index into the merged string token table
}
///|
priv enum St {
Normal
InBlock(Int32, String, String) // depth, current start marker, end marker
InStr(Int32) // index into merged string token table
}
///|
priv struct StrTokDef {
start : String
end : String
escapable : Bool
}
///|
priv struct Matcher {
line_toks : Array[String] // sorted by length desc
block_toks : Array[(String, String)] // sorted by start length desc
str_toks : Array[StrTokDef] // sorted by start length desc
}
///|
fn build_matcher(lang : @lang.LangDef) -> Matcher {
let line_toks : Array[String] = []
for t in lang.line_comments {
line_toks.push(normalize_token(t))
}
// `important_syntax` marks language-specific constructs such as HTML
//