Skip to main content

only_semantic/
analysis.rs

1use only_diagnostic::DiagnosticPhase;
2use only_syntax::{BootstrapHeader, SyntaxSnapshot, bootstrap, snapshot};
3
4use crate::SemanticSnapshot;
5use crate::lower::lower_syntax;
6use crate::symbols::build_symbol_index;
7use crate::validate::validate_document;
8
9/// Compiles source text into a semantic snapshot shared by hosts.
10///
11/// Args:
12/// source: Raw Onlyfile source text.
13///
14/// Returns:
15/// Immutable semantic snapshot with AST, diagnostics and symbols.
16pub fn compile_document(source: &str) -> SemanticSnapshot {
17    compile_syntax(&snapshot(source))
18}
19
20/// Compiles source after checking its optional language version declaration.
21pub fn compile_document_for_runner(source: &str, runner_version: &str) -> SemanticSnapshot {
22    compile_document_with_runner(source, runner_version).1
23}
24
25/// Compiles source and retains the syntax snapshot created after the version gate.
26pub fn compile_document_with_runner(
27    source: &str,
28    runner_version: &str,
29) -> (SyntaxSnapshot, SemanticSnapshot) {
30    let header = match bootstrap(source, runner_version) {
31        Ok(header) => header,
32        Err(diagnostic) => return snapshot_with_version_error(diagnostic),
33    };
34    let syntax = snapshot(source);
35    let mut compiled = compile_syntax(&syntax);
36    append_unversioned_parse_help(&mut compiled, header);
37    (syntax, compiled)
38}
39
40/// Compiles a pre-parsed syntax snapshot into a semantic snapshot shared by hosts.
41///
42/// Args:
43/// snapshot: Immutable syntax snapshot for one source version.
44///
45/// Returns:
46/// Immutable semantic snapshot with AST, diagnostics and symbols.
47pub fn compile_syntax(snapshot: &SyntaxSnapshot) -> SemanticSnapshot {
48    let (document, mut diagnostics) = lower_syntax(snapshot);
49    let symbols = build_symbol_index(&document);
50    diagnostics.extend(validate_document(&document, &symbols));
51
52    SemanticSnapshot {
53        document,
54        diagnostics,
55        symbols,
56    }
57}
58
59fn snapshot_with_version_error(
60    diagnostic: only_diagnostic::Diagnostic,
61) -> (SyntaxSnapshot, SemanticSnapshot) {
62    let syntax = snapshot("");
63    let mut compiled = compile_syntax(&syntax);
64    compiled.diagnostics.push(diagnostic);
65    (syntax, compiled)
66}
67
68fn append_unversioned_parse_help(compiled: &mut SemanticSnapshot, header: BootstrapHeader) {
69    if header.required_version.is_some() {
70        return;
71    }
72
73    if let Some(diagnostic) = compiled
74        .diagnostics
75        .iter_mut()
76        .find(|diagnostic| diagnostic.phase == DiagnosticPhase::Parse)
77    {
78        diagnostic.message.push_str(
79            "\nnote: this file has no `!version` line\nhelp: check the syntax; it may need a newer version of only",
80        );
81    }
82}