collect_doc_comments

func collect_doc_comments(source: String, outcome: &ParseOutcome) -> DocIndex

Attaches leading line-comment groups without changing the parser token stream.

A group must end on the line immediately before a declaration after skipping declaration modifiers. Imports may be crossed as one block, but any blank line breaks attachment. The merge is ordered and local declarations are excluded.

View Source
pub func collect_doc_comments(source: String, outcome: &ParseOutcome) -> DocIndex {
	let view = source.utf8()
	let spans = collect_item_spans(items: outcome.items, spans: [])
	let entries: [DocumentedDecl] = []
	let orphans: [Comment] = []
	let group: [Comment] = []
	let si = 0
	for c in outcome.comments {
		// A comment sharing its line with preceding code is trailing.
		let trailing = false
		let j = c.start - 1
		loop j >= 0 {
			let b = view.at(index: j)._toInt()
			if b == newline_byte { break }
			if b == space_byte || b == tab_byte || b == return_byte {
				j = j - 1
				continue
			}
			trailing = true
			break
		}
		if trailing {
			let f = flush_group(source: source, group: group, spans: spans, si: si)
			si = f.si
			group = []
			if let .some(e) = f.entry { entries.push(e) }
			for o in f.orphans { orphans.push(Comment(start: o.start, end: o.end)) }
			orphans.push(Comment(start: c.start, end: c.end))
			continue
		}
		// `// no-core` is a compiler pragma, not documentation: it
		// breaks the current group and never attaches.
		if c.end - c.start == 10 {
			let is_pragma = true
			let pragma = "// no-core".utf8()
			let p = 0
			loop p < 10 {
				if view.at(index: c.start + p)._toInt() != pragma.at(index: p)._toInt() {
					is_pragma = false
					break
				}
				p = p + 1
			}
			if is_pragma {
				let f = flush_group(source: source, group: group, spans: spans, si: si)
				si = f.si
				group = []
				if let .some(e) = f.entry { entries.push(e) }
				for o in f.orphans { orphans.push(Comment(start: o.start, end: o.end)) }
				orphans.push(Comment(start: c.start, end: c.end))
				continue
			}
		}
		// A group continues only across adjacent comment lines.
		if group.is_empty() == false {
			let k = group[group.count - 1].end
			let newlines = 0
			let blocked = false
			loop k < c.start {
				let b = view.at(index: k)._toInt()
				if b == newline_byte {
					newlines = newlines + 1
				} else if b == space_byte || b == tab_byte || b == return_byte { } else {
					blocked = true
				}
				k = k + 1
			}
			if blocked || newlines != 1 {
				let f = flush_group(source: source, group: group, spans: spans, si: si)
				si = f.si
				group = []
				if let .some(e) = f.entry { entries.push(e) }
				for o in f.orphans { orphans.push(Comment(start: o.start, end: o.end)) }
			}
		}
		group.push(Comment(start: c.start, end: c.end))
	}
	let f = flush_group(source: source, group: group, spans: spans, si: si)
	if let .some(e) = f.entry { entries.push(e) }
	for o in f.orphans { orphans.push(Comment(start: o.start, end: o.end)) }
	DocIndex(entries: entries, orphans: orphans)
}