Parser i diagnostyka
KitsuneScript 3.0.0 rozdziela kompilację fail-fast od analizy edytorskiej. Wykonanie skryptu nadal zatrzymuje się na pierwszym błędzie, natomiast language service odzyskuje parser po granicy instrukcji i może zwrócić wiele niezależnych problemów.
Cały parser jest częścią logicznego artefaktu rip.nerd.kitsunescript:kitsunescript:3.0.0 dodawanego do commonMain. Gradle wybiera wariant platformowy automatycznie; nie istnieje osobny ani uproszczony parser dla iOS, Web lub Androida.
Zalecane API dla edytora
val service = KitsuneScriptLanguageService(config)
val diagnostics = service.diagnose(source, "rules.ks")
diagnostics.forEach { issue ->
println("${issue.kind}: ${issue.position} ${issue.message}")
}
diagnose nie wykonuje kodu, nie instaluje stdlib i respektuje limity źródła, tokenów, literałów oraz głębokości parsera z EngineConfig.
Bezpośrednie API parsera
val tokens = Lexer(source, "rules.ks").scanTokens()
// Kompilator i runtime: wyjątek przy pierwszym błędzie.
val program = Parser(tokens).parse()
// IDE/linter: częściowy AST i maksymalnie 100 diagnostyk.
val result = Parser(tokens).parseRecovering(maxDiagnostics = 100)
Każdy ParserDiagnostic zawiera komunikat i token z dokładnym indeksem, linią oraz kolumną. Częściowego AST nie należy wykonywać, ponieważ służy wyłącznie do analizy narzędziowej.
Zakresy, dokument i LSP
val document = IncrementalScriptDocument(source, "rules.ks")
val afterEdit = document.apply(ScriptTextEdit(12, 13, "2"))
val lsp = KitsuneScriptLanguageServerAdapter()
val issues = lsp.diagnostics(afterEdit.source, afterEdit.sourceName)
val formatted = lsp.format(afterEdit.source)
Diagnostyka zawiera teraz SourceRange z końcem wyłącznym. Dokument waliduje granice zmian, nadaje im monotoniczną wersję i nie uruchamia parsera ponownie dla odczytu bez zmiany. Adapter łączy błędy parsera z bezpiecznymi regułami lint i formatowaniem, dzięki czemu może być użyty przez IntelliJ, VS Code albo zewnętrzny serwer LSP.
Formatter i wersja AST
KitsuneScriptFormatter celowo jest konserwatywny: poprawia wcięcia i białe znaki, ale nie przepisuje wyrażeń. Nawiasy wewnątrz napisów i komentarzy nie wpływają na wcięcie. Narzędzia zapisujące AST powinny umieszczać KitsuneScriptAstSchema.CURRENT_VERSION i odrzucać nieznaną wersję zamiast wykonywać ją przez przypadek.
Parser z aplikacji iOS i Swift
val bridge = KitsuneScriptSwift("editor-preview", maxSteps = 100_000)
val issues = bridge.diagnostics(source, "preview.ks")
val result = bridge.executeWithParameters(source, """[{"locale":"pl"}]""")
bridge.close()
Facade Swift korzysta dokładnie z tego samego leksera, parsera odzyskującego, formattera i limitów co Android/JVM/Web. Diagnostyka ma wyłącznie pola proste, a wyniki wykonania są ścisłym JSON-em. executeBundle przyjmuje obiekt JSON ścieżka -> źródło, sprawdza ścieżki względne i pozwala parserowi obsłużyć importy bez dostępu do systemu plików iOS.
Granice i błędy
- Tokeny przekazane ręcznie muszą kończyć się tokenem
EOF. maxDiagnosticsmusi być dodatni; domyślny limit wynosi 100.- Parser synchronizuje się po średniku albo początku kolejnej deklaracji/instrukcji.
- Interpolacja
${expression}musi mieć zamykający nawias i dokładnie jedno pełne wyrażenie. - Błędy limitów mają rodzaj
LIMIT, pozostałe błędy składni rodzajSYNTAX.
Parser and diagnostics
KitsuneScript 3.0.0 separates fail-fast compilation from editor analysis. Script execution still stops at the first error, while the language service recovers at statement boundaries and can return multiple independent issues.
The complete parser belongs to the logical rip.nerd.kitsunescript:kitsunescript:3.0.0 artifact added to commonMain. Gradle selects the platform variant automatically; iOS, Web and Android do not use separate or reduced parsers.
Recommended editor API
val service = KitsuneScriptLanguageService(config)
val diagnostics = service.diagnose(source, "rules.ks")
diagnostics.forEach { issue ->
println("${issue.kind}: ${issue.position} ${issue.message}")
}
diagnose never executes code or installs the standard library. It honors source, token, literal and parser-depth limits from EngineConfig.
Direct parser API
val tokens = Lexer(source, "rules.ks").scanTokens()
// Compiler and runtime: throw on the first error.
val program = Parser(tokens).parse()
// IDE/linter: partial AST and at most 100 diagnostics.
val result = Parser(tokens).parseRecovering(maxDiagnostics = 100)
Each ParserDiagnostic contains a message and token with an exact index, line and column. Never execute the partial AST because it exists for tooling only.
Ranges, documents and LSP
val document = IncrementalScriptDocument(source, "rules.ks")
val afterEdit = document.apply(ScriptTextEdit(12, 13, "2"))
val lsp = KitsuneScriptLanguageServerAdapter()
val issues = lsp.diagnostics(afterEdit.source, afterEdit.sourceName)
val formatted = lsp.format(afterEdit.source)
Diagnostics now expose an end-exclusive SourceRange. The document validates edit boundaries, assigns monotonic versions and reuses diagnostics between unchanged reads. The adapter combines parser errors, conservative lint rules and formatting for IntelliJ, VS Code or an external LSP server.
Formatter and AST version
KitsuneScriptFormatter only normalizes indentation and whitespace; it does not rewrite expressions. Braces inside strings and comments do not affect indentation. Tools persisting an AST should record KitsuneScriptAstSchema.CURRENT_VERSION and reject unknown versions before execution.
Parser from iOS and Swift
val bridge = KitsuneScriptSwift("editor-preview", maxSteps = 100_000)
val issues = bridge.diagnostics(source, "preview.ks")
val result = bridge.executeWithParameters(source, """[{"locale":"en"}]""")
bridge.close()
The Swift facade uses the exact same lexer, recovering parser, formatter and limits as Android/JVM/Web. Diagnostics contain primitive fields only, while execution results use strict JSON. executeBundle accepts a JSON path -> source object, validates relative paths and lets the parser resolve imports without iOS filesystem access.
Boundaries and errors
- Manually supplied token streams must end with
EOF. maxDiagnosticsmust be positive; the default limit is 100.- Recovery synchronizes after a semicolon or at the next declaration/statement starter.
- An interpolation
${expression}must close and contain exactly one complete expression. - Limit failures use
LIMIT; other syntax failures useSYNTAX.