Add pure modular source3 project compiler and update APIs
This commit is contained in:
+119
-3
@@ -745,7 +745,7 @@ sets and enum constructors are closed by sections 3–5.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
document = "arcadia" "2" ";" project
|
||||
document = "arcadia" "3" ";" project
|
||||
project = "project" alias string identity? "{" project-entry* "}"
|
||||
project-entry = "description" string ";" | declaration
|
||||
declaration = (kind | "diagram" | "artifact" | "trace")
|
||||
@@ -784,6 +784,87 @@ Ordinary string fields require quoted strings and cannot contain an unquoted
|
||||
constructor records. Typed values MUST NOT nest more than 64 levels; malformed
|
||||
deeply nested drafts produce a diagnostic instead of exhausting the parser stack.
|
||||
|
||||
6.1. Modular source3 projects
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The pure ``source_project`` core API compiles a virtual source bundle, containing
|
||||
``entry`` and a ``files`` map from logical paths to UTF-8 strings. Its entry is a
|
||||
root-level ``.arcadia`` file with the source3 project header above. A project entry
|
||||
MAY also be ``include string ";"``. An included fragment consists only of ordinary
|
||||
declarations and include statements; it MUST NOT contain another version header,
|
||||
project wrapper, or project description. Includes MUST occur between declarations,
|
||||
never inside a typed field value. For example::
|
||||
|
||||
arcadia 3;
|
||||
project rescue "Rescue" id "00000000-0000-4000-8000-000000000001" {
|
||||
description "Operational model";
|
||||
include "oa/participants.arcadia";
|
||||
include "oa/activities/activity_respond.arcadia";
|
||||
include "views/diagram_operational.arcadia";
|
||||
}
|
||||
|
||||
An include path is relative to its containing file. ``.`` and ``..`` segments
|
||||
normalize within the virtual project root; escaping that root is an error. Bundle
|
||||
keys MUST already be normalized, use forward slashes and the lowercase
|
||||
``.arcadia`` suffix, and contain no empty path segments. Absolute, drive, UNC,
|
||||
URL, backslash, control-character and non-portable Windows device paths are
|
||||
rejected. Paths ending a segment in dot or space are rejected. Keys that collide
|
||||
after Unicode lowercasing are rejected. References use the exact normalized
|
||||
spelling; filesystems do not participate in resolution.
|
||||
|
||||
Every reachable file is compiled once, including through repeated or diamond
|
||||
includes. Include cycles are errors with their chain and including location.
|
||||
Missing files, duplicate JSON file keys and supplied unreachable files are
|
||||
errors. The compiler MUST NOT read local files, network resources, environment
|
||||
variables or the process working directory. A future native loader is responsible
|
||||
for translating a directory into this explicit bundle and enforcing physical
|
||||
path ownership; the pure compiler grants no filesystem access.
|
||||
|
||||
``inspect_includes(path, source, is_entry, limits)`` supports native discovery
|
||||
before all included documents are available. It uses the same strict entry or
|
||||
fragment syntax parser, applies document byte/record and local include-edge
|
||||
budgets, and returns normalized targets with exact directive spans. Comments and
|
||||
strings that mention include syntax are not directives. A syntax failure anywhere
|
||||
in the document returns located errors and no partial include list; it does not
|
||||
scan arbitrary token strings after failure. Global references and engineering
|
||||
validation are deferred to bundle compilation. A native loader MUST retain the
|
||||
unparsed draft on failure and enforce aggregate bytes/files/depth/edges while
|
||||
loading; this inspection call does not own or inspect a directory.
|
||||
|
||||
All files share the existing global alias/UUID namespace. Files add no semantic
|
||||
namespace, implicit parent, allocation or port contract. Forward references work
|
||||
across files. Duplicate aliases and identities report the offending declaration
|
||||
and the previous declaration location, including collisions with the project.
|
||||
Moving a declaration between files MUST preserve the resulting model and UUIDs.
|
||||
|
||||
``ProjectLimits`` adds file, include-depth and include-edge budgets to the existing
|
||||
``language::ParseLimits``. Model bytes, graph objects, records and ordered
|
||||
references are counted across the complete bundle, never reset per file. The
|
||||
default candidate policy is 256 files, depth 32 (entry depth zero), 1,024 include
|
||||
edges and 64 MiB combined UTF-8 source. Other model counts remain caller policy.
|
||||
Repeated include edges count toward the edge budget; file contents count once.
|
||||
The compiler admits input and stabilized output against the same limits.
|
||||
|
||||
``compile_bundle`` returns either located errors and no candidate, or a
|
||||
``CompiledSourceProject`` with the validated ``DecodeResult``, stabilized bundle,
|
||||
derived ``SourceIndex`` and located engineering warnings. It inserts explicit
|
||||
UUID clauses into headers that omitted them without otherwise reformatting the
|
||||
input. The returned source index and diagnostics address the returned stabilized
|
||||
bytes. Clients MUST retain that bundle after successful Apply; recompiling the
|
||||
original buffers with missing identities would generate fresh identities.
|
||||
|
||||
Bundle diagnostics wrap the existing Diagnostic with a logical path and optional
|
||||
related locations. Declaration spans, top-level field value spans, project
|
||||
header/body/description spans and resolved include locations are available in
|
||||
the source index. Columns remain one-based Unicode scalars within the real file;
|
||||
spans never refer to concatenated or synthetic source.
|
||||
|
||||
Single-string parse/lint APIs remain filesystem-free and reject include
|
||||
statements with an explicit source-bundle requirement. V1/V2 single-file imports
|
||||
continue through their existing migration readers and reports. Modular projects
|
||||
require source3; migration is performed before modular export, not independently
|
||||
on included fragments. Modular source does not change the semantic JSON schema.
|
||||
|
||||
7. Canonical output and source tooling
|
||||
--------------------------------------
|
||||
|
||||
@@ -806,11 +887,46 @@ relations; diagrams and their nodes follow, then artifacts, then traces.
|
||||
Fields use deterministic name order. Output ends with LF. Alias values come
|
||||
from the model, never from regenerating display names.
|
||||
|
||||
Comments and input whitespace are lexical trivia. Canonicalizing or applying
|
||||
source does not preserve them; the editor MUST explain that behavior.
|
||||
Comments and input whitespace are lexical trivia to the canonical writer.
|
||||
Canonical export and the current desktop single-document Apply path do not
|
||||
preserve them; the editor MUST explain that behavior. This existing path does not
|
||||
define an acceptable lossless authoring policy for a future project editor.
|
||||
The pure project compiler in section 6.1 preserves them while inserting missing
|
||||
identities. Project update/export distinctions are described below.
|
||||
Camera position, selection, source cursor, and undo history are not stored
|
||||
model fields. Layout and collapse state inside NodePlacement are model data.
|
||||
|
||||
The pure ``format_bundle`` exporter uses the same typed declaration writer as
|
||||
``format``. It creates a small entry file, layer/category modules, separate
|
||||
activity/function roots and behavior contexts, and separate diagrams with their
|
||||
placements. Ports follow their owner; relations follow their source/context.
|
||||
Module names derive from persistent aliases, not display names or UUID chunks.
|
||||
Declarations are ordered by semantic ancestry and alias, with owners before
|
||||
descendants. Case-colliding generated file names receive deterministic numeric
|
||||
suffixes. When more than 240 distinct modules would be produced, aggregate
|
||||
folders consolidate into category modules to avoid thousands of tiny files.
|
||||
For every valid P, ``compile_bundle(format_bundle(P)).decoded.project == P``
|
||||
when the caller supplies sufficient admission budgets.
|
||||
|
||||
``update_bundle(compiled, P, limits)`` is a core prototype update facility. It
|
||||
checks that the compiled document/index/model snapshot still agrees, preserves
|
||||
existing declaration file ownership and all untouched document bytes, and
|
||||
recompiles the result before returning it. New children inherit their owner's
|
||||
file; new roots use canonical module rules and add an explicit entry include.
|
||||
Removed declarations do not delete source files. Alias changes also update
|
||||
declarations containing references to that alias. Invalid or stale updates
|
||||
return errors without mutating the input workspace.
|
||||
|
||||
The current update facility canonicalizes each changed declaration in full.
|
||||
It therefore DOES NOT preserve inline comments or custom layout inside that
|
||||
declaration, even for a single scalar edit. This is an explicit prototype
|
||||
limitation, not final authoring/save acceptance. A lossless project editor needs
|
||||
minimal header/field/value edits that preserve unrelated tokens and comments;
|
||||
the available source spans provide the starting point. Canonical modular export
|
||||
is a distinct, explicit operation and does not promise original comment/layout
|
||||
preservation. No native multi-file editor, project save transaction or REST
|
||||
bundle endpoint is claimed by the pure core APIs.
|
||||
|
||||
``parse`` returns a complete structurally validated candidate or error
|
||||
diagnostics and no model. Engineering warnings alone MUST NOT reject a valid
|
||||
candidate. Parsing may stop at the first syntax/conversion error. Diagnostics
|
||||
|
||||
Reference in New Issue
Block a user