feat: publish Dever core with project scaffolding and versioned AI skills
This commit is contained in:
1 parent
70fa73cdc2
commit
ac458ffa7f
960 files changed
+221319
-1163
No files matched your search
@@ -0,0 +1,793 @@
|
||||
# Dever Minimal Core 0.1 Design
|
||||
|
||||
## N4 Concurrent Composition And Reusable Clients (2026-09-12, Complete)
|
||||
|
||||
Source `dever.task.start` establishes the one runtime from a synchronous entry with an explicit configuration and static async handler. HTTP system primitives infer an optional final transferable context and pass it to a statically checked handler; applications can wrap this in their own concrete context signature. Ordinary records retain value semantics; Channel/client/resource fields share their existing resource identity.
|
||||
|
||||
`timeout(task, millis, fallback)` consumes a Task, waits for cancellation cleanup on expiry, then invokes a zero-input async fallback with the identical output signature. `race(tasks...)` consumes equally typed tasks and drains losers before returning the first result. Neither operation suppresses program faults. `stream(Channel|List|Bytes)` and periodic `dever.task.ticks` are pull-driven; async memory traversal reuses collection handlers and bounded Group dispatch.
|
||||
|
||||
Network clients own bounded reusable HTTP/1 connections and stream bodies. TLS uses tokio-rustls/ring, with certificate verification, bundled public roots and explicit custom roots/server PEM material. TCP/TLS share the concrete I/O owner used by HTTP and WebSocket upgrades. Protocol parsing stays in Hyper/tungstenite. Idle connections, pending requests, body chunks and cancellation have explicit owners. No HTTP/2, implicit retries, redirects or detached connection drivers.
|
||||
|
||||
The implemented pool fixes one origin per shared HttpClient and uses Hyper's low-level HTTP/1 API. Separate request and physical-connection permits include idle/queued drivers in the same limit. One structured task drives the bounded queue and FuturesUnordered, expiring idle entries without a future request. Its owner guard is constructed before task creation, including the unpolled-child cancellation case. Response EOF returns its lease; early close/fault/cancellation aborts the connection. Listener.close triggers graceful HTTP shutdown; timeout(server, grace_ms, fallback) bounds draining active responses and upgrades.
|
||||
|
||||
Locked additions are tokio-rustls 0.26.5, rustls 0.23.44 with ring/std/tls12 and webpki-roots 1.0.8. Shared TLS configuration uses small explicit session-cache capacities. Transport boxes only the large TLS variant; ordinary TCP stays direct. The backend example combines configured source entry, concrete Context with Channel, a pooled request and graceful shutdown on an owned random loopback port.
|
||||
|
||||
## N3 Streaming HTTP, SSE And WebSocket (2026-09-12, Approved)
|
||||
|
||||
Keep ordinary `serve` direct; `serve_live` binds an async zero-output `(Request, HttpReply)` handler. A Group of one owns each connection's live handler. Shared request decoding, checked response encoding and Hyper configuration avoid a parallel HTTP implementation. A one-slot body channel provides backpressure. Response-body Drop signals cancellation for streamed, buffered and HEAD responses; Session cleanup closes the producer or upgraded socket. Handler faults propagate and cannot be emitted as a successful truncated body.
|
||||
|
||||
On upgrade, wait for Hyper's driver, extract its known TcpStream and preread bytes, then keep the connection reservation while awaiting the handler Group. This removes the HTTP write deadline and the need for an extra transport abstraction. WebSocket uses independent reader/writer locks around tokio-tungstenite split halves, the shared Endpoint close signal and bounded message/write buffers with a 4 KiB read buffer. Acquire the writer lock before arming cancellation cleanup. close takes final transport ownership, wakes other operations and completes a bounded handshake.
|
||||
|
||||
SSE is a small field encoder plus response-body timer; no routing framework or heartbeat task is needed. Preserve CR/LF/CRLF and trailing data lines, compute final size before allocation and reserve Content-Type for the protocol. Request headers carry Last-Event-ID; replay belongs to application code. WebSocket control frames are processed while receive/messages is polled; no automatic reader or Ping task. Public exact limits and lifecycle are defined once in LANGUAGE.md.
|
||||
|
||||
References checked: [tokio-tungstenite 0.30.0](https://docs.rs/tokio-tungstenite/0.30.0/tokio_tungstenite/), [WebSocketConfig](https://docs.rs/tungstenite/0.30.0/tungstenite/protocol/struct.WebSocketConfig.html), [EventSource parsing](https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream). No TLS, HTTP/2, pooling, protocol extensions or compatibility layer in N3.
|
||||
|
||||
## N2 HTTP Engine (2026-09-12, Approved)
|
||||
|
||||
Hyper HTTP/1 owns parsing/framing/persistence, using the existing Tokio runtime and only hyper-util's Tokio I/O/timer adapter. No Axum dependency is needed for the current single static route contract. This supersedes earlier source-only HTTP and per-request fault-isolation proposals below: handler program faults propagate through the structured server task, while peer protocol/I/O failures end only that connection.
|
||||
|
||||
Official source owns Header/Request/Response/Limits, header helpers, send and serve. Header is Text name plus Bytes value; List preserves repeated values. Native conversions resolve fields by name after exact shape checks. Intrinsic carries an optional static callback; callback extraction is shared with Collection for dependency/cycle/specialization traversal, and handler effects/recovery propagate through the existing summaries.
|
||||
|
||||
HTTP accepts unique Tokio streams through the existing Listener owner before constructing any aliased public Socket. Existing AsyncStream/Group reserves capacity before accept, observes connection faults while idle, and drains descendants on stop. Hyper never spawns a detached connection driver. Client send polls driver and response in the same bounded future and releases both on completion/cancellation; pooling is deferred.
|
||||
|
||||
Bytes uses bytes::Bytes for shared engine storage, slicing and compatible Text ownership transfer. Bodies are buffered within explicit limits, merging fragments incrementally without retaining one metadata entry per tiny frame. Header, body, handler and stalled-write deadlines have separate owners. The public contract and exact protocol exclusions are in LANGUAGE.md; TLS/HTTP2, streaming responses, client pooling and WS/SSE are not N2 deliverables.
|
||||
|
||||
## N1 Async Stream And TCP (2026-09-12, Approved)
|
||||
|
||||
This new-language phase supersedes the historical compatibility baseline and network pause below. Migrate callers directly; no synchronous TCP backend, aliases or fallback paths.
|
||||
|
||||
Use one existing Tokio runtime with its I/O driver enabled. AsyncStream owns one Send stream producer, serializes pulls, and shares a close signal across aliases. Closing or finishing a consumer releases its producer; there is no unbounded buffer or per-item boxed future. Stream remains the distinct synchronous file-sequence type.
|
||||
|
||||
Socket and Listener share explicit resource closure. Socket read and write have independent async locks; closure wakes both. A write tracks partial progress and closes the socket if abandoned after writing any bytes, so subsequent operations cannot append to a truncated message. Operation timeout includes waiting for its direction lock. No retry of an entire interrupted write.
|
||||
|
||||
AsyncStream traversal may call synchronous effect-checked handlers or async handlers. parallel_each on AsyncStream requires an async zero-output handler and uses the existing structured Group. It checks completed tasks and acquires group capacity before pulling, and observes handler failures even while the producer is idle. No new detached task model or private thread pool.
|
||||
|
||||
Compiler types, effects, liveness, native specialization, official network API and existing HTTP transport move together. The synchronous reference evaluator explicitly excludes async execution; no second network implementation is retained for differential tests.
|
||||
|
||||
## Structured Concurrency Design And Implementation Contract (2026-09-12)
|
||||
|
||||
This preceding phase is implemented through the compiler frontend, checked HIR, native backend and bounded runtime, with evidence in `implement.md`. It superseded the first-stage no-async model. The current N1 decision permits direct source-contract changes without a compatibility baseline.
|
||||
|
||||
### One Task Model
|
||||
|
||||
Dever has one concurrency model rather than separate async, coroutine and thread abstractions:
|
||||
|
||||
- an async function compiles to a stackless coroutine;
|
||||
- `await` suspends that coroutine without occupying a worker thread;
|
||||
- `run` schedules the coroutine as a child Task;
|
||||
- the runtime may move transferable tasks across worker threads;
|
||||
- `parallel` and `blocking` cross from async scheduling into bounded synchronous execution.
|
||||
|
||||
The program creates one Tokio runtime at an async entry point. A program whose reachable entry graph is entirely synchronous retains the current direct native entry and does not initialize Tokio. The runtime configuration owns async worker count, blocking capacity and task limits once; packages do not create private runtimes or pools.
|
||||
|
||||
### Source Surface
|
||||
|
||||
`async` prefixes a function clause. Every clause in one logical function must agree on this modifier:
|
||||
|
||||
```dever
|
||||
async load_user(id: Id) (user: User) {
|
||||
user = await(fetch_user(id))
|
||||
}
|
||||
```
|
||||
|
||||
An async call is context-only, not an ordinary storable future. It may appear directly under `await`, `run` or the matching compiler-owned task operation. This avoids adding a general `Awaitable<T>` value and preserves the current static-call model.
|
||||
|
||||
```dever
|
||||
first = run(load_user(first_id))
|
||||
second = run(load_user(second_id))
|
||||
first_user = await(first)
|
||||
second_user = await(second)
|
||||
```
|
||||
|
||||
`await(async_call(...))` invokes and waits without creating a separately owned Task. `run(async_call(...))` starts first and returns an affine Task whose associated output signature remains in checked HIR. `await(task)` consumes it and yields the same zero, single or named multi-output shape as the function. Task operations consistently use the language's existing call appearance; no second prefix spelling is accepted.
|
||||
|
||||
Static handler syntax places `async` before `handler`:
|
||||
|
||||
```dever
|
||||
async serve(
|
||||
route: async handler(request: Request) (response: Response)
|
||||
) () {
|
||||
response = await(route(request))
|
||||
}
|
||||
```
|
||||
|
||||
`async` has one canonical declaration position immediately before the function name. Existing `pure` and `recover` contracts retain their post-signature positions. Parser, formatter, Markdown signatures and examples must change atomically; no postfix async spelling is accepted.
|
||||
|
||||
### Task Ownership
|
||||
|
||||
Task is a compiler-owned affine local type, not a new user-defined generic facility. It may be held only in a local slot of the async function that created it. It cannot be copied, compared, stored in an aggregate, passed as an ordinary value, returned, captured by a handler or left live at any clause exit.
|
||||
|
||||
Each async entry and spawned task has an internal runtime Scope; the compiler treats every async function as a lexical ownership scope. Directly awaited calls inherit the current Scope because runtime faults cannot be caught, while `run` and Group create a supervised child Scope. Every Task must be consumed exactly once by `await` or `stop`. On abnormal runtime exit, the root or child supervisor requests cancellation and waits for descendant and blocking-work cleanup before returning the failure. There is no detached task in the first release.
|
||||
|
||||
`stop` means cancel-and-wait, not fire-and-forget cancellation. To keep failure and output obligations explicit, the first release accepts only zero-output Task values. Result-bearing tasks must be awaited. Cancellation is cooperative at await/yield boundaries; it neither kills a running synchronous operation nor rolls back effects that already occurred.
|
||||
|
||||
### Dynamic Task Groups
|
||||
|
||||
`group(limit)` creates an affine Group for a dynamic number of zero-output async calls. It is needed for later connection/session ownership without allowing detached children:
|
||||
|
||||
```dever
|
||||
workers = group(128)
|
||||
run(workers, serve_connection(connection))
|
||||
await(workers)
|
||||
```
|
||||
|
||||
`run(group, async_call(...))` transfers the child into the Group and returns no Task. It may suspend while the positive capacity limit is full, providing backpressure before starting more work. Ungrouped `run(async_call(...))` is likewise subject to the owning function scope's task limit. `await(group)` closes admission, waits for all children and consumes the Group. `stop(group)` closes admission, requests cancellation, waits for every child and consumes the Group. Group cannot be copied, stored or escape its creating async function.
|
||||
|
||||
Only zero-output calls enter a Group, so the runtime cannot accumulate unbounded result values and expected failures cannot be silently discarded. A later result-collecting combinator must define ordering and memory limits separately.
|
||||
|
||||
### Thread Transfer And Execution Classes
|
||||
|
||||
The type model derives a `transferable` property recursively, alongside the existing comparison/move/transfer properties. Bool, numeric values, Text, Id and Bytes are transferable. Records, choices, nullable values, Lists and Maps are transferable only when every nested value is transferable. Each opaque resource is opted in only when its runtime representation and lifecycle are thread-safe; the current pull-based Stream is initially non-transferable.
|
||||
|
||||
Values live across an `await`, captured by `run`, or passed through channel/parallel boundaries must be transferable. Last-use analysis may move uniquely owned values into a task; otherwise ordinary value semantics require a copy. This rule is checked before native emission and is not delegated to a Rust compiler error.
|
||||
|
||||
Execution classes remain distinct:
|
||||
|
||||
- ordinary synchronous calls execute inline;
|
||||
- `run` schedules an async call on the shared runtime;
|
||||
- `parallel(sync_call(...))` accepts only a pure synchronous target with transferable inputs/outputs and runs it through bounded CPU execution;
|
||||
- `blocking(sync_call(...))` accepts a synchronous target whose transitive effect summary contains a compiler-known blocking system boundary and uses bounded blocking capacity.
|
||||
|
||||
`parallel` and `blocking` are async-context operations in the first release: they suspend their caller until the synchronous call completes. Synchronous code continues to use `parallel_each`; it does not initialize Tokio solely to access these operators.
|
||||
|
||||
Existing synchronous `parallel_each` keeps its public behavior and joined scoped workers. Async List/Bytes lowering requires a named synchronous function with no transitive concurrency effect, then submits bounded batches directly to the shared Tokio blocking executor, so it neither blocks a Tokio scheduling worker nor creates a nested thread pool. Other collection operations inspect the complete handler effect and cannot hide blocking, concurrency or an unconstrained handler effect on a Tokio scheduling worker. The first release has no handler effect bounds, so an async function cannot invoke a synchronous handler parameter inline. Both parallel paths share worker-limit and batch-size validation. Synchronous Stream remains unavailable in async functions until async Stream is designed.
|
||||
|
||||
### Channels
|
||||
|
||||
`channel(Type, capacity)` is compiler-contextual syntax: its first operand is a TypeRef, not a runtime type value. It creates a bounded `Channel<Type>` resource. Capacity is required, positive and capped. This deliberately avoids adding generic function invocation syntax solely for one constructor.
|
||||
|
||||
Channel aliases share one state. `send(channel, value)` asynchronously waits for capacity; `receive(channel)` asynchronously waits for an item and returns `Item?`, where a value is an item and `null` means the Channel is closed. Because nullable types are idempotent, receiving from `Channel<Item?>` also returns `Item?`; native emission flattens the runtime's nested option. A runtime scheduler or Channel fault remains a located fatal execution failure rather than a domain value. `close(channel)` is idempotent and wakes blocked senders and receivers. No unbounded constructor exists. Values must be transferable. Channel itself cannot be a Map key or comparable value, and its close/alias behavior follows explicit resource semantics rather than ordinary value semantics.
|
||||
|
||||
### Effects, Failures And Static Handlers
|
||||
|
||||
Async is part of a function and handler signature. Sync callers cannot invoke async functions or async handlers. Async callers may invoke sync code directly and async code only through an explicit async operation. Collection handlers remain synchronous because collection operations do not await handler futures; async handlers are called only through `await` or `run`. Handler specialization keys include the async signature bit, and cycle detection continues across await/run/forwarding edges; async does not legalize recursion.
|
||||
|
||||
`await`, `run`, `stop`, group operations, channel waits, timers, `parallel` and `blocking` are effects. The existing transitive effect graph owns these facts, so the first release rejects `async` together with `pure`. Task boundaries do not discharge error-bearing outputs: awaiting restores the original output obligations, while Group and stop accept only zero-output work. Runtime scheduler failure is a located fatal execution failure; expected domain failures remain explicit source choice values.
|
||||
|
||||
### HIR And Native Boundaries
|
||||
|
||||
The syntax tree records the async modifier and contextual concurrency expressions. Checked HIR owns explicit `AwaitCall`, `RunCall`, `AwaitTask`, `StopTask`, Group and Channel operations. It never represents a generic user-visible Future. Function metadata and HandlerSignature carry the async bit; Task stores its concrete checked output fields.
|
||||
|
||||
Native emission generates concrete Rust futures and direct calls. Static handlers remain specialized direct targets; no boxed dynamic callback, generic runtime Value, reflection registry or garbage collector is introduced. The runtime owns scheduler construction, task/group/channel state, limits and cancellation primitives. Compiler checks own source legality, transferability, affine consumption and diagnostic locations.
|
||||
|
||||
Runtime cancellation separates a business future from its supervisor. Task/Group stop aborts the business future; the supervisor itself remains alive, drains its child Scope, and only then publishes completion to the parent Scope. Started `spawn_blocking` jobs register a sticky completion signal because Tokio cannot abort them safely. Drop paths request cancellation and detach only supervisor handles whose completion is still owned and awaited by the parent Scope; no Drop implementation calls `block_on`.
|
||||
|
||||
### Compatibility And Deferred Work
|
||||
|
||||
Existing synchronous source and `parallel_each` behavior stay valid. `LANGUAGE.md`, Markdown contracts and API snapshots are updated with the implementation. The `run` source operator is distinct from the CLI command by grammar context.
|
||||
|
||||
The task-foundation phase deferred networking; N1 above resumes AsyncStream and TCP on these primitives. The HTTP engine and WebSocket/SSE remain later work. Detached tasks, arbitrary shared mutation, locks, user thread creation, unbounded channels and forceful cancellation remain out of scope.
|
||||
|
||||
## Markdown Source Follow-through (2026-09-09)
|
||||
|
||||
`.dever.md` is an additional source container alongside `.dever`. Top-level literal `dever` and `typescript dever` fences contain ordinary Dever declarations; the latter supplies a TypeScript highlighting hint while retaining an explicit Dever marker. A dedicated Markdown contract parser maps one H1 to the package header and one H2 to each type or logical function group before formatting. After shared signature resolution, semantic validation compares package/API/use metadata, type fields/variants and function inputs/outputs with syntax and HIR, retaining both documentation and declaration spans in diagnostics. Shared fence extraction keeps original spans for parsing, diagnostics and per-block formatting. `.dever` and language/runtime semantics are unchanged. The authoritative source-format contract is `LANGUAGE.md` and `.trellis/spec/backend/toolchain-and-library.md`; earlier `.dever`-only and unconstrained-heading limits below are superseded.
|
||||
|
||||
## Performance Implementation Boundary (2026-09-08)
|
||||
|
||||
- Compiler analysis worker owns types.rs, check.rs integration and contracts dependency scheduling: memoized type properties and monotone reverse-dependency work queues, retaining handler substitution and proof limits. Existing graph traversal is reused.
|
||||
- Cache worker owns source/parse caching, native/build.rs and its cache helper plus CLI cache integration if necessary. Cache identities include effective source, compiler/toolchain/runtime and options; checked API baselines stay outside cached native execution. No new external dependency or source format.
|
||||
- Main owns native liveness/emission, runtime collections, JSON/HTTP source algorithms, performance fixtures and integration. Record updates preserve value aliases and evaluation order; consuming iteration retains resource scope; direct split consumption avoids eager character lists; HTTP parsing tracks incremental boundaries and framing in Dever.
|
||||
- Root tests own semantic regressions and bounded before/after measurements; no services/full suite/commit. Workers are not alone and must preserve unrelated edits. Shared check.rs edits require coordination with the analysis owner. Independent final review checks values, failure order, cache invalidation and protocol bounds.
|
||||
|
||||
## Follow-through Implementation Design (2026-09-07)
|
||||
|
||||
This section owns the current follow-through; older extension boundaries below describe completed milestones.
|
||||
|
||||
- Formatter: add an AST writer using existing spans, preserved comments and precedence. Preserve record initializer expression order. CLI owns filesystem mutation and prepares every result before any rewrite. Expose syntax-only formatting separately from semantic checking.
|
||||
- Reference evaluator: add an opt-in `reference` compiler feature, not a runtime dependency. Consume checked HIR, normalized domains and static handler bindings; reuse runtime number/resource primitives. Frames hold value locals and preserve copy semantics. Capture stdout and named results for differential tests. Do not add an evaluator production CLI path.
|
||||
- Standard library: extend the single intrinsic/checker/native catalog for atomic representation/OS operations only. Public result choices live in `library/`; share runtime implementations with the evaluator. Text indexes are Unicode scalar positions; Bytes indexes remain byte offsets. Number parse failures are nullable results, never a silent zero; finite Decimal rules remain unchanged.
|
||||
- Optimization: analyze actual read order and writes per clause, retaining outputs and assignment hosts. Move dead values, preserve live aliases and short-circuit paths; transfer reduction state between iterations. Verify value semantics before performance comparison.
|
||||
- Parallel ownership: formatter worker owns formatter modules, formatting CLI and root format tests; reference worker owns evaluator modules and root differential tests. Main agent owns libraries, primitive integration, native optimization, task documents and integration. Coordinate shared module registration edits.
|
||||
- Verification uses offline focused targets and test-owned files/processes. Performance checks are bounded local computation, exclude compiler startup and use matching numeric/collection wrappers. Existing user sources are never formatter test fixtures.
|
||||
- Production native compilation and matching performance baselines share one optimization-argument owner (`opt-level=3`, `codegen-units=1`). The single generated source compiles as one unit to keep generic collection inlining independent of source size; compilation time is measured separately from hot paths.
|
||||
|
||||
- Status: Core foundations and foundation extension implemented and verified on 2026-09-07
|
||||
- Date: 2026-09-04
|
||||
- Product source of truth: `prd.md`
|
||||
|
||||
## Completed Foundation Boundary (Historical)
|
||||
|
||||
Extend the implemented core with the approved sequence and resource foundation: `reduce`, `reduce_until`, Bytes traversal, `Stream<Item>`, restricted static handler inputs, and file/TCP stream wrappers. Existing clause-only branching, linear bodies and the ban on source loops and user recursion remain permanent. Compiler distribution, cross-platform work and full HTTP/JSON/CRUD packages remain deferred.
|
||||
|
||||
Extend the existing checker and HIR in place. Represent user types nominally, resolve every function signature before bodies, prove clause coverage over symbolic input domains, and emit concrete native types/functions. Keep source expression order, including record construction; formatting must not reorder effectful field expressions. Use one runtime implementation for numeric operations, ordered collections and resource primitives. Bundled `.dever` sources define official wrappers and result types through the same frontend as user packages; only fixed primitive signatures have native implementations.
|
||||
|
||||
## Foundation Extension Design
|
||||
|
||||
This section records the completed foundation-extension design. The Follow-through Implementation Design above owns subsequent additions; later numbered sections retain the original Core roadmap.
|
||||
|
||||
### Sequence Contract And Reuse
|
||||
|
||||
The checker extends the existing collection-operation owner rather than adding parallel validators. One internal sequence classifier returns the element type and source kind for `List<Item>`, Bytes and `Stream<Item>`; `each`, `reduce` and `reduce_until` reuse it for handler checking and lowering.
|
||||
|
||||
- `reduce(handler, sequence, initial_state)` requires a two-input handler `(Item, State) -> State` and returns `State`.
|
||||
- `reduce_until(handler, sequence, initial_state)` requires `(Item, State) -> (State, stop: Bool)`, processes the current item before stopping, and returns only `State`.
|
||||
- List and Bytes use finite direct loops. Bytes yields Int values from 0 through 255 without allocating `List<Int>`.
|
||||
- Stream consumption calls its pull boundary only when the next item is needed. `reduce_until` leaves the next item unread; `reduce` consumes through natural exhaustion.
|
||||
- `each(Stream)` accepts only a zero-output handler. List/Bytes retain their existing zero-output action and one-output mapping behavior. `filter`, `find` and `sum` remain List-only.
|
||||
- Core `close(stream)` is a zero-output, idempotent Stream operation. It shares the same sequence operation registry but is checked as resource termination, not traversal.
|
||||
|
||||
Handler signature diagnostics, sequence classification and output-shape validation each have one semantic owner. Native lowering receives already classified sequence and handler facts; it does not repeat source-level type decisions.
|
||||
|
||||
### Static Handler Representation
|
||||
|
||||
`handler(inputs) (named_outputs)` is contextual syntax allowed only after a function input colon. The syntax tree represents value patterns and handler parameter declarations as separate input kinds; it does not disguise a handler as an ordinary `TypeRef`. The semantic model likewise keeps `HandlerSignature` separate from runtime `Type`, because a handler is a compile-time binding rather than a value.
|
||||
|
||||
`HandlerSignature` stores positional input types and ordered named output fields. Input names do not participate in compatibility; output name, position and type all do. The checker accepts only a matching named function or a handler parameter already in scope. Handler references cannot enter local slots, aggregates, outputs, comparisons or clause domains.
|
||||
|
||||
HIR uses explicit call and argument forms:
|
||||
|
||||
```text
|
||||
HandlerTarget = NamedFunction(FunctionId) | Parameter(HandlerParameterId)
|
||||
CallTarget = NamedFunction(FunctionId) | Handler(HandlerTarget)
|
||||
CallArgument = Value(Expression) | Handler(HandlerTarget)
|
||||
```
|
||||
|
||||
Collection/sequence HIR stores the same `HandlerTarget`; it no longer carries a collection-specific optional function ID. This is the reusable representation for direct handler calls, sequence operations and multi-level forwarding.
|
||||
|
||||
Native compilation treats a function with handler inputs as a template. A specialization key is the function ID plus its ordered concrete named-function bindings. Forwarding substitutes bindings until every handler call has a concrete target, then emits an ordinary direct call. The specialization graph rejects a repeated active key as direct or indirect recursion before any private Rust source is compiled. Generated handler plumbing contains no function pointers, closures, virtual dispatch or reflective registry; the opaque Stream producer described below is the only dynamic call boundary.
|
||||
|
||||
### Stream Representation And Lifecycle
|
||||
|
||||
The semantic type model adds `Stream(Box<Type>)`. It is the only new compiler-provided generic type; it is a valid parameter, local, field and choice payload but is not comparable and cannot be a Map key. Copying it preserves opaque resource semantics: every alias shares one cursor, exhausted flag and explicit-close flag.
|
||||
|
||||
`dever-runtime` adds one generic pull-stream owner backed by shared synchronized state. Its producer returns either one item or natural end. The only dynamic producer abstraction is inside this opaque I/O boundary, where the PRD explicitly permits it; Dever handlers remain statically specialized. Pulling and closing are serialized, with no prefetch, worker thread or async task.
|
||||
|
||||
The terminal rules are:
|
||||
|
||||
1. Normal EOF marks the Stream exhausted and releases its producer without yielding an element.
|
||||
2. A terminal file/socket read error is converted once to `ReadEvent.Failed`, then the Stream becomes exhausted.
|
||||
3. A terminal accept error is converted once to `ConnectResult.Failed`, then the Stream becomes exhausted.
|
||||
4. `close(stream)` marks all aliases closed, drops the producer and is a no-op when repeated; later traversal sees ordinary exhaustion.
|
||||
5. Closing a separately held File, Socket or Listener invalidates the shared underlying resource. The dependent Stream then yields its one typed Failed item and ends.
|
||||
6. Closing only the Stream drops its source alias but does not close a separately held source handle. Native destruction remains the final cleanup fallback.
|
||||
|
||||
`reduce_until` never pre-pulls, so its stop item is consumed and the following item remains available to every Stream alias. Concurrent consumption is outside the language contract; the synchronized state protects resource integrity but does not introduce concurrency semantics.
|
||||
|
||||
### Official Package And Runtime Boundary
|
||||
|
||||
The public stream API remains ordinary bundled `.dever` source:
|
||||
|
||||
```dever
|
||||
type ReadEvent {
|
||||
Chunk(bytes: Bytes)
|
||||
Failed(message: Text)
|
||||
}
|
||||
|
||||
type ReadStreamResult {
|
||||
Streaming(stream: Stream<ReadEvent>)
|
||||
Failed(message: Text)
|
||||
}
|
||||
```
|
||||
|
||||
`dever.io.chunks(file, limit)` and `dever.net.chunks(socket, limit)` return `dever.io.ReadStreamResult`; `dever.net.connections(listener)` returns `Stream<dever.net.ConnectResult>`. Existing one-shot `read` remains unchanged. Invalid limits and already-closed sources fail during stream creation; later source failures become one terminal stream item.
|
||||
|
||||
The ownership flow remains:
|
||||
|
||||
```text
|
||||
bundled .dever function and result choices
|
||||
-> fixed dever.system intrinsic signature
|
||||
-> generated typed adapter
|
||||
-> dever-runtime Stream/resource primitive
|
||||
```
|
||||
|
||||
The generated adapter maps runtime pull outcomes (item, natural end or error) into the source-defined concrete choices. Runtime code therefore owns pulling, locking and OS resources, while `.dever` owns public names and recoverable result shapes. No HTTP parser, route table, JSON codec or user model enters the runtime.
|
||||
|
||||
### Implementation And Rollback Boundaries
|
||||
|
||||
Implementation proceeds through coherent compiler boundaries: syntax/semantic handler declarations; shared handler and sequence HIR; List/Bytes reduce lowering; runtime Stream; file/TCP adapters; then native specialization and end-to-end fixtures. Each boundary must compile and pass its focused tests before the next. Unsupported handler or Stream positions remain compile diagnostics; there is no compatibility fallback to runtime values or eager Stream collection.
|
||||
|
||||
The existing one-shot file/TCP APIs, List operations and generated-binary boundary remain compatible. No stored data or public artifact format needs migration. Reverting the extension removes its syntax, standard source declarations, HIR forms and runtime module together while leaving the completed core foundations intact.
|
||||
|
||||
## Historical Hello Milestone (2026-09-06)
|
||||
|
||||
The completed deliverable is a native `user.dever` whose `main() ()` prints `hello`. A future user API may start with in-memory fixtures; database selection is no longer a prerequisite. Existing parser and surface syntax are preserved.
|
||||
|
||||
The implemented Text/action subset covers package and function resolution, Text parameters and local assignment, zero-output calls, checked HIR, native Rust emission and local check/build/run. It checks all source declarations and rejects unsupported constructs, duplicate symbols, invalid exposures, private cross-package calls, source/package mismatches and cycles. This is not full Core checking.
|
||||
|
||||
The standard `dever.io.println(Text)` signature resolves to a typed intrinsic. Its implementation belongs to a small dependency-free `dever-runtime`; the native backend embeds that same runtime source in disposable generated Rust. Text uses owned Rust Strings to preserve Dever value semantics. User function and local identifiers lower to numeric IDs, not raw Rust identifiers. Output failures propagate internally to a nonzero process exit with the Dever call location; no new source exception syntax is introduced.
|
||||
|
||||
The CLI owns argument parsing and process execution; the core owns checked programs and native compilation. Invoke rustc directly without a shell, using RUSTC or PATH. Compile into an exclusively created temporary directory, retain it through execution and remove owned artifacts afterwards. Explicit build output must not overwrite an existing file. No external dependency, package distribution, interpreter or service is needed.
|
||||
|
||||
The following sections describe the wider roadmap. Implemented foundations are recorded in the Active Core Checklist and Core Foundation Evidence in `implement.md`; formatter, reference evaluator, performance gates and application packages are not part of this delivery.
|
||||
|
||||
## Deferred Application Architecture
|
||||
|
||||
This is a later HTTP/JSON/CRUD direction, not part of the approved foundation extension. It must be reconsidered against the implemented Stream and static-handler contracts before application work begins.
|
||||
|
||||
The native path remains `.dever -> parser -> resolver/checker -> typed HIR -> private Rust -> native executable`. HTTP requests must execute the compiled business functions, not an interpreter or a handwritten Rust user service.
|
||||
|
||||
| Owner | Required responsibility |
|
||||
| --- | --- |
|
||||
| `.dever` application packages | User/input types, validation, CRUD orchestration, parameterized queries, routes and business error mapping |
|
||||
| `dever-core` | Symbol/type/clause/initialization checks, standard signatures, I/O effects, typed handler checks and native code generation |
|
||||
| `dever-runtime` | Mature HTTP and JSON implementations, the selected database driver, connection/resource lifecycle and per-request fault boundary |
|
||||
| CLI | Configuration inputs, `check`, native `build/run` and diagnostics |
|
||||
|
||||
Necessary semantic adaptations, with no new surface keywords:
|
||||
|
||||
- Allow named function references in fixed HTTP registration positions, extending the existing collection-handler mechanism. They remain statically resolved, not general first-class functions.
|
||||
- Add opaque standard resource types for database pools and server resources. Ordinary records/collections keep value semantics; resource handles explicitly identify external state and cannot be serialized or mutated as records.
|
||||
- Give standard I/O operations fixed effect metadata and propagate effects through the call graph. Preserve statement/expression evaluation order; internal async lowering does not introduce `async` or `await` into `.dever`.
|
||||
- Reuse choice results for recoverable HTTP/JSON/database failures. Program faults are isolated to the failing request and retain Dever source locations.
|
||||
- Bundle only the required standard HTTP/JSON/database contracts with the toolchain. External package distribution remains deferred.
|
||||
|
||||
The current `TypeRef` AST can represent parameterized standard types, but `parser.rs::type_ref_inner` presently recognizes only List/Map/MapEntry generic spellings. Any required qualified standard generic type must be supported through the standard-type contract, without a User-specific parser branch. User-defined generics remain deferred.
|
||||
|
||||
Persistence selection is pending. The initial design candidate uses parameterized SQL and static type-driven row decoding, with schema/query definitions owned by one application persistence package. Do not build an ORM or multi-database framework speculatively. JSON and row decoding should share resolved type facts, rather than duplicate user field definitions in Rust.
|
||||
|
||||
Verification must show that changing `.dever` handlers, types or routes changes the compiled API. A second small schema/route fixture should prove that compiler/runtime code contains no user-API special case. Report actual CRUD throughput, latency percentiles, errors and memory against equivalent native code under identical database/durability settings; finalize the performance budget after storage and deployment scope are selected.
|
||||
|
||||
## 1. Architecture Decision
|
||||
|
||||
Core 0.1 is a textual language toolchain, not a semantic-graph workbench. It has one checked frontend and two deliberately different consumers of the same typed HIR:
|
||||
|
||||
```text
|
||||
.dever source root
|
||||
|
|
||||
v
|
||||
source loader -> lexer -> parser -> syntax tree
|
||||
| |
|
||||
| +-> formatter
|
||||
v
|
||||
package/name resolver
|
||||
v
|
||||
type + clause + flow checks
|
||||
v
|
||||
typed HIR
|
||||
/ \
|
||||
v v
|
||||
reference evaluator native specialization
|
||||
v
|
||||
private Rust emission
|
||||
v
|
||||
rustc / LLVM -> binary
|
||||
|
||||
dever CLI -> load / check / format / build / run
|
||||
```
|
||||
|
||||
Dever text in `.dever` files or program blocks of `.dever.md` files is the program source. The syntax tree and typed HIR are in-memory compiler representations; they are not editable JSON formats or public compatibility contracts. The evaluator defines a simple executable reference for conformance tests. Production `build` and `run` use ahead-of-time native compilation and never route through the evaluator.
|
||||
|
||||
The bootstrap compiler is implemented in Rust because rustc provides a mature LLVM path. The repository starts without an existing workspace or implementation. This is an implementation choice, not a surface-language dependency: diagnostics, type identities and runtime semantics are owned by Dever, and generated Rust is a disposable private build artifact.
|
||||
|
||||
## 2. Scope Boundaries
|
||||
|
||||
The implementation contains three production crates:
|
||||
|
||||
```text
|
||||
crates/
|
||||
dever-core/
|
||||
src/
|
||||
source.rs
|
||||
diagnostic.rs
|
||||
token.rs
|
||||
lexer.rs
|
||||
syntax.rs
|
||||
parser.rs
|
||||
format.rs
|
||||
package.rs
|
||||
resolve.rs
|
||||
types.rs
|
||||
clauses.rs
|
||||
check.rs
|
||||
hir.rs
|
||||
value.rs
|
||||
stdlib.rs
|
||||
eval.rs
|
||||
native.rs
|
||||
lib.rs
|
||||
dever-runtime/
|
||||
src/
|
||||
number.rs
|
||||
collections.rs
|
||||
fault.rs
|
||||
lib.rs
|
||||
dever-cli/
|
||||
src/
|
||||
main.rs
|
||||
```
|
||||
|
||||
Compiler phases remain in one `dever-core` library rather than separate syntax, semantic and IR crates. They share source spans and language contracts and will evolve together during 0.1. `dever-runtime` is the only justified split because generated native programs consume it without depending on parser, checker, evaluator or CLI code. It contains only language-owned numeric, ordered-collection and runtime-fault primitives; it does not contain a dynamic interpreter or plugin layer.
|
||||
|
||||
`dever-cli` owns argument parsing, filesystem invocation, exit codes and rendering. It calls `dever-core` APIs and contains no parser, type or evaluation rules.
|
||||
|
||||
Permanent integration tests stay under repository-root `test/`, matching project policy. Plain-source examples live under `examples/dever/`; Markdown examples live under `examples/markdown/`. Both may contain small fixture data when needed.
|
||||
|
||||
## 3. Reuse And Replacement
|
||||
|
||||
### Reuse
|
||||
|
||||
- Pinned dependency discipline in the new Rust workspace.
|
||||
- Small modules and explicit data structures.
|
||||
- The idea that every diagnostic maps back to a source location.
|
||||
- Root-level integration tests and deterministic fixtures.
|
||||
|
||||
### Replace
|
||||
|
||||
- `SemanticGraph`, canonical JSON loading and semantic hashing.
|
||||
- Refiner candidates, approval, scrap and quarantine workflows.
|
||||
- Dever IR designed around the old graph.
|
||||
- Old target-facing Rust and React source generators and their public backend contracts.
|
||||
- Workbench presentation and temperature-alarm example.
|
||||
- Old child-task plan and old repository rules that call the semantic graph trusted source.
|
||||
|
||||
No adapter translates old JSON into new `.dever`. Such a bridge would preserve the rejected architecture, expand the change surface and create two sources of truth.
|
||||
|
||||
The replacement list describes rejected concepts, not files present at kickoff. No old implementation exists in the working tree or HEAD. Initialize `dever-core` and the root test crate first; add the runtime and CLI when their real consumers exist, without empty crates or partially working public commands.
|
||||
|
||||
## 4. Source Model
|
||||
|
||||
### 4.1 Source Files And Spans
|
||||
|
||||
`SourceFile` owns:
|
||||
|
||||
- canonical source-root-relative path;
|
||||
- UTF-8 text;
|
||||
- precomputed line-start offsets.
|
||||
|
||||
`Span` contains a file identifier and half-open byte range. Line and column are calculated only when rendering a diagnostic, keeping compiler nodes small. Every token, syntax node, resolved reference and HIR instruction retains a span.
|
||||
|
||||
The loader:
|
||||
|
||||
1. walks the supplied source root for `.dever` files;
|
||||
2. sorts paths lexically before parsing;
|
||||
3. rejects invalid UTF-8 and duplicate canonical paths;
|
||||
4. derives the expected package name from the path;
|
||||
5. returns all diagnostics in deterministic file/span order.
|
||||
|
||||
### 4.2 Tokens And Trivia
|
||||
|
||||
The lexer emits semantic tokens plus newline and `#` comment trivia. Newlines matter for separating linear statements; whitespace otherwise does not. Comments attach to the following syntax item, or to the preceding item when trailing on the same line, so the formatter can preserve them. `//` is always one integer-division token and is never considered comment syntax.
|
||||
|
||||
Numeric text remains unconverted in tokens. Parsing a very large literal directly into i64 or f64 would lose the ability to issue precise range and rounding diagnostics; conversion happens during checking with the expected type. An inexact Decimal literal is rejected rather than silently rounded, while checked Decimal arithmetic may produce the specified rounded result.
|
||||
|
||||
### 4.3 Syntax Tree
|
||||
|
||||
The parser produces a lossless-enough typed AST:
|
||||
|
||||
- `PackageDecl` and exposed names;
|
||||
- record/choice `TypeDecl`;
|
||||
- `FunctionClause`;
|
||||
- input patterns and output declarations;
|
||||
- assignment/call statements;
|
||||
- value construction, call, field, literal, unary and binary expressions.
|
||||
|
||||
The parser does not resolve names or infer types. It supports bounded recovery at a newline, closing delimiter or next top-level declaration and returns a partial tree plus diagnostics. Later phases run only for packages without syntax errors.
|
||||
|
||||
## 5. Formatter
|
||||
|
||||
The formatter consumes the syntax tree and attached comments, never performs string replacements over raw source, and owns one layout:
|
||||
|
||||
- two-space indentation;
|
||||
- multiline package exposure and type members, one item per line;
|
||||
- commas only where grammar requires positional separation;
|
||||
- no semicolons;
|
||||
- stable spaces around operators;
|
||||
- record fields in declaration order after successful resolution;
|
||||
- parentheses inserted only when required by precedence;
|
||||
- one blank line between top-level definitions and no trailing whitespace.
|
||||
|
||||
`format(format(source)) == format(source)` is an acceptance invariant. Invalid files are not rewritten in Core 0.1; the CLI reports diagnostics and leaves them untouched.
|
||||
|
||||
## 6. Resolution And Symbols
|
||||
|
||||
Resolution runs in three passes:
|
||||
|
||||
1. Register every package, type, function name and function arity.
|
||||
2. Register record fields, choice variants and full function signatures.
|
||||
3. Resolve bodies, patterns, exposed names and cross-package references.
|
||||
|
||||
Symbols use compiler-assigned integer IDs internally. User-visible identity remains the package-qualified source name, not an opaque semantic graph ID.
|
||||
|
||||
The resolver enforces:
|
||||
|
||||
- one file per package and exact path/package match;
|
||||
- local source plus the fixed compiler-owned standard catalog as the only Core 0.1 package origins;
|
||||
- reserved core single-segment names and the `dever.*` namespace, which local source cannot declare;
|
||||
- unique names inside a package;
|
||||
- one function signature per name/arity;
|
||||
- contiguous clauses for the same signature;
|
||||
- public access only through `exposes`;
|
||||
- full qualification across packages;
|
||||
- acyclic package, type and function-call graphs.
|
||||
|
||||
Resolution never performs network access or searches outside the supplied source root in Core 0.1. An unavailable official or third-party package is an ordinary unknown-package diagnostic. Future lockfile-pinned components will be registered as an additional origin before these same resolution passes; this does not require imports, aliases or version text in `.dever` calls.
|
||||
|
||||
### 6.1 Distribution Compatibility Contract
|
||||
|
||||
External distribution is deferred to 0.2, but Core 0.1 must not close off its confirmed identity model:
|
||||
|
||||
- a stable component ID such as `shemic.contact` owns the root of package and type identity;
|
||||
- registry, Git and local paths are replaceable source transports and never appear in `.dever` references;
|
||||
- Git additions require an explicit tag or revision, then lock the full commit and normalized SHA-256 content hash;
|
||||
- CLI-maintained `dever.mod` records direct dependency intent while `dever.lock` records the complete exact graph;
|
||||
- verified sources live in a global read-only content-addressed store shared across projects;
|
||||
- only explicit `add`, `update` and `fetch` operations may access the network;
|
||||
- every package supplied by a component must remain under that component ID, and duplicate providers are errors.
|
||||
|
||||
No 0.2 parser, Git client, resolver, store or command is implemented speculatively in Core 0.1. The current resolver needs only reserved namespaces and origin-neutral internal symbol IDs so adding a locked package origin later does not change source names.
|
||||
|
||||
The ordinary call graph is computed after all bodies resolve. Sequence handlers and handler-input forwarding are explicit HIR edges; native specialization checks the fully substituted instance graph, so indirect recursion cannot hide behind `each`, `reduce`, `reduce_until` or a handler parameter.
|
||||
|
||||
## 7. Type System
|
||||
|
||||
`TypeId` points to interned compiler types:
|
||||
|
||||
- the six scalar types;
|
||||
- user record and choice types;
|
||||
- `Nullable(TypeId)`;
|
||||
- `List(TypeId)`;
|
||||
- `Map(KeyTypeId, ValueTypeId)`;
|
||||
- compiler-owned `MapEntry(KeyTypeId, ValueTypeId)`;
|
||||
- compiler-owned `Stream(ItemTypeId)` opaque resources;
|
||||
- ephemeral named multi-output result types.
|
||||
|
||||
There are no user-defined generic parameters in 0.1. List, Map, MapEntry, Stream and sequence functions are compiler-provided generic contracts. Static `HandlerSignature` is a separate function-parameter contract and is not a runtime `Type`.
|
||||
|
||||
The type interner owns idempotent nullable construction for standard generic returns; explicit doubled `?` syntax remains invalid. Structural equality follows the PRD, including ordered Map pairs and IEEE Float comparisons inside aggregates. Checking, reference evaluation and native lowering must share these contracts.
|
||||
|
||||
Checking is expression-directed:
|
||||
|
||||
- function inputs and outputs provide declared boundary types;
|
||||
- assignment provides an expected type once the local is initialized;
|
||||
- an uninitialized local takes the inferred type of its first complete assignment;
|
||||
- empty List/Map and context-sensitive numeric literals require an expected type;
|
||||
- the only implicit numeric conversion is Int to Decimal;
|
||||
- function output, static handler and sequence-operation contracts are checked before lowering.
|
||||
|
||||
Linear bodies make definite assignment a forward pass. The checker tracks each local as uninitialized or initialized with one stable type. Record field writes require an initialized record and preserve its type.
|
||||
|
||||
## 8. Clause Analysis
|
||||
|
||||
Clause-based conditional dispatch is a permanent source-language constraint, not a Core 0.1 deferral. Native decision trees are its internal implementation and do not introduce another source-level branching form.
|
||||
|
||||
Each same-name/same-arity group becomes one `FunctionDef` with multiple clauses. Analysis separates base input types from clause patterns.
|
||||
|
||||
Patterns normalize into symbolic sets:
|
||||
|
||||
- Bool and no-payload choice types become finite atoms.
|
||||
- Nullable adds a distinct null atom.
|
||||
- Payload choices keep the variant atom and bind payload fields after selection.
|
||||
- Text/numeric constants become singleton sets.
|
||||
- Int and Decimal comparisons become normalized intervals with open or closed endpoints.
|
||||
- `other` is computed as the complement of all explicit patterns in that argument position and group.
|
||||
|
||||
A multi-input clause is a product of its per-input sets. The analyzer incrementally subtracts each product from the function input universe:
|
||||
|
||||
- intersection with prior coverage means overlap;
|
||||
- an empty clause domain means unreachable;
|
||||
- remaining universe after all clauses means non-exhaustive.
|
||||
|
||||
The algorithm works on finite atoms and interval boundaries, not enumerated i64 or Decimal values. Float range patterns are rejected before this phase. The source order is never part of selection.
|
||||
|
||||
At runtime, HIR stores a compiler-chosen decision tree built from the normalized domains. It can optimize tests while preserving order-independent semantics; no runtime “first matching clause” rule exists.
|
||||
|
||||
## 9. HIR And Reference Evaluation
|
||||
|
||||
The typed HIR contains only resolved IDs and typed operations:
|
||||
|
||||
- constants and value construction;
|
||||
- local/field load and store;
|
||||
- checked numeric/text/boolean operations;
|
||||
- direct function and statically bound handler calls;
|
||||
- standard collection/sequence calls with explicit handler targets;
|
||||
- clause decision nodes;
|
||||
- named outputs.
|
||||
|
||||
The evaluator uses an explicit call frame with owned locals and a source span for every operation. There is no global mutable program state.
|
||||
|
||||
Runtime values are:
|
||||
|
||||
```text
|
||||
Bool
|
||||
Int(i64)
|
||||
Decimal(DecimalValue)
|
||||
Float(f64)
|
||||
Text
|
||||
Id
|
||||
Record
|
||||
Choice
|
||||
Nullable
|
||||
List
|
||||
Map
|
||||
Stream
|
||||
MultiOutput
|
||||
```
|
||||
|
||||
Aggregate values use shared immutable storage with copy-on-write mutation. This implements source-level value semantics without eagerly cloning every nested List, Map or record. The optimization is internal and must pass alias-observation tests.
|
||||
|
||||
Map storage uses an insertion-ordered map. In Rust, `indexmap::IndexMap` is the planned implementation; replacement keeps the same wrapper contract. Removal must use order-preserving removal, and overwrite must retain the existing position.
|
||||
|
||||
Evaluation returns either named outputs or a `RuntimeFault`. A fault carries category, message and originating `Span` and unwinds only to the current CLI execution boundary. There is no language-level catch path.
|
||||
|
||||
The evaluator is intentionally not optimized as the production runtime. Its job is to make language semantics easy to inspect, to evaluate focused tests and to serve as a differential oracle for native output.
|
||||
|
||||
## 10. Native AOT Compilation
|
||||
|
||||
The native path consumes only fully checked typed HIR. It performs whole-program specialization from the selected zero-input entry function and emits one transient Rust crate:
|
||||
|
||||
```text
|
||||
reachable typed HIR
|
||||
|
|
||||
v
|
||||
specialize concrete List/Map/Stream and handler-binding combinations
|
||||
|
|
||||
v
|
||||
emit static Rust records, enums, functions and loops
|
||||
|
|
||||
v
|
||||
cargo build --release -> native executable
|
||||
```
|
||||
|
||||
There is no generic `Value` in generated function signatures. Dever records lower to concrete Rust structs, choices to concrete enums, nullable values to an internal option representation, and calls to direct functions. Clause domains lower to compiler-selected decision trees. Because sequence handlers are concrete after specialization, `each`, `reduce`, `reduce_until`, `filter`, `find` and `sum` lower to direct calls and loops. List/Bytes loops have no virtual dispatch; only opaque Stream pulling may use the internal producer abstraction at the I/O boundary.
|
||||
|
||||
Source-level value semantics do not require eager deep copies. A last-use/liveness pass may move a value when the source is dead; when both aliases remain live, generated aggregates use a language-owned clone or copy-on-write representation. This is invisible to `.dever` and is verified against the evaluator. Locals and non-escaping records remain eligible for normal Rust/LLVM stack and register optimization. The AOT runtime has no garbage collector and no reflection registry.
|
||||
|
||||
Checked Int and Decimal behavior is emitted explicitly, so the release profile cannot remove language-required overflow or invalid-operation faults. Runtime helpers carry compact source-location IDs; the executable maps a fault back to the original `.dever` path and span. Internal Rust compiler errors are toolchain failures, not Dever diagnostics, and generated Rust names must never appear as user symbols.
|
||||
|
||||
The transient crate depends only on `dever-runtime`. Its generated source and Cargo metadata live in a compiler-managed build directory, are not emitted by a public command and may be deleted at any time. The optimized profile starts with `opt-level = 3`, thin LTO and one codegen unit; benchmark evidence may change those internal settings without changing the language.
|
||||
|
||||
The first backend deliberately uses stable Rust as a bootstrap bridge to LLVM. A later direct LLVM or Cranelift backend can consume the same checked HIR and runtime contracts without changing `.dever` source. No `dever-backend-rust` public crate or target-specific surface syntax is introduced.
|
||||
|
||||
Self-hosting is a staged replacement, not a Core 0.1 syntax promise:
|
||||
|
||||
1. The Rust bootstrap compiler establishes parser, checker, HIR, native semantics and conformance fixtures.
|
||||
2. Later language phases add the explicit file/process/memory capabilities required to write compilers.
|
||||
3. The frontend and standard library are reimplemented in `.dever` against the same fixtures and HIR contracts.
|
||||
4. A stage-1 compiler builds stage 2; stage 2 builds stage 3; stage-2/stage-3 behavior and reproducible artifacts are compared before the Rust frontend becomes only a seed.
|
||||
|
||||
## 11. Numeric Implementation
|
||||
|
||||
`dever-runtime::number` is the only module allowed to depend on the decimal implementation. It exposes a language-owned `DecimalValue` and operations returning:
|
||||
|
||||
```text
|
||||
Result<DecimalValue, NumericFault>
|
||||
```
|
||||
|
||||
Core 0.1 uses the Rust `dec` crate's `Decimal128` plus a reusable Context configured for 34 digits and round-half-even. Its status flags are cleared and checked around every operation: inexact/rounded is an accepted rounded result, while overflow, underflow, division by zero and invalid operation become Dever runtime faults. Decimal NaN/Infinity never enter a normal Dever `Value`. Compile-time constant evaluation and the reference evaluator call this same runtime wrapper, so native and reference behavior cannot acquire separate Decimal implementations.
|
||||
|
||||
This boundary is necessary because `dec` uses libdecnumber internally and exposes more IEEE decimal states than the language permits. Conformance tests, not the dependency's default operators, define Dever behavior.
|
||||
|
||||
Int operations use Rust checked arithmetic. Division and remainder explicitly handle zero and `i64::MIN / -1`. Int-to-Decimal conversion is exact.
|
||||
|
||||
Float uses Rust f64 operations without fast-math transformations. List summation is left-to-right. NaN/Infinity classification is exposed through `math` functions.
|
||||
|
||||
## 12. Standard Library Boundary
|
||||
|
||||
Core names such as `each`, `reduce`, `reduce_until`, `close` and `get` are registered from a static table containing:
|
||||
|
||||
- accepted arities;
|
||||
- generic input/output constraints;
|
||||
- whether an argument is a sequence, value or statically bound handler;
|
||||
- evaluator function.
|
||||
|
||||
Qualified standard packages (`text`, `decimal`, `float`, `math`) use the same table with qualified names. This is a fixed compiler-owned catalog, not a plugin registry.
|
||||
|
||||
Every implemented standard operation has one checking contract and one native lowering rule. Sequence source classification and handler validation are shared so List, Bytes and Stream forms cannot drift. The deferred evaluator must later consume these same checked contracts rather than define a second interpretation.
|
||||
|
||||
## 13. CLI Contract
|
||||
|
||||
`dever-cli` builds one `dever` binary:
|
||||
|
||||
```text
|
||||
dever check <source-root>
|
||||
dever fmt <source-root>
|
||||
dever build <source-root> <package.function> --output <path>
|
||||
dever run <source-root> <package.function>
|
||||
```
|
||||
|
||||
- `check` loads every package and runs all static phases.
|
||||
- `fmt` prepares every file before writing; if any source file is invalid, no file is modified. Record-field reordering requires successful resolution.
|
||||
- `build` checks the complete source root, specializes one exposed zero-input function as the entry point and writes an optimized native executable to the requested path.
|
||||
- `run` uses the same native compilation path in a compiler-managed directory and then invokes the executable; it does not run the reference evaluator.
|
||||
- Outputs print in declaration order using deterministic Dever value formatting.
|
||||
- Diagnostics go to stderr; program output goes to stdout.
|
||||
- Exit 0 means success, exit 1 means source/runtime diagnostics, exit 2 means invalid CLI usage.
|
||||
|
||||
The CLI is deliberately not a project/package manager. Source-root selection avoids introducing a manifest before dependency versions or executable targets are designed.
|
||||
|
||||
Core 0.1 therefore has no `add`, `update`, registry, signature or component-cache commands. Those are a 0.2 distribution concern; `check`, `build` and `run` remain offline and deterministic.
|
||||
|
||||
### 13.1 Command Identity And Coexistence
|
||||
|
||||
The Cargo binary and canonical product command remain `dever`. Command examples, help semantics and the public CLI contract use that name.
|
||||
|
||||
During Core 0.1 coexistence with the existing Dever framework CLI, a machine may expose this compiler on `PATH` as `deverc`. That entry is a symlink or launcher for the same compiler binary, not a second CLI implementation. It must not replace, shadow or modify the existing `dever` executable.
|
||||
|
||||
Repository builds and automated tests invoke the built binary directly and never mutate global executables or shell configuration. Installing, updating or removing the temporary `deverc` entry is an explicitly authorized machine-level operation. Moving the compiler onto the global `dever` name requires a separate migration plan.
|
||||
|
||||
## 14. Diagnostics
|
||||
|
||||
All compile diagnostics use one structure:
|
||||
|
||||
```text
|
||||
severity
|
||||
code
|
||||
message
|
||||
primary span
|
||||
zero or more labeled related spans
|
||||
optional help
|
||||
```
|
||||
|
||||
Examples include both conflicting clause spans, declaration and bad-reference spans, or first initialization and later type-changing assignment. Rendering uses `path:line:column` and a source excerpt. Messages describe the violated Dever rule and never expose Rust type names, crate names or implementation stack traces.
|
||||
|
||||
Runtime faults use the same renderer with a runtime category. The CLI may include a Dever call trace, but the first diagnostic always points to the failing `.dever` operation.
|
||||
|
||||
## 15. Migration And Repository Cleanup
|
||||
|
||||
Implementation starts from the documentation-only repository verified on 2026-09-05:
|
||||
|
||||
1. Initialize `dever-core` and `dever-tests`; add `dever-runtime` and `dever-cli` at their implementation stages.
|
||||
2. Implement `dever-core` around textual language phases.
|
||||
3. Do not recreate old Refiner, IR, Workbench, generated backend or semantic JSON architecture.
|
||||
4. Preserve the existing deletion of superseded planning documents; no old child links exist.
|
||||
5. Update repository `AGENTS.md` and Trellis package specs so future work treats `.dever` as the trusted source.
|
||||
6. Add the Core 0.1 examples and tests.
|
||||
|
||||
No database, persisted user data or old implementation exists, so there is no migration. Git history retains the old planning documents.
|
||||
|
||||
## 16. Verification Strategy
|
||||
|
||||
Tests are organized by behavior rather than compiler module:
|
||||
|
||||
```text
|
||||
test/dever-tests/tests/
|
||||
syntax_and_format.rs
|
||||
package_resolution.rs
|
||||
type_checking.rs
|
||||
clause_analysis.rs
|
||||
value_semantics.rs
|
||||
collections.rs
|
||||
numbers.rs
|
||||
failures.rs
|
||||
native.rs
|
||||
differential.rs
|
||||
performance.rs
|
||||
cli.rs
|
||||
```
|
||||
|
||||
Fixtures include valid programs plus one focused invalid case per diagnostic. Tests assert diagnostic code and relevant spans, not full prose, except dedicated rendering tests.
|
||||
|
||||
The highest-risk property tests are:
|
||||
|
||||
- parse/format/parse semantic equivalence and formatter idempotence;
|
||||
- clause order permutation does not change coverage or result;
|
||||
- Int division/remainder identity across boundary samples;
|
||||
- Decimal conformance vectors for precision, rounding and fault flags;
|
||||
- copy-on-write values do not expose alias mutation;
|
||||
- Map overwrite/remove/reinsert order;
|
||||
- Float sum remains left-to-right.
|
||||
- reference evaluator and native executable produce identical outputs/fault categories for the conformance corpus;
|
||||
- generated executables do not link the evaluator or perform per-element dynamic dispatch;
|
||||
- representative native hot paths stay within the PRD performance budget against equivalent safe Rust baselines.
|
||||
|
||||
The foundation extension adds focused cases to the existing `syntax_and_format`, `core_semantics`, `core_native`, `runtime_foundations` and `hello_native` targets. They cover handler syntax and forbidden positions, signature matching and forwarding, specialization-cycle rejection, List/Bytes reduce behavior, Stream alias/EOF/stop/close/error behavior, official package compilation, and actual CLI check/run/build of a chunked state parser. File fixtures use test-owned temporary directories; TCP fixtures use only loopback port 0, bounded data and explicit timeouts.
|
||||
|
||||
No existing service, browser, npm build, full workspace test or external integration environment is involved in this extension.
|
||||
|
||||
## 17. Key Trade-offs
|
||||
|
||||
- One compiler crate is less independently reusable than many compiler crates, but avoids unstable public boundaries during the first grammar; the native runtime is separate only because generated programs are a real independent consumer.
|
||||
- No recursion/effects limits programs to finite pure computation, but makes the first language deterministic and prevents hidden control flow.
|
||||
- Full clause checking is more compiler work than ordered pattern matching, but it directly enforces the user's requirement that AI-written code cannot hide behavior in ordering or nested branches.
|
||||
- A decimal dependency is safer than hand-written decimal128 arithmetic; the wrapper and conformance suite prevent it from defining public language behavior.
|
||||
- A small fixed standard catalog is less extensible than plugins, but keeps the first implementation inspectable and removes speculative architecture.
|
||||
- Rust emission gets optimized native code much earlier than implementing an LLVM backend, while typed HIR, differential tests and a private artifact boundary prevent Rust from becoming the language definition.
|
||||
- Keeping a reference evaluator adds implementation work, but it localizes semantic debugging and gives native code generation a deterministic oracle; it is excluded from production binaries.
|
||||
- Separating component identity from Git/registry location adds two CLI-managed metadata files in 0.2, but prevents repository moves from becoming source-breaking type renames and enables one verified global source store.
|
||||
# Compiler Contract Extension (2026-09-08)
|
||||
|
||||
Extend existing AST fields and clause modifiers, normalize field bounds with the same interval owner as patterns, then analyze checked HIR before publishing Program. Keep private checks in field access/construction owners. Function/package metadata feeds effect/dependency checks and deterministic API snapshots. Failure obligations follow values across aggregates and calls, with explicit source recovery declarations as the only normal-value discharge boundary. Static handlers share existing specialization bindings. Facts must be conservative on mutation and unknown operations; no runtime interpreter, speculative fallback, new dependencies or source keyword for every domain.
|
||||
|
||||
Independent syntax/formatter work owns syntax.rs/parser.rs/format.rs; effect/API work owns contracts/effects.rs/api.rs and CLI; main owns semantic types, HIR integration, fact/failure analysis, standard-source migration, tests and docs. All workers preserve shared changes. Core check is the single enforcement entry used by CLI and native execution.
|
||||
|
||||
# AI-Oriented Source Architecture Design (2026-09-19)
|
||||
|
||||
Source classification is one compiler-owned value derived from the relative source path. It records main or component/domain/role/topic identity and is reused by parsing, Model registration, symbol resolution, API route construction and architecture diagnostics. Those layers must not rediscover roles with independent string searches.
|
||||
|
||||
Every physical source still has a unique internal owner name so diagnostics, HIR ownership and native symbol generation remain deterministic. App declarations additionally receive one stable logical alias, `<component>.<domain>.<name>`, regardless of whether they live in `app.dever` or `app/<topic>.dever`. Alias collisions are duplicate declarations. Topic paths remain an implementation detail and never leak into API snapshots or call sites.
|
||||
|
||||
Name lookup tries the current physical owner first, then role-relative names in the current domain, same-component App aliases, and finally full App aliases. A resolved reference is accepted only when the role dependency matrix permits it. Main and API may call App; App may call private roles in its own domain and App aliases elsewhere; private roles may collaborate only inside their own domain. API functions are registered for HTTP routing but rejected as source call targets. Model type identity stays path-derived, while generated operations are restricted to their owning domain.
|
||||
|
||||
Application `public` modifiers are rejected. App functions and App-declared types form the external contract automatically; Model record/choice/ID types remain type-visible where relations or App contracts require them. After failure inference, every App function is also checked so a private Domain/Adapter error type cannot leak through its effective error set. Bundled standard sources keep compiler-internal visibility metadata because they are not application architecture. The existing API baseline and unused-export checks consume logical App names.
|
||||
|
||||
Architecture validation runs before semantic bodies: legal layouts, reserved names, file/directory exclusivity, flat non-API topic directories and the no-single-file-role-directory rule. Declaration-role validation then keeps API thin, Model storage-only and App as the sole cross-domain capability boundary. Port syntax itself is not expanded in this change; `port` is a reserved architectural role until a separately approved replaceable-boundary declaration contract exists.
|
||||
@@ -0,0 +1,819 @@
|
||||
# Dever Minimal Core 0.1 Implementation Plan
|
||||
|
||||
## HTTP/2 Ceiling And Soak (2026-09-18, Complete)
|
||||
|
||||
子任务 `09-13-http2-ceiling-soak` 复用既有负载器,将客户端 worker/CPU 集合参数贯通 HTTP/1、HTTP/2 和长连接入口。34 项运行器定向测试及最小 loopback 回归通过;生产运行时未改。1 CPU、128 MiB 下 h2c/TLS+h2 的 16x16、30k/45k/60k/90k 双次扫描表明本机吞吐约 36k-40k req/s 时服务端接近 1 核,客户端仍占 1.4-2 核;请求槽丢弃使它不是纯服务端上限。28k 的首轮稳态未达 99% 成功率,故改用 20k:128/64 MiB 各 60 秒的四组成功率为 99.77%/99.92%/99.94%/99.80%,无请求错误、OOM 或 FD 残留。h2c/TLS+h2 各 100 轮重连无错误或 FD 残留;短时 RSS 数据不证明小时级无泄漏。原始报告、命令和限制见 `test/performance/README.md`。
|
||||
|
||||
HTTP/2 有界验收和 typed ORM 子任务均已完成。根任务保持进行中:历史计划的编译器发行/跨平台与自举仍未交付,小时级稳定性等扩展也没有在本轮获批或验证;不得凭子任务完成数宣称整个语言路线图结束。
|
||||
|
||||
## N5 HTTP/2 (2026-09-12, Complete)
|
||||
|
||||
子任务 `09-12-http2` 完成:Hyper/h2 buffered/live 服务端、single-use/pooled 客户端、TLS ALPN、固定流控窗口与每连接流配额、逐流 handler/上传/下载/SSE、RST 隔离及 GOAWAY 排空。官方 `Limits.http2: Http2Limits?` 与检查器一起直接演进,静态原生桥接复用既有 Nullable/Record;没有新 intrinsic 或兼容层。
|
||||
|
||||
Hyper Executor 的协议任务接入 Dever 子 Scope,关闭 admission 与登记串行,故障上报/注销在 completion 之前;不可取消 supervisor 清理协议任务和已启动 blocking 后代后才释放物理许可。池连接归持久 driver;上传/下载共享流租约。只有 Hyper 结构化交回的未发送请求可在原期限重排,已发请求不重放。
|
||||
|
||||
88 个不同定向用例通过:HTTP/2 client/server 各6,HTTP engine12、HTTP library7、live16、pooled network14、pooled library6、async runtime10、structured concurrency11。独立 h2 对端覆盖流控、取消、容量、ALPN、语义与故障;原生程序覆盖单连接 TLS 嵌套代理、流式上传、SSE、run/await 和原有 HTTP/1/WSS。修复传输取消误升为整服故障、响应发布锁重入、GOAWAY 未发请求卡住旧租约和 Response TE 静默删除;测试端句柄和 WSS 独立连接预算也已修正。
|
||||
|
||||
最终 CLI release 构建、backend check/fmt-check、network_bench/reference 编译及源码检查通过;独立审查闭环。Rustfmt/Clippy 不可用,官方库 fmt-check 的原有 net.dever 差异未改。临时构建目录和暂存约378 MiB可再生缓存已清理,旧编译器与性能报告保留。不提交、不自动归档;N5 实现没有运行 HTTP/2 性能矩阵。后续仍有 HTTP/2 压测、小时级稳定性、入口调度优化、RFC 8441/协议扩展、数据库、发行和自举。
|
||||
|
||||
## P2 Async Comparison And Long Connections (2026-09-12, Complete)
|
||||
|
||||
子任务 `09-12-runtime-performance-p2` 继续复用 P1 工具,完成同语义 Rust run/wait 对照、perf 调度定位、HTTP/HTTPS 高负载和 TCP/WS/SSE 分阶段回收测量。12 个运行器检查、4 个独立对端检查、11 个原生入口及新 Rust examples 的离线构建通过;未修改生产编译器/运行时。
|
||||
|
||||
1 CPU/128 MiB 下,Dever run/await root约15.50 µs、实验worker约2.003 µs,与Rust15.59/1.984 µs接近;任务入口跨线程切换是明确优化方向,根任务配额、Send和取消语义需保留。54组HTTP高负载发出1500830请求全部成功、299170计划请求未发出;压测槽位已限制结果,不是服务上限。
|
||||
|
||||
最终27组长连接覆盖32/128/512条,每组3轮;18144连接、377061消息均成功,81次FD回基线。另各协议512连接十轮,共15360连接、471207消息,无错误/OOM且30次FD回基线;SSE RSS在约25.3 MiB趋稳。修正采样退出与阶段交接竞态、SSE无心跳误通过和客户端清理;完整证据与限制集中在 `test/performance/README.md`。
|
||||
|
||||
P2 结束时尚未启用http2/h2依赖;当时规划的TLS ALPN、独立流/连接预算、流控、取消隔离和GOAWAY已由后续N5交付。小时级soak与入口调度优化另行落地,总语言路线图保持未完成。
|
||||
|
||||
## P1 Standalone Runtime Performance (2026-09-12, Complete)
|
||||
|
||||
用户批准建立常驻内存、异步调度和 HTTP/HTTPS 三组基准,取代旧网络实施阶段的局部“不压测”限制。子任务 `09-12-runtime-performance` 完成:真实原生二进制、Rust runtime/Hyper 对照、有界固定速率负载、Linux RSS/PSS/CPU 和专属 cgroup 预算、原始 JSON 报告。生产语言/运行时未改动。
|
||||
|
||||
7 个运行器与 2 个独立 HTTP 对端检查通过;离线原生/release 构建和格式检查通过,Rustfmt/Clippy 不可用。最终 78 组主测、18 组新连接、15 组 64 MiB 空闲基线均完成且无 OOM;主测网络发出 107962 请求全部成功,38 个计划请求未发出并按原因记录。当前只是热缓存、短时、指定负载结果,不是吞吐极限、冷启动整机内存或长期稳定性结论。
|
||||
|
||||
运行命令、确切统计口径和首轮数据以 `test/performance/README.md` 为准,原始产物/报告保存在 `target/performance/`。后续候选:同语义 Rust 异步对照与调度剖析、高负载扫描、TCP/WS/SSE 长连接;其余语言/后端路线图仍未完成。
|
||||
|
||||
## N4 Concurrent Composition And Reusable Clients (2026-09-12, Complete)
|
||||
|
||||
- [x] Implement source runtime configuration, typed handler context, timeout/race and pull-driven stream adapters; extend async memory traversal.
|
||||
- [x] Add verified TLS transport and bounded reusable HTTP clients with streamed uploads/downloads; integrate HTTPS/WSS and TLS servers.
|
||||
- [x] Wire compiler contracts, official source, native conversion and examples together.
|
||||
- [x] Run focused compiler/native and independent loopback protocol/lifecycle tests; review final ownership and limits.
|
||||
- [x] Update canonical language/spec docs and record evidence without a commit or archive.
|
||||
|
||||
### N4 Evidence
|
||||
|
||||
83 distinct focused cases passed: async_composition 7, pooled_network 14, pooled_library 5, structured_concurrency 11, async_network 9, http_engine 12, http_library 6 and live_network 16. Reruns are not counted twice. The old structured-concurrency case that rejected async List handlers was migrated to the newly accepted contract and checked for a concurrency effect.
|
||||
|
||||
New coverage includes source runtime bounds/start-once, timeout cleanup of started blocking children, race loser cleanup/fault propagation, Channel null/drain/close and periodic stream timing, static handler/output checks, C012 stream failure obligations, async memory traversal/fusion and concrete HTTP Context transfer. Native programs exercise HTTPS, pooled proxy calls through shared Context, streamed uploads/downloads, SSE, WSS and graceful shutdown.
|
||||
|
||||
Independent peers verify physical connection reuse, repeated headers, early chunks beyond the response-head deadline, chunked upload, slow/abandoned/truncated bodies, upload failure/cancellation, queue/body/idle deadlines, pool close wakeups, unpolled-task cleanup, certificate CA/name rejection and WSS frames. A reproduced lifetime defect allowed a pool's unpolled driver to escape its creator; constructing the driver owner guard before task creation fixes it. Native checks also exposed missing Channel Debug/Render for shared records and async handlers entering synchronous fusion; both are corrected. Final bounded cleanup removed an infallible Result from the private lease-completion path; all 14 pool cases passed afterward.
|
||||
|
||||
Actual CLI backend example check and fmt-check passed without warnings. Offline build produced a standalone binary; running with an empty environment and PATH restricted to /usr/bin:/bin printed exactly `Hello /Dever\nrequests = 1\n` and exited successfully. Official source formatting, optional-reference core/runtime/CLI cargo check, whitespace/conflict-marker and final ownership/contract inspection passed. Rustfmt/Clippy are not installed, so their checks were unavailable; Rust layout was reviewed manually.
|
||||
|
||||
Only initial dependency preparation fetched locked packages; validation/builds were offline. All network peers used owned loopback random ports and static test certificates under test/. No full suite, prior performance baseline, existing service, persistent example launch, global install or commit. No throughput/RSS improvement is inferred from functional checks. Temporary build, certificate-generation, formatting and demo directories are removed at handoff; workspace native caches remain. N4 is complete; HTTP2, protocol extensions/close metadata, database, distribution/cross-platform and self-hosting keep the umbrella task active.
|
||||
|
||||
## N3 Streaming HTTP, SSE And WebSocket (2026-09-12, Complete)
|
||||
|
||||
- [x] Add `serve_live`, HttpReply and LiveLimits while keeping ordinary serve direct. Reuse request/response codecs and connection configuration; one-slot body channel and one-handler Group per live connection.
|
||||
- [x] Add SSE field encoding, bounded chunks, Last-Event-ID access and body-driven heartbeat timers; no event history or extra heartbeat task.
|
||||
- [x] Reuse tokio-tungstenite 0.30.0 handshake/protocol for server/client Text/Binary/Ping/Pong, AsyncStream messages and close handshakes. Shared Endpoint lifecycle, 4 KiB read buffer, bounded messages/write buffers and independent directions.
|
||||
- [x] Integrate resource types, exact nominal records/choices, async effects, static handlers, native conversion, API/Markdown names and Render. No new syntax, compatibility layer, dynamic interpreter or generic transport abstraction.
|
||||
- [x] Verify owned wire peers and real native programs; update canonical docs/example and manually record the session without a commit or archive.
|
||||
|
||||
### N3 Evidence
|
||||
|
||||
46 distinct focused cases passed: live_network 16, live_library 3, http_engine 12, http_library 6, async_network 9. Repeated checks after corrections are not counted again. All final checks passed; the earlier slow-peer test assumed normal return and was corrected to observe cleanup on either return or cancellation.
|
||||
|
||||
Wire evidence covers early chunk delivery, bounded slow-peer output, SSE exact encoding/heartbeats past the ordinary deadline, idle failure isolation, HEAD cleanup, handler faults, upgrade capacity/preread bytes, independent client masks, fragmentation/UTF-8/control frames, close, partial writes, waiting-writer cancellation and started blocking descendant drain. A reproduced regression showed duplicate response publication closed the existing body; cancellation ownership now starts only after publication is accepted, and the regression passes.
|
||||
|
||||
The native source program exercised all four routes (buffered, stream, SSE, WebSocket), including client connect/send/receive/close and static async message-stream handlers. Existing native HTTP clients also matched independent wire peers. Final optional-reference cargo check, actual CLI example check (no warnings), CLI fmt-check, source format roundtrips and explicit whitespace/owner inspection passed. Rustfmt/Clippy are not installed and were not run. No throughput/RSS claims or old baseline.
|
||||
|
||||
Only a one-time dependency fetch accessed the registry; checks/builds ran offline. No full suite, existing service, persistent example launch, global install or commit. N3 is complete; TLS/WSS, HTTP2, client pools, protocol extensions, close metadata, database/distribution and other roadmap work keep the umbrella task active.
|
||||
|
||||
## N2 HTTP Engine (2026-09-12, Complete)
|
||||
|
||||
The user approved continuing after N1. Execute inline; no further planning approval. Reuse Hyper HTTP/1 on the shared Tokio runtime. No legacy compatibility, old baseline, full suite, service checks or global installation.
|
||||
|
||||
- [x] Replace the custom HTTP parser/transport with Hyper server/client primitives and migrate all source callers.
|
||||
- [x] Preserve repeated headers as `List<Header>` with byte values; buffer bodies within explicit limits. Reuse byte storage across the engine boundary.
|
||||
- [x] Add `serve(async handler, Listener, Limits) -> ()` with bounded structured connections, server keep-alive, chunked input and cancellation cleanup. Configuration/accept/handler faults propagate; peer protocol failures terminate only that connection.
|
||||
- [x] Add one-shot `send(address, port, Request, Limits) -> ResponseResult`. Poll its driver in the request future; no detached tasks, implicit retries or client pool.
|
||||
- [x] Check static handler contracts/effects and native record conversion. Replace obsolete parser tests with independent loopback wire cases and focused compiler/native tests.
|
||||
- [x] Update canonical docs and record evidence. TLS, HTTP/2, client pooling, streaming response bodies, WebSocket and SSE remain later work.
|
||||
|
||||
Limits: header buffer at least 8192 bytes (Hyper requirement), nonnegative body bytes, positive timeout, bounded connections. Defaults: 8192 / 1048576 / 5000 ms / 32. Runtime owns HTTP framing; outgoing Content-Length/Transfer-Encoding are rejected. Request header/body/handler and stalled write deadlines prevent one idle peer retaining a connection indefinitely. Static Dever handlers specialize directly; no dynamic interpreter dispatch.
|
||||
|
||||
### N2 Evidence
|
||||
|
||||
- 44 distinct focused cases passed: http_engine 12, http_library 6, async_network 9, structured_concurrency 11, native_ownership byte cases 3, runtime_foundations bytes case 1, contract_execution selected example checks 2. Repeats after local corrections are not counted again.
|
||||
- Independent wire cases cover persistence/pipelining, HEAD and 204/205/304, fragmented/chunked/binary bodies, repeated and non-UTF8 headers, conflicting lengths, header/body limits, unsupported trailers/upgrades, truncated responses, all deadlines, connection capacity and descendant cleanup. Header timeout closes directly; body/handler timeouts produce 408/504. Native tests execute real compiled send/serve and compare client bytes to an independent peer.
|
||||
- Bytes tests retain unique Text storage transfer, shared-alias behavior, shared slices and consuming iteration. Connection setup now configures TCP_NODELAY once through one helper. No old-performance baseline, throughput or RSS claims were derived from correctness tests.
|
||||
- Core compiled offline with the optional reference feature. Actual CLI HTTP example check/fmt-check and formatting roundtrips passed; the persistent example was not started. Final owning-layer, dependency, obsolete-reference and whitespace review passed. Rustfmt and Clippy were unavailable (components not installed), not reported as passing.
|
||||
- Hyper 1.11.1, hyper-util 0.1.20, http-body-util 0.1.5 and bytes 1.12.1 are pinned. Missing transitive development dependencies were fetched once; builds/tests remained offline. No Axum, TLS or HTTP2 features were added.
|
||||
- No full suite, existing service check, load test, global install, commit or task archive. N2 is complete; the umbrella task remains active for N3 and other unshipped roadmap work.
|
||||
|
||||
## N1 Async Stream And TCP (2026-09-12, Complete)
|
||||
|
||||
- [x] Persist the approved new-language/no-compatibility policy; use existing inline execution routing.
|
||||
- [x] Add bounded, cancellable async stream consumption and Tokio TCP resources to the shared runtime.
|
||||
- [x] Integrate AsyncStream types, async handlers, effects/liveness and concrete native code generation.
|
||||
- [x] Replace synchronous TCP source contracts and migrate official HTTP transport, examples and tests.
|
||||
- [x] Verify stream backpressure, close/stop, duplex I/O, timeout and compiler/native behavior with focused tests.
|
||||
- [x] Update public contracts, inspect the final changed flows and record evidence. N2 HTTP engine and N3 WS/SSE remain deferred.
|
||||
|
||||
### N1 Evidence
|
||||
|
||||
- 62 distinct focused cases passed: async_network 9, async_stream 6, structured_concurrency 11, async_native 6, async_runtime 10, http_library 11, core_native `official_` 5, runtime_foundations `stream` 3, and the reference/native file-stream differential case 1. The HTTP benchmark stayed ignored. Repeated individual checks after local fixes are not counted again.
|
||||
- Network tests owned only loopback port-0 sockets. A one-worker runtime proved duplex progress, pending close wakeups, read timeout reuse, partial-write cancellation closure, pre-pull backpressure, failure while the producer is idle, child cleanup and listener release. The persistent server example was checked without starting it.
|
||||
- Native execution exposed missing Render implementations for new resource types; those were fixed at the runtime owner and the affected native checks passed. Migrated TCP differential cases now assert independent native expectations; the synchronous evaluator no longer carries a duplicate TCP implementation.
|
||||
- Compiler/default and optional reference builds passed offline. Source formatting round trips, explicit whitespace checks and final owning-layer inspection passed. Rustfmt/Clippy were unavailable because those components are not installed; no claim of passing them.
|
||||
- No workspace-wide tests, service checks, old-performance baseline, network load test, global install or commit. The task remains active for N2 HTTP engine and N3 WebSocket/SSE, not for unfinished N1 work.
|
||||
|
||||
## Structured Concurrency Implementation (2026-09-12, Complete)
|
||||
|
||||
The user approved this preceding implementation. Networking was paused during it; N1 above resumes AsyncStream/TCP. Each phase uses only focused offline tests under root `test/`; do not run the workspace-wide suite, service checks, old-performance baselines or network load tests.
|
||||
|
||||
### Phase A: Freeze Syntax And Semantic Model
|
||||
|
||||
- [x] Add the canonical `async name(...)` modifier while retaining post-signature `pure`/`recover`; update lexer/parser/formatter and Markdown signature model together.
|
||||
- [x] Add async to function identity metadata and HandlerSignature compatibility without changing package/name/arity lookup.
|
||||
- [x] Reject `async` together with `pure` in the first release and classify every concurrency operator through the existing transitive effect owner.
|
||||
- [x] Add contextual `await`, `run`, `stop`, `group`, `parallel`, `blocking` and `channel` syntax; reject async calls as ordinary stored values.
|
||||
- [x] Add HIR task/group/channel operations and compiler-owned affine local metadata; do not add a user-visible Future or generic evaluator value.
|
||||
- [x] Extend recursive type properties with thread transferability and explicit resource opt-in.
|
||||
- [x] Add focused syntax/format/check cases for clause agreement, sync-to-async rejection, handler mismatch, forbidden Task escape and transfer failures.
|
||||
|
||||
Rollback point: syntax/HIR-only changes must leave all existing synchronous HIR and formatted output unchanged.
|
||||
|
||||
### Phase B: Await And One Shared Runtime
|
||||
|
||||
- [x] Add Tokio with the smallest required features and one runtime owner in `dever-runtime`.
|
||||
- [x] Emit async functions as concrete Rust futures while retaining direct sync emission for wholly synchronous entry graphs.
|
||||
- [x] Implement direct `await(async_call(...))` and async entry execution; preserve zero/single/named multi-output and source-located failures.
|
||||
- [x] Implement async timer sleep as the first real suspension boundary; do not use TCP/HTTP as the proof fixture.
|
||||
- [x] Verify multiple sleeping tasks can make progress without one OS thread per task and sync binaries do not initialize the runtime.
|
||||
|
||||
Rollback point: runtime dependency and native entry changes are isolated from Task ownership and can be removed while keeping Phase A diagnostics.
|
||||
|
||||
### Phase C: Structured Task And Group Ownership
|
||||
|
||||
- [x] Implement `run(async_call(...)) -> Task`, `await(task)`, and exactly-once affine consumption across local writes and every clause exit.
|
||||
- [x] Implement zero-output `stop(task)` as cooperative cancel-and-wait; reject result-bearing stop and repeated consume.
|
||||
- [x] Implement positive bounded `group(limit)`, backpressured `run(group, call)`, `await(group)` and `stop(group)`.
|
||||
- [x] Ensure normal and abnormal parent completion cleans all children; no detached path or swallowed expected failure.
|
||||
- [x] Verify start-before-await concurrency, output equivalence, cancellation cleanup, capacity backpressure and bounded task ownership.
|
||||
|
||||
Rollback point: Task and Group runtime modules remain separate from scheduler construction and do not change direct await.
|
||||
|
||||
### Phase D: Multi-thread And Blocking Work
|
||||
|
||||
- [x] Implement `parallel(sync_call(...))` for pure transferable calls using bounded execution; preserve existing numerical/error semantics.
|
||||
- [x] Implement the compiler-owned `blocking` boundary only for calls with a transitive compiler-known blocking effect; bound active workers plus queued submissions.
|
||||
- [x] Route async use of `parallel_each` away from Tokio workers while retaining the current synchronous contract and shared worker validation.
|
||||
- [x] Configure conservative defaults from available parallelism with explicit hard maxima; do not create per-call runtimes or unconstrained pools.
|
||||
- [x] Verify multi-core execution, no scheduler starvation under bounded blocking work, exact output/error behavior and small-worker configurations.
|
||||
|
||||
Rollback point: retain the existing synchronous `parallel_each` implementation until the common executor passes its focused compatibility cases.
|
||||
|
||||
### Phase E: Bounded Channels And Contract Integration
|
||||
|
||||
- [x] Add compiler-contextual `channel(Type, capacity)` and the runtime Channel resource.
|
||||
- [x] Implement async `send`/`receive`, idempotent `close`, wakeup behavior and explicit source-defined result choices.
|
||||
- [x] Extend effect, failure, dependency, redundancy, API snapshot and Markdown checks for every new signature/operation.
|
||||
- [x] Add documentation only for implemented behavior and a runnable non-network producer/consumer example.
|
||||
- [x] Run the available focused syntax/semantic/native/runtime/concurrency, reference-feature and whitespace checks; record unavailable rustfmt/Clippy components explicitly.
|
||||
|
||||
Final gate: inspect generated native code for concrete futures/direct static handlers and absence of generic Value/handler dispatch. Record passed, failed and unrun checks without claiming network readiness.
|
||||
|
||||
### Final Evidence
|
||||
|
||||
- `structured_concurrency`: 11 passed; syntax, formatter shape, affine ownership, transferability, effects/failures, handler boundaries and Channel contracts.
|
||||
- `async_runtime`: 10 passed; recursive cleanup, cancel-and-wait, Group backpressure, bounded channels, shared blocking limits and async `parallel_each` peak concurrency.
|
||||
- `async_native`: 6 passed; real native execution of await/Task/Group/Channel/parallel/blocking/timer, sync-entry isolation and nullable Channel flattening.
|
||||
- Existing synchronous `concurrency`: 5 passed and its explicit benchmark remained ignored; the async example and nullable-result native regressions each passed their exact case.
|
||||
- `dever-core` with the optional `reference` feature compiled offline. `git diff --check` and explicit trailing-whitespace scans passed. Dependency inspection confirmed Tokio uses only runtime, sync and time features in this phase.
|
||||
- The installed Rust toolchain has no rustfmt or Clippy component, so those two checks were unavailable rather than passed. No full suite, build, service, network, old-performance baseline, global installation or commit was run.
|
||||
- Independent final review found no remaining blocking defect after nullable Channel emission, synchronous collection-handler enforcement and transitive async effect boundaries were corrected.
|
||||
|
||||
### Deferred Follow-through
|
||||
|
||||
- [x] Design and implement AsyncStream/Tokio TCP on the shared runtime in N1. HTTP engine and WebSocket/SSE integration remain later phases.
|
||||
- [ ] Measure the new packaged binary and live network behavior only after network integration; the user explicitly waived an old-runtime baseline.
|
||||
|
||||
## Active Performance Checklist (2026-09-08)
|
||||
|
||||
- [x] Capture bounded compiler, record/text/list/map/JSON/HTTP and concurrency baselines.
|
||||
- [x] Memoize type properties and schedule effect/failure summaries by dependencies.
|
||||
- [x] Eliminate redundant record field copies and consume unique list elements safely.
|
||||
- [x] Optimize direct character-list consumption and eligible collection fusion without changing fault order.
|
||||
- [x] Implement incremental HTTP framing and test in-memory fragments/limits/malformed inputs.
|
||||
- [x] Cache bundled frontend work and native artifacts with complete invalidation and API checks.
|
||||
- [x] Measure concurrent task granularity; batch only where justified and preserve bounded Stream consumption.
|
||||
- [x] Run affected offline tests, native/reference regressions, strict lint, formatting and independent final review; record measurements and update owning docs.
|
||||
|
||||
User has authorized the complete implementation. This extends the active task and does not require another planning approval. Two bounded implement workers own analysis and cache respectively; main owns emission/runtime/protocols and benchmark integration. All permanent tests stay in root test/. Never run workspace-wide tests, existing services or global installation; use test-owned temporary inputs/processes only.
|
||||
|
||||
## Packaged Runtime Footprint Follow-through (2026-09-09)
|
||||
|
||||
- Composite runtime values and generated records/choices now append recursively through `Render::render_to`; named entry outputs reuse that same String instead of building a rendered value and then copying it into a second formatted String. Numeric `to_text` retains its direct `to_string()` path after the bounded hot-path gate exposed a slower generic formatting attempt.
|
||||
- Native binding temporaries now transfer uniquely owned Text/Bytes storage and List/Map values through consuming operations. Live aliases retain copy-on-write behavior, and resource-containing values remain non-movable under the existing type-property contract.
|
||||
- Exact-size finite parallel iterators create no more workers than items/batches. Unknown-length Stream dispatch keeps the caller-requested worker limit, bounded queue, cancellation and joined lifecycle.
|
||||
- Production optimization arguments now use fat LTO and strip symbols; the workspace release runtime uses matching fat LTO/one-unit settings. The same allocation-performance fixture decreased from 4,680,864 to 452,352 bytes (90.3%) and measured 3,468 KiB peak RSS, versus 3,608 KiB without LTO.
|
||||
- Thin LTO was rejected because ordered Map reached a 1.255 native/baseline ratio. Fat LTO passed all five gates: Int 0.713, Float 1.001, List 0.668, Decimal 0.985 and ordered Map 1.030. It trades substantially longer cold compilation for the user-approved packaged-runtime priority.
|
||||
- An attempted fixed 64 KiB clamp for one-shot reads was rejected and removed: it changed a 1 MiB regular-file result to 64 KiB and failed the exact performance result. `read(limit)` remains caller-sized; low-memory programs use smaller limits or `chunks`.
|
||||
- Focused runtime/concurrency/native ownership/core-native checks and both explicit performance scenarios cover the final contracts. No workspace-wide suite, service, external network, global installation or commit was used.
|
||||
|
||||
## Performance Evidence (2026-09-08)
|
||||
|
||||
- Nominal type properties are memoized after cycle validation. Facts, effects and failures share one dependency graph; summary changes reschedule callers instead of rescanning every function. The same 24-level shared-type debug regression went from 11.56 s to 0.47 s across the combined analysis/frontend changes.
|
||||
- Native emission reuses checked HIR and last-use analysis. Safe record aliases are coalesced, scalar reads can be snapshotted before consuming large records, and exact field overwrites can move their old value. Unique Lists move elements; shared Lists clone only consumed elements. Resources retain their original lifetime and aliases retain value semantics. Empty Bytes concatenation reuses storage without weakening copy-on-write.
|
||||
- Text splitting has one iterator implementation. Direct consumers avoid an intermediate List; eligible each/filter stages fuse only when handlers are proven free of observable effects and faults. A pure Int handler alone is insufficient because overflow can change fault order. Generated-code, alias, mutation and native/reference cases cover these boundaries.
|
||||
- HTTP wire decoding now retains its header boundary and parsed frame between feeds. Transport uses that state; legacy one-shot scan delegates to the same implementation. Three new in-memory cases cover fragmentation, binary bodies, EOF, limits, duplicate headers and private/aliased state; five existing pure protocol tests passed. No live HTTP service was used.
|
||||
- Bundled AST and the last complete frontend result are cached within a process. Native artifacts persist across processes, keyed by source-generated code, compiler/toolchain/runtime/dependency identities and native options. Atomic publication, fingerprint validation, isolated executable copies and create-new saves preserve correctness. All six cache tests and the explicit actual-CLI API-baseline regression passed. Independent CLI processes still check current sources and API baselines; no persistent HIR cache was introduced.
|
||||
- Finite parallel inputs use bounded batches through the existing cancellation/join owner; Stream keeps bounded producer-driven pulls. With 32,768 inputs and four workers, median light-handler queue/batch/serial times were 140.945/3.894/0.247 ms; 512-round handlers measured 178.267/20.033/60.185 ms. Batching reduces dispatch cost but does not make tiny tasks preferable to serial execution.
|
||||
- Main-agent final ownership/JSON/reference verification passed 9/7/10 tests respectively; only three network-dependent differential cases were skipped. Concurrency passed five functional cases, contracts passed 38 affected cases, and strict Clippy/type checks passed for core/runtime/CLI and affected test targets. Actual CLI library formatting and contracts/library checks passed. Independent final review found no blocking issue.
|
||||
- After the final Bytes optimization, the main agent reran all three incremental HTTP cases and six default native-cache cases successfully. The actual-CLI cache test is ignored by default and had already passed when explicitly selected. Final targeted Rust formatting and new-file whitespace checks passed.
|
||||
|
||||
The same source was compiled before and after this change. Linux x86-64, Rust 1.98.0, CPU affinity 4; five alternating processes per side, native internal timing excluding compilation/startup. Text/List/JSON each retain five samples per process after discarding warmup; Map retains one per process. All expected results were asserted. Medians:
|
||||
|
||||
| Source workload | Before | After |
|
||||
| --- | --- | --- |
|
||||
| 16,384 record Text appends | 14.093 ms | 0.279 ms |
|
||||
| 16,384 Text List elements | 4.786 ms | 1.342 ms |
|
||||
| Long JSON string parsing | 28.072 ms | 6.977 ms |
|
||||
| Record accumulation of 16,384 distinct Map keys | 548.061 ms | 1.999 ms |
|
||||
| Process peak resident memory | 4,648 KiB | 3,604 KiB |
|
||||
|
||||
- Separate HTTP strategy measurement used identical 16,947-byte input in 64-byte fragments, both paths on the new compiler, seven alternating samples after warmup: repeated one-shot scan 4.541 ms, incremental decode 0.366 ms. This is parser work, not server throughput or an old/new compiler comparison.
|
||||
- Same release CLI hello: cold native miss 0.84 s; subsequent independent-process hits 0.17/0.17/0.16 s, including source/API checks and runtime freshness. In-process frontend cold/hit measured 171.273/3.742 ms.
|
||||
- The existing five-kernel matching-runtime gate passed again with 45 effective samples per side: native/baseline Int 0.989, Float 0.998, List 0.578, Decimal 0.979, ordered Map 1.006 (limit 1.15). This checks code-generation overhead against the same runtime, not against the old compiler. Build times were measured separately: native 2,137–2,693 ms, baseline 252–680 ms.
|
||||
- These are bounded local workloads, not whole-language speed guarantees. README, IMPLEMENTATION and owning specs describe the optimization boundaries. No full suite, service integration, global installation or commit; the performance scope is complete while the umbrella language roadmap remains active.
|
||||
|
||||
## Active Follow-through Checklist (2026-09-07)
|
||||
|
||||
- [x] AST formatter, comments/precedence/idempotence, all-file preparation and CLI fmt/check.
|
||||
- [x] Text/number library expansion and explicit argument/environment/clock primitives.
|
||||
- [x] Opt-in reference evaluator, core semantics and native differential cases.
|
||||
- [x] Last-use and reduction-state ownership optimization with alias/order regressions.
|
||||
- [x] Bounded reproducible native performance baseline and evidence.
|
||||
- [x] JSON/HTTP source packages and focused protocol fixtures.
|
||||
- [x] Controlled concurrent execution with explicit limits/lifecycle and focused verification.
|
||||
- [ ] Resolve database choice from pending user answer; implement or record explicit deferral.
|
||||
- [x] Integrate delivered flows, review, update canonical specs and actual validation evidence.
|
||||
|
||||
Workers implement formatter and reference evaluator independently; the main agent owns libraries and integration. Checks are targeted, offline and bounded; no full suite, live service, global install, commit or cross-platform distribution. Later checklists are historical.
|
||||
|
||||
## Follow-through Evidence (2026-09-07)
|
||||
|
||||
- Implemented syntax-only AST formatting and CLI `fmt`/`--check`. Source snapshots are reloaded before staging and before replacement, comparing both the complete path set and file contents. Independent review found the initial missing path-set check; the shared source loader now closes that gap without a second traversal implementation. Per-file replacement remains atomic, not a multi-file OS transaction.
|
||||
- Added Unicode Text operations, numeric parsing/rendering, process arguments/environment and explicit clocks/sleep through the existing intrinsic catalog and source-defined result choices. JSON and HTTP algorithms are ordinary `.dever` packages; no runtime JSON/HTTP parser or new dependency was added.
|
||||
- JSON validates grammar, precise numeric spelling, duplicate keys, Unicode, graph references, nesting and expansion limits. HTTP supports a declared HTTP/1.1 single-message subset with binary bodies, Content-Length, strict ASCII headers and typed failures; independent peers check canonical request/response bytes, fragmentation, invalid requests/400, EOF and no-body statuses. Blocking read/write syscalls have explicit timeouts; no strict overall message deadline is claimed.
|
||||
- `parallel_each` reuses static handlers/sequence classification and adds a bounded producer/worker owner with explicit worker limits, fault cancellation at pull boundaries and joined completion. Stream remains producer-owned; worker inputs/context cannot recursively contain Stream.
|
||||
- Ordinary last-use moves and transferred reduction state preserve live aliases and output/field order. Resource-containing locals retain lexical lifetime; a differential socket regression verifies no premature peer EOF. Full-domain Int/Decimal guards omit redundant comparisons without altering bounded clauses.
|
||||
- Passed 25 targeted core/library tests: `standard_library` 5, `native_ownership` 3, `concurrency` 4 and opt-in `differential` 13. `formatter` passed 11 tests including added/renamed source snapshots and all current official packages/examples. JSON passed 7 and HTTP passed 8 in worker validation; the main agent independently reran Unicode/exact-number JSON and the real HTTP server wire/400 case. Production CLI feature resolution excludes `reference`.
|
||||
- Actual CLI `check`, `fmt`, `run` and `build` succeeded for `examples/library/src`; normal run and a standalone executable under `env -i PATH=/nonexistent` printed `json = {"message":"你好 Dever","total":6}` and `http_roundtrip = true`.
|
||||
- Independent final review found no remaining blocker in formatter, reference, ownership, numeric domain optimization, concurrency and JSON after the snapshot fix. Main-agent HTTP review checked framing/status/timeout contracts. Database selection remains pending rather than implicitly chosen.
|
||||
- Passed the explicitly ignored performance target on Linux x86-64, CPU affinity 4, Rust 1.98.0, cached runtime, optimization level 3 and one codegen unit. Each side used five alternating processes and 45 effective samples. Native/baseline median ratios: checked Int 0.952, Float 1.000, List each/filter/sum 0.207, Decimal 1.001, ordered Map 1.145; all met 1.15. Native build times were 1,206–1,793 ms, baseline compile times 255–668 ms, recorded separately from execution. These figures cover the selected kernels only.
|
||||
- Decimal comparison was corrected to use identical lexical `0.0` representation with baseline parsing outside timing. Map diagnostics identified missed generic hash-table inlining under multiple codegen units; production and baseline now share one optimization-argument constant. This changes compiler optimization scope without changing hashing, panic, arithmetic or value semantics; it trades compilation parallelism for optimization consistency.
|
||||
- After the final native compiler setting, all 13 differential cases passed again, including exact fault traces, signed zero, Map semantics and resource lifetime. Strict Clippy/type checks passed for core/runtime/CLI and every new test target; targeted rustfmt and explicit whitespace checks passed. The complete follow-through has 51 functional tests plus one five-kernel performance gate, not a full workspace test run.
|
||||
- No full suite, existing service, external database, global toolchain/command change, Git commit or archive. Distribution/cross-platform remains deferred; self-hosting is still unshipped.
|
||||
|
||||
- Status: Approved core foundations and foundation extension implemented and verified on 2026-09-07
|
||||
- Requirement source: `prd.md`
|
||||
- Architecture source: `design.md`
|
||||
- Execution mode: one tightly coupled task; no obsolete child-task dispatch
|
||||
|
||||
## Completed Foundation Delivery Rule (Historical)
|
||||
|
||||
Implement the foundation extension as one bounded delivery: `reduce`, `reduce_until`, Bytes traversal, `Stream<Item>`, restricted static handler inputs, file/TCP stream wrappers and focused verification. Reuse the existing collection checker, typed HIR, intrinsic catalog, native emitter and resource owner; do not build a parallel execution path. Compiler distribution, cross-platform work, formatter/evaluator work and full HTTP/JSON/CRUD/database packages remain deferred. The completed core and hello milestones are regression baselines; the old API and original phase checklists are historical.
|
||||
|
||||
## Foundation Extension Checklist (Authoritative, Complete)
|
||||
|
||||
### 1. Syntax And Semantic Contracts
|
||||
|
||||
- [x] Parse contextual `handler(inputs) (named_outputs)` only in function input declarations, using a dedicated AST input kind rather than an ordinary value type.
|
||||
- [x] Parse `Stream<Item>` through the standard generic-type path; reject wrong arity, nullable handler signatures and handler syntax in fields, outputs or local/value positions.
|
||||
- [x] Add semantic `HandlerSignature` and handler-parameter symbols separately from runtime `Type`; add opaque `Stream(Item)` to the type model with non-comparable, non-Map-key resource semantics.
|
||||
- [x] Centralize handler compatibility, allowed reference positions and sequence element classification so direct calls, forwarding, `each`, `reduce` and `reduce_until` cannot drift.
|
||||
|
||||
### 2. Typed HIR And Static Specialization
|
||||
|
||||
- [x] Replace collection-only handler IDs with shared `HandlerTarget`, `CallTarget` and handler/value call arguments.
|
||||
- [x] Lower direct handler calls and multi-level forwarding without storing handlers in value locals or aggregates.
|
||||
- [x] Key native specializations by function plus ordered concrete handler bindings, substitute every forwarded target, and emit only direct calls.
|
||||
- [x] Detect direct and indirect cycles in the substituted specialization graph before private Rust compilation.
|
||||
|
||||
### 3. Sequence Operations
|
||||
|
||||
- [x] Add `reduce` and `reduce_until` to the single standard-operation registry and HIR, with exact state and `stop: Bool` output contracts.
|
||||
- [x] Lower List and Bytes traversal as left-to-right direct loops; emit Bytes elements as Int values without an intermediate List.
|
||||
- [x] Extend `each` to Bytes and zero-output Stream consumption while preserving existing List mapping/action behavior.
|
||||
- [x] Leave `filter`, `find` and `sum` List-only and reject implicit Stream collection.
|
||||
- [x] Add idempotent zero-output `close(stream)` and reject it for non-Stream values.
|
||||
|
||||
### 4. Stream Runtime And Official Packages
|
||||
|
||||
- [x] Add one generic runtime Stream owner with shared cursor/end/close state and serialized pull/close operations; do not add prefetch, threads or async machinery.
|
||||
- [x] Implement natural EOF, one terminal typed failure item, idempotent close, alias continuation after `reduce_until`, and release of only the Stream-held source alias.
|
||||
- [x] Add `ReadEvent`, `ReadStreamResult` and `chunks` to bundled `dever.io`; add socket `chunks` and listener `connections` to bundled `dever.net`.
|
||||
- [x] Extend fixed `dever.system` intrinsic signatures and generated typed adapters only for Stream creation/pulling; keep public result choices in `.dever` source and OS/resource mechanics in runtime.
|
||||
- [x] Preserve existing one-shot read/write/accept/close contracts without compatibility aliases or behavior changes.
|
||||
|
||||
### 5. Focused Verification And Cleanup
|
||||
|
||||
- [x] Add parser/semantic negatives for handler placement, type/arity/output mismatch, forbidden storage/return/comparison/clause use and indirect recursion.
|
||||
- [x] Add native List/Bytes cases for empty input, order, state typing, stop behavior, zero-output each and absence of intermediate Bytes allocation.
|
||||
- [x] Add runtime/native Stream cases for shared aliases, natural EOF, early stop/resume, repeated close, source close, invalid limit and one terminal failure.
|
||||
- [x] Compile official wrappers through the normal source loader and test file chunks plus loopback socket chunks/connections with owned resources, bounded data and timeouts.
|
||||
- [x] Exercise actual CLI `check`, `run`, `build` and the resulting standalone executable with a chunked state-parser fixture whose behavior is defined in `.dever`.
|
||||
- [x] Run focused formatting/type/lint/test checks only, inspect generated code/artifacts for direct handler calls, validate Trellis context and run whitespace checks.
|
||||
- [x] Review the final diff for duplicate contracts, runtime handler dispatch, eager Stream collection, HTTP/JSON leakage and unrelated changes; update the canonical specs and implementation evidence.
|
||||
|
||||
Planned focused validation targets:
|
||||
|
||||
```bash
|
||||
cargo test --offline -p dever-tests --test syntax_and_format <handler-or-stream-filter>
|
||||
cargo test --offline -p dever-tests --test core_semantics <reduce-or-handler-filter>
|
||||
cargo test --offline -p dever-tests --test core_native <sequence-or-specialization-filter>
|
||||
cargo test --offline -p dever-tests --test runtime_foundations <stream-or-loopback-filter>
|
||||
cargo test --offline -p dever-tests --test hello_native <regression-filter>
|
||||
cargo check --offline -p dever-core -p dever-runtime -p dever-cli
|
||||
python3 ./.trellis/scripts/task.py validate 09-04-dever-language-mvp
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Filters will be replaced by the concrete test names introduced during implementation. No full suite, workspace-wide test, performance gate, service start, external network call or global command mutation is authorized. File tests use test-owned temporary directories; TCP tests bind only `127.0.0.1:0` and terminate within explicit bounds.
|
||||
|
||||
Rollback boundaries are syntax/semantic representation, HIR/specialization, finite sequences, runtime Stream and official wrappers. A boundary is not accepted while it relies on a runtime function value, duplicated checker rule, eager collection fallback or partially exposed public API.
|
||||
|
||||
## Foundation Extension Evidence (2026-09-07)
|
||||
|
||||
- Handler inputs use dedicated syntax, semantic symbols and HIR arguments. Clause coverage and runtime locals traverse value parameters only. One specialization graph resolves direct and multi-level handler forwarding, records real cross-package handler references and rejects substituted recursion; generated functions contain direct calls and no user-handler function values.
|
||||
- `reduce`, `reduce_until` and `each` reuse one sequence classifier. List and Bytes lower to direct left-to-right loops, Stream pulls on demand, and `reduce_until` does not pull past the stopping item. Bytes traversal yields Int directly without constructing a List.
|
||||
- Runtime `Stream<T>` shares cursor/end/close state across aliases and serializes pull/close. File/socket chunks validate creation, release their producer at EOF or after one terminal failure, and support early-stop continuation. Bundled `dever.io` and `dever.net` expose source-defined stream choices through the normal loader.
|
||||
- Passed `cargo check --offline -p dever-core -p dever-runtime -p dever-cli` and strict Clippy for core/runtime/CLI plus the root test crate. `cargo fmt --all --check` passed.
|
||||
- Passed 74 focused tests: 22 `syntax_and_format`, 16 `core_semantics`, 16 `core_native`, 8 `runtime_foundations` and 12 `hello_native`. File tests owned their temporary directories; TCP tests used `127.0.0.1:0`, explicit timeouts and bounded transfers.
|
||||
- Final review made handler signatures reuse ordinary nested Map validation, preserved `Pull::Last` through mapped official streams, and added generated-code plus official creation-failure regressions. An independent read-only review then found no blocking correctness, safety or contract issue.
|
||||
- Actual CLI `check`, `run` and `build` succeeded for `examples/stream/src`; run and the standalone executable both printed `total = 208`. The executable also ran with an empty environment and no Cargo/Rust path.
|
||||
- No formatter/evaluator, async/concurrency system, HTTP/JSON/database package, external service, full workspace test, benchmark, distribution change, global command change or commit was included.
|
||||
|
||||
## Active Core Checklist
|
||||
|
||||
- [x] Record clause-only conditional dispatch as a permanent language rule and remove conditional blocks from the deferral list.
|
||||
- [x] Retain settled repetition rules and remove the redundant planning blocker.
|
||||
- [x] Record the user's approval and map the implementation boundary to core language and system interfaces.
|
||||
- [x] Implement scalar/aggregate types, complete symbols, expressions, outputs and value-semantic assignments.
|
||||
- [x] Implement clause type inference, normalization, overlap/exhaustiveness analysis and typed native dispatch.
|
||||
- [x] Implement numeric and collection runtime operations plus shared intrinsic contracts.
|
||||
- [x] Compile bundled official source and implement Bytes/file/TCP resource foundations.
|
||||
- [x] Verify focused semantic/native/runtime cases and review the final cross-layer changes.
|
||||
|
||||
## Core Foundation Evidence (2026-09-07)
|
||||
|
||||
- Implemented six scalars, records/choices/nullable/List/Map/MapEntry, typed expressions, named outputs, stable assignments and value semantics through check/HIR/native execution. Added naming and unused-write diagnostics.
|
||||
- Function groups infer one signature, use symbolic per-axis domains and rectangle subtraction to prove disjoint coverage, and lower into concrete native dispatch. No conditional blocks, source loops or user recursion were introduced.
|
||||
- Official source in `library/` shares the same frontend; one intrinsic enum bridges the small system boundary. Decimal128 and ordered maps reuse pinned `dec`/`indexmap` runtime wrappers. Added Bytes, create-new/read-only files, TCP and shared-close opaque handles with explicit source-defined result choices.
|
||||
- Passed 46 focused tests: 13 `core_semantics`, 9 `core_native`, 5 `runtime_foundations`, 12 existing `hello_native`, and 7 relevant `syntax_and_format` source/diagnostic regressions. Runtime tests used owned temporary files and loopback port 0 only. No full suite or integration environment was run.
|
||||
- Passed targeted rustfmt and strict Clippy/type checks for compiler/runtime/CLI and affected test targets. Existing tool archives were invoked with command-scoped paths; a local ignored verification wrapper supplies the toolchain library path after Cargo sanitizes its environment. No global installation or environment changes.
|
||||
- Actual CLI `run examples/core/src app.main` produced all 22 expected named outputs. `check` succeeded with nonexistent RUSTC. `build` produced `target/dever-core-example`, confirmed as a native Linux x86-64 ELF, and it produced the same outputs with `env -i PATH=/nonexistent`.
|
||||
- Independent read-only review found and closed duplicate choice Map keys, Group-sensitive inference, null-only `first`, and Float signed-zero constant propagation. Added semantic/native regressions; Float literal contextual typing does not retype existing Decimal/Int locals.
|
||||
- The initial wrapper/fixture errors and one stale numeric rejection fixture were corrected; final affected checks passed. Trellis context validation passed with implementation/check JSONL absent and skipped for inline work. Ordinary `git diff --check` passes but does not inspect the untracked compiler files; targeted formatting and explicit new-file whitespace checks cover those files.
|
||||
- Formatter, reference evaluator/differential checks, performance gates, full HTTP/JSON/database packages, self-hosting and distribution/cross-compilation were not implemented or claimed by this delivery. No commit/archive; the wider language task remains active.
|
||||
|
||||
## Completed Hello Checklist
|
||||
|
||||
- [x] Correct the superseded API-first requirements and record the approved Text/action subset.
|
||||
- [x] Add package/function resolution, semantic diagnostics and checked HIR.
|
||||
- [x] Add standard output runtime and native compilation.
|
||||
- [x] Add local check/build/run CLI and `examples/hello/src/app/user.dever`.
|
||||
- [x] Run focused semantic/native/runtime tests and the actual hello command; announce local process execution first.
|
||||
- [x] Review the final changes, update implementation evidence and record the session.
|
||||
|
||||
## Native Hello Evidence (2026-09-06)
|
||||
|
||||
- Implemented the approved Text/action subset, checked HIR, shared stdout runtime, native Rust generation and local `deverc` CLI. Example: `examples/hello/src/app/user.dever`.
|
||||
- Passed 12 `hello_native` tests and the existing 20 `syntax_and_format` tests. After the final emitter readability change, reran all 12 native tests successfully.
|
||||
- Passed rustfmt and strict Clippy for core/runtime, both targeted test binaries and the actual CLI binary.
|
||||
- Actual CLI `check` succeeds even with a nonexistent RUSTC, proving it does not invoke compilation. `run` prints exactly `hello\n`; an unknown entry returns exit 1. `build` produced `target/hello-user`, identified as a native x86-64 ELF, which prints `hello\n` with PATH containing no Rust tools.
|
||||
- Independent read-only reviewer found no blocking issue; the noted CLI verification gap was closed by the actual commands above. Tests exercise Unicode/escaping, source locations, value semantics and write failures, not a User/hello-specific execution branch.
|
||||
- Added README run/build instructions and updated owning compiler specs. No global command replacement, external dependency, commit, service, database or load test.
|
||||
- This bounded milestone is complete. The overall language roadmap remains open; HTTP/JSON/CRUD and persistence are deferred pending the user's next step.
|
||||
|
||||
Preserve unrelated changes and do not create a commit without explicit authorization. Verification for the new API must use its own local process and test storage, with functional checks and bounded performance checks described before execution. Do not test against, restart or benchmark existing services. No runtime or load check has been run during this planning turn.
|
||||
|
||||
## Historical API Replanning Checklist (Deferred)
|
||||
|
||||
- [x] Record the real user API goal and supersede the pure-computation-only boundary.
|
||||
- [x] Keep `.dever` source and the existing surface syntax; defer the speculative contract-declaration system.
|
||||
- [ ] Confirm persistence selection.
|
||||
- [ ] Specify typed HTTP/JSON/storage boundaries and necessary effect/concurrency semantics.
|
||||
- [ ] Finalize user API behavior and meaningful performance acceptance.
|
||||
- [ ] Replace the next execution steps with a bounded native application delivery plan.
|
||||
- [ ] Review the concrete plan with the user before implementation.
|
||||
|
||||
Proposed delivery order, to finalize after the open product decisions:
|
||||
|
||||
1. Implement name/type/clause/flow checking and HIR for the language features the API actually uses.
|
||||
2. Establish concrete native business-function execution and source-located failures.
|
||||
3. Add typed HTTP/JSON boundaries, explicit resource/effect semantics and the selected persistent database adapter.
|
||||
4. Implement `examples/user-api` entirely in `.dever`, with real CRUD and configuration supplied by the runtime environment.
|
||||
5. Run announced, isolated functional/persistence/concurrency checks and a bounded native performance comparison.
|
||||
|
||||
Complete Decimal/Float/Map libraries, the full reference evaluator, formatter, component distribution and AI indexing remain on the roadmap; they are not all prerequisites for the first user API. Preserve unsupported-source diagnostics rather than silently approximating unimplemented language behavior.
|
||||
|
||||
## Initial Frontend Evidence (2026-09-05)
|
||||
|
||||
- Implemented: dependency-free Rust workspace, source directory loading, UTF-8 and line/column handling, deterministic diagnostics, lexer, spanned AST and parser.
|
||||
- Passed: 20 focused `syntax_and_format` tests, including the complete PRD package; Rust formatting check; focused Clippy with `-D warnings`; diff whitespace check.
|
||||
- Independent review: fixed iterative expression-tree depth bypass and removed inaccurate terminal-width caret rendering. Follow-up review confirmed both fixes.
|
||||
- Validation tools: rustc/Cargo 1.98.0 are installed but absent from the default PATH. Rustfmt and Clippy were missing, so their exact 1.98.0 official archives were downloaded to ignored `target/verification-tools/`, checked against the installed Rust manifest SHA-256 values and invoked directly with command-scoped library/tool paths. No global toolchain installation or command replacement occurred.
|
||||
- At that checkpoint, native/differential/performance checks had not run. The Native Hello Evidence above records the subsequently implemented and verified native subset.
|
||||
- The previous API-first next step was superseded by the approved hello-world milestone; formatter and other language work remain on the roadmap.
|
||||
|
||||
## Historical Original Roadmap Notice
|
||||
|
||||
The phase checklist below records the original repository bootstrap plan. Its unchecked boxes are not the current implementation status and do not expand the authoritative extension above. The Active Core Checklist and dated evidence describe completed work.
|
||||
|
||||
## Phase 1: Initialize The Repository
|
||||
|
||||
### 1.1 Preserve and classify current changes
|
||||
|
||||
- [x] Record `git status --short`; current changes contain planning and agent metadata, plus two deleted old documents.
|
||||
- [x] Confirm no old Rust workspace, implementation or test files exist in the working tree or HEAD.
|
||||
- [x] Preserve existing user changes; no old implementation needs removal.
|
||||
|
||||
### 1.2 Establish the new workspace
|
||||
|
||||
- [x] Create `crates/dever-core` as the single language library.
|
||||
- [ ] Add `crates/dever-runtime` in Phase 7 when numeric/fault consumers exist; keep parser, checker, HIR and evaluator code out of it.
|
||||
- [ ] Add `crates/dever-cli` in Phase 10 for the `dever` binary; do not expose syntax-only success as the public semantic `check` command.
|
||||
- [x] Create `test/dever-tests` as the only permanent test crate.
|
||||
- [x] Create root `Cargo.toml`; pin external dependencies when they are first consumed.
|
||||
- [ ] Add a decimal128 dependency behind `dever-runtime::number` and reuse that wrapper from the evaluator.
|
||||
- [ ] Add an insertion-ordered map dependency behind `dever-runtime::collections` and reuse that wrapper from the evaluator.
|
||||
- [x] Do not add parser generators, async runtimes, plugin systems or CLI frameworks.
|
||||
|
||||
### 1.3 Establish current rules
|
||||
|
||||
- [x] Confirm the rejected prototype and its fixtures/tests are absent; do not add migration scaffolding.
|
||||
- [x] Preserve existing deletion of superseded plan/spec documents.
|
||||
- [x] State in `AGENTS.md` that `.dever` source is the trusted source.
|
||||
- [x] Replace relevant Trellis spec placeholders with the actual frontend ownership and verification rules.
|
||||
|
||||
Rollback point: kickoff adds compiler files and updates canonical planning only; existing user deletions and unrelated metadata are preserved.
|
||||
|
||||
## Phase 2: Source, Diagnostics And Lexer
|
||||
|
||||
### 2.1 Source ownership
|
||||
|
||||
- [x] Implement `SourceId`, `SourceFile`, `SourceMap` and half-open `Span`.
|
||||
- [x] Precompute line starts and render stable one-based line/column positions.
|
||||
- [x] Load `.dever` paths in lexical order and reject invalid UTF-8.
|
||||
|
||||
### 2.2 Diagnostics
|
||||
|
||||
- [x] Implement the shared diagnostic model; semantic phases will consume it when implemented.
|
||||
- [x] Support primary and related spans plus stable diagnostic codes.
|
||||
- [x] Sort diagnostics deterministically.
|
||||
- [x] Add renderer tests for the syntax-phase messages, related source files and Unicode locations.
|
||||
|
||||
### 2.3 Lexer
|
||||
|
||||
- [x] Tokenize identifiers, keywords, delimiters, operators, newlines and comments.
|
||||
- [x] Preserve numeric spelling and comment trivia.
|
||||
- [x] Decode Text escapes with precise bad-escape diagnostics.
|
||||
- [x] Reject non-ASCII identifiers while allowing UTF-8 strings/comments.
|
||||
|
||||
Focused checks:
|
||||
|
||||
```bash
|
||||
cargo test --offline -p dever-tests --test syntax_and_format
|
||||
```
|
||||
|
||||
## Phase 3: Parser And Formatter
|
||||
|
||||
### 3.1 Syntax tree
|
||||
|
||||
- [x] Define focused AST nodes for package, type, function clauses, patterns, statements and expressions.
|
||||
- [x] Keep every node spanned; do not attach resolved IDs or runtime values.
|
||||
- [x] Preserve ordered comments with source spans; formatter attachment remains part of Phase 3.3.
|
||||
|
||||
### 3.2 Recursive-descent parser
|
||||
|
||||
- [x] Parse the package header and exposure list.
|
||||
- [x] Parse record and choice type declarations.
|
||||
- [x] Parse function signatures, clause patterns and linear bodies.
|
||||
- [x] Parse record/List/Map values, calls, field access and operators with fixed precedence.
|
||||
- [x] Recover only at bounded declaration/statement delimiters.
|
||||
- [x] Reject excluded constructs rather than accepting compatibility syntax.
|
||||
|
||||
### 3.3 Canonical formatter
|
||||
|
||||
- [ ] Format every valid syntax node from structure.
|
||||
- [ ] Preserve comments and normalize whitespace, blank lines and indentation.
|
||||
- [ ] Add parse-format-parse and twice-format idempotence tests.
|
||||
- [ ] Refuse to rewrite invalid files.
|
||||
|
||||
Focused check:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test syntax_and_format
|
||||
```
|
||||
|
||||
Milestone boundary: the parser is currently an internal library for focused tests. Do not expose a public checked-source or formatting command until its complete contracts are implemented.
|
||||
|
||||
## Phase 4: Package And Name Resolution
|
||||
|
||||
- [ ] Register package/type/function headers before resolving bodies.
|
||||
- [ ] Validate path/package equality and one-file ownership.
|
||||
- [ ] Load only the supplied source root and fixed standard catalog; do not search external paths or perform network access.
|
||||
- [ ] Reserve core single-segment package names and `dever.*` against local declarations.
|
||||
- [ ] Validate `exposes` against locally declared names.
|
||||
- [ ] Resolve local short names and cross-package fully qualified names.
|
||||
- [ ] Enforce visibility without import tables.
|
||||
- [ ] Group same-name/same-arity clauses and enforce contiguity.
|
||||
- [ ] Reject package, recursive type and direct/indirect function cycles.
|
||||
- [ ] Include standard core and qualified package names through one fixed catalog.
|
||||
- [ ] Report unavailable future official/third-party references as unknown packages without an implicit install fallback.
|
||||
|
||||
Focused check:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test package_resolution
|
||||
```
|
||||
|
||||
## Phase 5: Type Checking And Linear Flow
|
||||
|
||||
### 5.1 Type interning and declarations
|
||||
|
||||
- [ ] Implement scalar, record, choice, nullable, List, Map, MapEntry, Stream and multi-output types, with static handler inputs represented separately from values.
|
||||
- [ ] Reject record/choice member mixing and recursive user types.
|
||||
- [ ] Validate choice payload arity and record completeness.
|
||||
- [ ] Validate Map key eligibility.
|
||||
|
||||
### 5.2 Expressions and calls
|
||||
|
||||
- [ ] Check literals using expected type without premature numeric conversion.
|
||||
- [ ] Implement operator tables exactly as specified in the PRD.
|
||||
- [ ] Permit only lossless Int-to-Decimal implicit promotion.
|
||||
- [ ] Resolve positional function calls and named multi-output access.
|
||||
- [ ] Restrict named handler references to sequence operations, direct static invocation and approved handler-input forwarding.
|
||||
|
||||
### 5.3 Definite assignment and mutation
|
||||
|
||||
- [ ] Track uninitialized/initialized locals in one forward pass.
|
||||
- [ ] Reject reads and field writes before complete initialization.
|
||||
- [ ] Require every output on every clause path.
|
||||
- [ ] Keep a local's inferred type stable across reassignment.
|
||||
- [ ] Report unused writes without adding defensive runtime behavior.
|
||||
|
||||
Focused check:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test type_checking
|
||||
```
|
||||
|
||||
## Phase 6: Clause Analysis And Typed HIR
|
||||
|
||||
### 6.1 Normalize patterns
|
||||
|
||||
- [ ] Normalize Bool, null, choice, scalar constant and `other` patterns.
|
||||
- [ ] Normalize Int/Decimal comparisons into open/closed intervals.
|
||||
- [ ] Support at most one lower and one upper bound joined by `and`.
|
||||
- [ ] Reject Float ranges and dynamic/function-based guards.
|
||||
|
||||
### 6.2 Prove clause validity
|
||||
|
||||
- [ ] Compute overlap, reachability and exhaustiveness over symbolic domains.
|
||||
- [ ] Support products of multiple input domains without enumerating numeric values.
|
||||
- [ ] Emit diagnostics that label both conflicting clauses or the uncovered domain.
|
||||
- [ ] Prove that permuting source clauses leaves the normalized decision model unchanged.
|
||||
|
||||
### 6.3 Lower typed HIR
|
||||
|
||||
- [ ] Lower only fully checked packages.
|
||||
- [ ] Replace names with resolved IDs and attach static types/spans.
|
||||
- [ ] Build decision nodes from normalized clause domains.
|
||||
- [ ] Keep HIR internal to `dever-core`; do not serialize it as a second source format.
|
||||
|
||||
Focused check:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test clause_analysis
|
||||
```
|
||||
|
||||
Rollback point: do not add an ordered first-match fallback if coverage analysis is incomplete. Unsupported patterns must fail compilation.
|
||||
|
||||
## Phase 7: Values, Numbers And Reference Evaluator
|
||||
|
||||
### 7.1 Runtime values
|
||||
|
||||
- [ ] Implement the language-owned `Value` variants.
|
||||
- [ ] Use shared immutable aggregate storage with copy-on-write updates.
|
||||
- [ ] Wrap insertion-ordered Map behavior and use order-preserving removal.
|
||||
- [ ] Implement deterministic value rendering and named output order.
|
||||
|
||||
### 7.2 Numeric layer
|
||||
|
||||
- [ ] Implement checked i64 arithmetic, including negative division/remainder edges.
|
||||
- [ ] Wrap Decimal128 Context with round-half-even and per-operation status clearing/checks; accept inexact/rounded and fault on overflow, underflow, division by zero or invalid operation.
|
||||
- [ ] Reject Decimal special values at the `DecimalValue` boundary.
|
||||
- [ ] Implement exact Int-to-Decimal and explicit Int-to-Float conversion.
|
||||
- [ ] Reject inexact Decimal literals while allowing specified inexact/rounded arithmetic results.
|
||||
- [ ] Implement f64 arithmetic and IEEE classification functions without fast math.
|
||||
- [ ] Add Decimal conformance and numeric fault fixtures.
|
||||
|
||||
### 7.3 Evaluator
|
||||
|
||||
- [ ] Execute HIR with explicit frames and no mutable global state.
|
||||
- [ ] Select clauses through compiled decision nodes.
|
||||
- [ ] Preserve source-level value semantics during local and field mutation.
|
||||
- [ ] Return named outputs or an uncatchable `RuntimeFault` with source span.
|
||||
- [ ] Add a Dever call trace only as diagnostic context.
|
||||
- [ ] Keep evaluator entry points internal to compiler tests; production `build` and `run` must not depend on them.
|
||||
|
||||
Focused checks:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test value_semantics
|
||||
cargo test -p dever-tests --test numbers
|
||||
cargo test -p dever-tests --test failures runtime
|
||||
```
|
||||
|
||||
## Phase 8: Standard Functions
|
||||
|
||||
- [ ] Define one static signature/evaluator catalog for core and qualified standard names.
|
||||
- [ ] Implement `append`, `first`, `get`, `put`, `remove` and `entries`.
|
||||
- [ ] Implement `each`, `reduce`, `reduce_until`, `filter`, `find` and `sum` with shared sequence/handler helpers.
|
||||
- [ ] Enforce one optional context and element-first handler inputs.
|
||||
- [ ] Preserve order and short-circuit `find`.
|
||||
- [ ] Keep Float sum left-to-right.
|
||||
- [ ] Implement minimum `text`, `decimal`, `float` and `math` functions used by the PRD.
|
||||
- [ ] Do not add unrequested collection aliases, lazy Stream transforms or reduction names besides `reduce` and `reduce_until`.
|
||||
|
||||
Focused check:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test collections
|
||||
cargo test -p dever-tests --test numbers standard_functions
|
||||
```
|
||||
|
||||
## Phase 9: Native AOT Compilation
|
||||
|
||||
### 9.1 Whole-program specialization
|
||||
|
||||
- [ ] Start from one checked, exposed, zero-input entry function and collect its reachable HIR.
|
||||
- [ ] Specialize every concrete record, choice, nullable, List, Map, Stream and static handler-binding combination.
|
||||
- [ ] Lower clauses to deterministic native decision trees and collection functions to direct loops.
|
||||
- [ ] Perform last-use/liveness analysis so dead sources move instead of clone while observable value semantics remain unchanged.
|
||||
- [ ] Reject any native path that would require a generic runtime `Value`, reflective lookup or virtual per-element dispatch.
|
||||
|
||||
### 9.2 Private Rust emission
|
||||
|
||||
- [ ] Emit concrete Rust types and direct functions from typed HIR through one structured writer with centralized identifier/literal escaping.
|
||||
- [ ] Emit explicit checked numeric and source-located runtime-fault operations.
|
||||
- [ ] Make generated programs depend only on `dever-runtime`, never `dever-core` or the evaluator.
|
||||
- [ ] Keep generated Rust and Cargo metadata in a compiler-owned transient directory with no public emit command.
|
||||
- [ ] Compile with an optimized release profile starting at opt-level 3, thin LTO and one codegen unit.
|
||||
- [ ] Translate toolchain failures into stable compiler diagnostics without leaking generated identifiers as Dever names.
|
||||
|
||||
### 9.3 Native conformance and performance
|
||||
|
||||
- [ ] Differentially compare evaluator and native outputs/fault categories across the language conformance corpus.
|
||||
- [ ] Inspect native artifacts to prove the evaluator is not linked.
|
||||
- [ ] Benchmark scalar arithmetic and List `each`/`filter`/`sum` against equivalent safe Rust using the same algorithm, data layout and toolchain.
|
||||
- [ ] Benchmark Decimal and ordered Map separately against Rust baselines using the same underlying semantic wrappers.
|
||||
- [ ] Fail the performance gate when representative median native hot-path time exceeds 1.15 times the matching Rust baseline.
|
||||
|
||||
Focused checks:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test native
|
||||
cargo test -p dever-tests --test differential
|
||||
cargo test -p dever-tests --test performance -- --ignored
|
||||
```
|
||||
|
||||
Rollback point: the evaluator remains the semantic oracle, but an incomplete native backend cannot silently become the production `run` path. Unsupported lowering is a compile diagnostic.
|
||||
|
||||
## Phase 10: CLI And End-To-End Example
|
||||
|
||||
### 10.1 CLI
|
||||
|
||||
- [ ] Implement `check`, `fmt`, `build` and `run` as thin adapters.
|
||||
- [ ] Do not add registry, `add`, `update`, signature or component-cache commands in Core 0.1.
|
||||
- [ ] Validate exact argument counts and stable exit codes.
|
||||
- [ ] Keep diagnostics on stderr and results on stdout.
|
||||
- [ ] Make `fmt` all-or-nothing when any source file is invalid.
|
||||
- [ ] Restrict `build` and `run` to exposed zero-input functions.
|
||||
- [ ] Make `build` write an optimized native executable to `--output` and make `run` compile/execute the same native path.
|
||||
- [ ] Keep the Cargo binary and canonical command name as `dever`; do not rename compiler internals or public command semantics to `deverc`.
|
||||
- [ ] Treat `deverc`, when explicitly installed for coexistence, as a thin link or launcher to the same compiler binary with no divergent behavior.
|
||||
- [ ] Do not replace the existing framework `dever`, modify system `PATH` or create global executables during repository implementation or automated tests.
|
||||
- [ ] If global `deverc` setup is later authorized, resolve and record both command targets and verify that the existing global `dever` remains unchanged.
|
||||
|
||||
### 10.2 Example and integration
|
||||
|
||||
- [ ] Add the canonical account/user package from the PRD.
|
||||
- [ ] Add a zero-input executable example covering types, clauses, collections and numbers.
|
||||
- [ ] Verify multiple source files and full qualification.
|
||||
- [ ] Verify the zero-input example produces identical evaluator and native results.
|
||||
- [ ] Ensure no example source depends on Rust, JSON graph, React or a hidden host fallback.
|
||||
|
||||
Focused check:
|
||||
|
||||
```bash
|
||||
cargo test -p dever-tests --test cli
|
||||
```
|
||||
|
||||
## Phase 11: Cleanup And Final Verification
|
||||
|
||||
### 11.1 Structural review
|
||||
|
||||
- [ ] Search for duplicate operator, standard-function, diagnostic and type rules.
|
||||
- [ ] Keep each language rule owned by one table/module.
|
||||
- [ ] Remove obsolete compatibility code, commented code, placeholders and old architecture references.
|
||||
- [ ] Confirm the CLI contains no language semantics.
|
||||
- [ ] Confirm no public Rust API leaks into `.dever` diagnostics or docs.
|
||||
- [ ] Confirm generated binaries depend on the minimal runtime but not compiler/evaluator modules.
|
||||
- [ ] Confirm private generated Rust is not documented or tested as a public compatibility format.
|
||||
|
||||
### 11.2 Acceptance mapping
|
||||
|
||||
- [ ] Map all 20 PRD acceptance criteria to named test cases.
|
||||
- [ ] Run each relevant focused test target.
|
||||
- [ ] Run static formatting and diff checks.
|
||||
- [ ] Record passed, failed, skipped and not-run checks separately.
|
||||
|
||||
Permitted final checks, announced before execution:
|
||||
|
||||
```bash
|
||||
cargo fmt --check
|
||||
cargo check -p dever-core -p dever-runtime -p dever-cli
|
||||
cargo test -p dever-tests --test syntax_and_format
|
||||
cargo test -p dever-tests --test package_resolution
|
||||
cargo test -p dever-tests --test type_checking
|
||||
cargo test -p dever-tests --test clause_analysis
|
||||
cargo test -p dever-tests --test value_semantics
|
||||
cargo test -p dever-tests --test collections
|
||||
cargo test -p dever-tests --test numbers
|
||||
cargo test -p dever-tests --test failures
|
||||
cargo test -p dever-tests --test native
|
||||
cargo test -p dever-tests --test differential
|
||||
cargo test -p dever-tests --test cli
|
||||
python3 ./.trellis/scripts/task.py validate 09-04-dever-language-mvp
|
||||
git diff --check
|
||||
```
|
||||
|
||||
The performance test is an explicit, separately announced gate and is not part of the default test list. Do not substitute `cargo test --workspace`, `npm run build` or service/integration tests. If a focused check reveals a shared compiler defect, fix the owning implementation once and rerun only affected targets.
|
||||
|
||||
## Finalization
|
||||
|
||||
- [ ] Run `trellis-check` after implementation.
|
||||
- [ ] Update canonical Trellis specs for the new crate ownership and language rules.
|
||||
- [ ] Review the final diff against PRD scope and remove accidental abstractions.
|
||||
- [ ] Do not commit until the user explicitly authorizes a commit.
|
||||
- [x] Confirm there are no obsolete planning children to archive.
|
||||
# Active Compiler Contract Checklist (2026-09-08)
|
||||
|
||||
- [x] Contract syntax, formatter and semantic metadata.
|
||||
- [x] Field privacy, numeric facts, construction/write/output constraints.
|
||||
- [x] Failure obligations and explicit recovery, including nested values and static handlers.
|
||||
- [x] Transitive effects, package dependencies and API snapshot/CLI enforcement.
|
||||
- [x] Evidence-backed redundancy diagnostics and application export analysis.
|
||||
- [x] Official source/examples migration, targeted tests, native equivalence, docs/specs and final review.
|
||||
|
||||
User approved the full contract implementation. Complete the list before claiming delivery. Keep earlier evidence below as historical; no full test suite, external services, distribution work or commit.
|
||||
|
||||
## Compiler Contract Evidence (2026-09-08)
|
||||
|
||||
- Implemented private record fields, normalized Int/Decimal field/payload/output/handler bounds, explicit error/recover and pure/depends. HIR facts reuse existing clause domains; handler boundaries support safe variance and concrete output inference without forcing wrapper annotations.
|
||||
- Failure obligations follow copies, nested fields, calls and collections. Official Failed variants are explicitly marked; HTTP transport preserves earlier failure state and returns the inspected result with its stop decision. The Stream example now propagates a CountResult failure instead of silently returning zero. Presentation/test recovery reasons are explicit and consistent across clauses.
|
||||
- Effects and recovery policies propagate through invoked static handlers. API generation is create-new; check/run/build compare an existing baseline. Adding a private recovering helper changes the effective public snapshot without exposing that helper's name. Depends includes normalized system resource types. W001 is reused; W002–W005 and entry-scoped W007 are advisory, not arbitrary abstraction requirements.
|
||||
- Final six contract targets passed 47 tests: syntax 4, facts 16, semantics 10, API 9, redundancy 6, execution 2. Existing core semantics passed 16 (15 in the first run, W001 assertion narrowed to its diagnostic then rerun); existing syntax passed 22, formatter passed 11 and the new contracts example roundtrip passed. The independent expected-output core differential case passed. Forty-one migrated source fixtures were checked without executing their network/resource scenarios; the temporary probe was removed.
|
||||
- Actual CLI api/check/run/build and standalone execution with `env -i PATH=/nonexistent` passed. A temporary source's new exposure was rejected by its unchanged baseline. `examples/contracts/src/dever.api` records the example's contract. Strict installed-driver Clippy/type checks passed for core/CLI and focused contract tests; formatting and explicit whitespace checks cover untracked files as well.
|
||||
- Independent review found and closed empty-reduce seed consumption, primitive resource dependency omission, and exponential/deep proof graphs. Added positive/negative regressions; immutable shared fact/value graphs preserve aliases, proof work is capped at 16,384 and iterative nominal depth validation caps 128 before recursive analysis. Exhaustion reports C015; no incomplete proof becomes a successful Program.
|
||||
- Updated LANGUAGE.md, IMPLEMENTATION.md, README and the owning compiler-contract spec. No database/distribution expansion, full suite, integration environment, existing service, global installation or Git commit. The umbrella task stays active for its previously deferred roadmap; this approved contract extension is complete.
|
||||
|
||||
## Direct Example Roots And Coverage (2026-09-08)
|
||||
|
||||
- Moved all five original source roots from `examples/<name>/src` to `examples/<name>`, including the unchanged contracts API baseline. Removed empty src directories; package-relative nesting, such as hello/app/user.dever, remains. Updated executable test references, current guides and owning specs; earlier dated evidence retains its historical paths.
|
||||
- Added sequences, text, privacy, parallel and system examples, bringing runnable roots to ten. Added six separately checkable rejected roots for C006/C009/C011/C012/C013/C014. The examples index documents commands, outputs, nondeterministic ordering, runtime input paths and explicit recovery boundaries.
|
||||
- Reused compiler/check/native APIs in one example runner. Automatic discovery checks every runnable root and any baseline; formatter coverage discovers all examples, including rejection fixtures. No compiler or runtime behavior changed.
|
||||
- Passed seven example-target tests covering all ten successful roots, nine native executions and six rejection cases; the existing core native test separately verified its 22 expected outputs. The targeted formatter roundtrip passed over every official/example source. Actual CLI contract check and expected C012 rejection passed; example fmt --check passed. Strict Clippy/type checks compiled all affected test targets, including feature-gated differential references.
|
||||
- No full suite, network/service integration, compiler feature expansion, global installation, commit or archive.
|
||||
|
||||
## Isolated PostgreSQL And Dual-source CMS Measurements (2026-09-18)
|
||||
|
||||
- In a nonprivileged, owned PostgreSQL 16 instance with a private Unix socket and no TCP listener, the ignored `postgres_orm_uses_the_configured_isolated_database` test passed 1/1. Its shared schema cleanup left no test schemas. Added a focused live named-migration probe for bound before/after SQL, atomic rollback on after failure, successful DDL and once-only re-execution. Test connection came only from a temporary root `config/setting.json`; no database URL environment variable or existing PostgreSQL service was used. After verification, the temporary setting was deleted, the owned instance stopped and its test data removed.
|
||||
- Focused `cms-profiles` build compiles both current `examples/cms/{dever,md}` source formats using one shared benchmark entry and separately builds base/SQLite/PostgreSQL/both runtime profiles. Artifacts: `target/performance/cms-dual-build-09-18-v2/manifest.json` and `profile-report.json`. Profile bytes: 411,352 / 2,558,200 / 2,708,112 / 4,672,888. CMS Dever/Markdown bytes: 3,151,352 / 3,151,416.
|
||||
- `target/performance/cms-dual-rss-09-18/report.json` completed all six runs (three per source, READY=3 throughout). Dever/Markdown median readiness 19.87/19.69 ms, idle RSS 5.37/5.37 MiB, PSS 3.28/3.33 MiB, VmHWM 5.37/5.37 MiB. This is warm-cache initialization and bounded idle sampling, not throughput. No hard 64/128 MiB CMS budget or cgroup peak: the local controller is not writable. No broad/full suite, existing service check, or global installation.
|
||||
- Benchmark runner unit tests pass 40/40; focused test compiled with `--features postgres`; Trellis task context validation passed. Rustfmt and Clippy are unavailable in the installed toolchain. This root roadmap remains in progress; API stays deferred pending its redesign, and hard-budget CMS stress requires a delegated cgroup environment.
|
||||
|
||||
# Source Visibility And Module API Implementation (2026-09-18)
|
||||
|
||||
- Replaced `package/exposes` syntax with path-derived package identity and explicit `public` for cross-package type/function visibility; fixed private `main.main` as the only run/build entry. Updated bundled sources, CMS Dever/Markdown roots, old runnable examples and Markdown metadata. The hello example now delegates through a public library function to its own `main.dever`.
|
||||
- Added statically checked module `api/` routes with GET/POST/DELETE naming, recursive paths, private handlers and one `response` output. `dever.api.serve()` opts the application into routing and the existing bounded HTTP engine; typed inputs, JSON serialization and `{code,message,data}` envelopes reuse a single runtime adapter. Listener settings are read from `config/setting.json`, not environment variables; no CMS business API or authentication policy was added.
|
||||
- Focused checks: core/CLI/runtime/tests cargo check passed; `source_visibility` 10/10, `syntax_and_format` 22/22, `core_semantics` 16/16, `formatter` 11/11 and `markdown_source` 20/20 passed. `api_routes` passed 7/7 before the final test adjustment, then its application-mode native compilation passed 1/1 with config bootstrap and no listener. An isolated temporary-project CLI `check/run/build` and API-baseline rejection test passed. Maintained examples, CMS Dever/Markdown source parity and rejection fixtures passed selected contract tests. Two ORM fixture static-check tests passed without database connections. `deverc check` passed for hello and both CMS formats (CMS retains W001 unused-write warnings).
|
||||
- Not run: full suite, live HTTP/API service check, real PostgreSQL, CMS runtime/build or benchmarks. Rustfmt and Clippy binaries are unavailable in the installed toolchain. The umbrella task remains in progress for separately deferred roadmap work; historical entries above retain their original date/context.
|
||||
|
||||
# AI-Oriented Source Architecture Implementation (2026-09-19, Complete)
|
||||
|
||||
- [x] Add one shared source-role classifier and project-layout validation.
|
||||
- [x] Replace application `public` visibility with automatic App capabilities and logical App aliases.
|
||||
- [x] Enforce role dependency direction, API non-callability and Model-operation ownership.
|
||||
- [x] Migrate the Dever and Markdown CMS sources from `service/` to component/domain roles without function-per-file fragmentation.
|
||||
- [x] Update the language, Markdown and backend compiler/database contracts.
|
||||
- [x] Add focused layout, visibility, API, Model and CMS parity tests; run only the affected checks.
|
||||
|
||||
The implementation does not add environment variables, implicit HTTP startup, authentication policy, a new Port declaration syntax, or backward compatibility for the superseded application layout.
|
||||
|
||||
## AI-Oriented Source Architecture Evidence (2026-09-19)
|
||||
|
||||
- `SourceLayout` is the single main/component/domain/role/topic classifier. Strict project loading rejects loose application paths, generic buckets, role file/directory conflicts, nested non-API topics and one-file role directories. The check cache includes strict-layout identity; in-memory compiler fragments remain isolated from project-layout enforcement and cannot weaken CLI projects.
|
||||
- App declarations receive stable `<component>.<domain>.<name>` identities without exposing topic filenames. Role-aware lookup enforces Main/API/App/private-role direction, API non-callability and owning-domain Model operations. App signatures and inferred failures reject private type leakage. Port remains a reserved, rejected declaration role.
|
||||
- Plain and Markdown CMS now contain only `main`, `user/account/{app,domain,model}` and `news/article/{app,model}`. Both forms have equal normalized declarations, Model/API snapshots and settings. Current examples contain no package/exposes/public syntax, old service/model roots or environment-variable configuration.
|
||||
- The current performance packager now stages `benchmark/<domain>/app.dever` plus generated `main.dever`; it no longer generates package/exposes headers or passes arbitrary entries to `deverc build`. ORM, profile, Dever CMS and Markdown CMS staged projects all passed actual CLI check. The CLI CMS regression test compiles against the fixed main-only interface and uses a test-owned App probe instead of injecting a loose root source.
|
||||
- Focused verification passed: core/runtime/CLI Cargo check; `source_architecture` 8/8; `source_visibility` 10/10; `orm_performance_fixture` 3/3; `concurrency` 5/5 with its explicit benchmark ignored; CMS source/config parity 1/1; archived parallel and source-root native regressions passed after the synchronous typed-error fix. Earlier in this same phase `api_routes` passed 7/7. Actual CLI `check` and `fmt --check` passed for both CMS formats, and Python syntax checking passed for the performance builder.
|
||||
- Not run: full workspace suite, live CMS `run/build`, `cms_project` integration execution, HTTP listener, real PostgreSQL, performance/size/RSS builds or 64/128 MiB stress. Rustfmt and Clippy components remain unavailable. The umbrella language roadmap stays in progress for separately deferred work.
|
||||
@@ -0,0 +1,990 @@
|
||||
# Dever Language Definition
|
||||
|
||||
## N5:HTTP/2(已完成)
|
||||
|
||||
用户在 P2 性能验证结束后批准继续接入 HTTP/2。使用 Hyper 实现 buffered/live 服务端和 single-use/pooled 客户端;复用既有请求/响应、TLS、AsyncStream 与 SSE 接口。Limits.http2 显式配置协议和每连接流数、接收窗口,TLS 必须协商 h2,明文使用 prior knowledge。每流取消隔离,Hyper 内部任务保留 Dever Scope,GOAWAY 排空不自动重试已发请求。详细验收以 `../09-12-http2/prd.md` 为准。
|
||||
|
||||
N5 已由 88 项定向测试、原生执行和独立审查验收。后续 HTTP/2 性能矩阵与有界稳态/恢复压测已由子任务完成;小时级稳定性、编译器发行/跨平台、自举及其余路线图仍未完成。
|
||||
|
||||
仅定向协议、生命周期与原生桥接验证;不重跑 P1/P2 性能矩阵,不改根任务调度,不接 RFC 8441、h2c Upgrade、推送、trailer、数据库或发行工具。下文各轮排除范围仅约束相应历史阶段。
|
||||
|
||||
## 已完成阶段 N4:并发组合与可复用网络客户端(2026-09-12)
|
||||
|
||||
用户批准完成上一轮清单的 1 和 2。交付源码运行参数、静态 HTTP handler 的类型化上下文、任务超时/多路竞争等待、周期与 Channel 流、异步内存序列遍历;有界 HTTP 连接池、域名、流式请求/响应、HTTPS/WSS 客户端和 TLS 服务端。保留 N3 SSE/WS 会话、取消和背压契约。HTTP/2、数据库、协议扩展和分发工具不属于本轮。
|
||||
|
||||
任务、连接及正文队列有界;取消和关闭回收所属工作,已开始的阻塞工作必须排空。复用 Tokio、Hyper、tungstenite 和 Rustls,不维护兼容接口或自写协议栈。只运行定向编译/测试及自有 loopback 随机端口,不测旧性能基线,不启动现有服务,不提交。
|
||||
|
||||
以上范围已接通 checked source、原生编译和运行时。83 项定向用例、实际 CLI check/fmt/build 与无 Rust 工具链环境中的独立后端示例通过;具体证据见 implement.md 的 N4 Evidence,公开用法以 LANGUAGE.md 为准。
|
||||
|
||||
## 已完成阶段 N3:流式响应、SSE 与 WebSocket(2026-09-12)
|
||||
|
||||
用户已授权“做下一阶段”,沿用新语言直接演进和低内存运行目标。保留普通 HTTP 的直接 handler 路径,增加 `serve_live` 和 HttpReply:同端口处理完整响应、逐块正文、SSE 和 WebSocket。HTTP 请求仍有界缓冲;响应通道只有 1 个槽位,长连接配置与普通请求期限分开。
|
||||
|
||||
WebSocket 服务端/客户端复用 tokio-tungstenite 0.30.0(handshake feature),提供 Text/Binary/Ping/Pong、AsyncStream 消息消费和关闭握手。SSE 提供字段编码、Last-Event-ID 访问和空闲注释心跳,历史重放归应用所有。HttpReply/WebSocket 进入编译器资源、类型、effects、API、Markdown 和 native 契约;不引入新语法、旧 API 兼容或自写 WebSocket 协议栈。
|
||||
|
||||
连接、handler 及升级后会话共用 Scope/Group 上限与取消排空;等待写锁时取消不能破坏另一任务的帧。仅执行根 test/ 下的定向编译器/运行时验证和自有回环端口,不测试旧性能基线、常驻示例或已有服务。TLS/WSS、HTTP/2、客户端池、子协议/压缩扩展、关闭帧元数据和数据库不属于 N3。
|
||||
|
||||
## 前一阶段 N2:HTTP 引擎(2026-09-12,已完成)
|
||||
|
||||
用户在 N1 完成后批准继续。采用 Hyper 1.x HTTP/1 引擎、hyper-util TokioIo/Timer 和共享 bytes 缓冲区;不额外引入路由框架。此阶段取代历史“HTTP 全部由 Dever 自写”的实现决定。官方类型与静态业务 handler 仍由 Dever 定义,不保留旧协议 API 或备用解析器。
|
||||
|
||||
- `serve(async handler, Listener, Limits) -> ()`:持久连接、流水线、chunked 输入,复用现有有界任务组、背压、超时和取消清理。accept/配置/程序故障沿任务传播,对端协议错误只结束对应连接。
|
||||
- `send(address, port, Request, Limits) -> ResponseResult`:单次请求,无客户端池和重试,driver 与请求同生命周期。
|
||||
- Header 列表保留重复头和字节值;消息体在显式上限内缓冲,单帧共享,多帧增量合并。
|
||||
- 直接迁移示例、检查器、native bridge 和测试。只用离线定向检查、自有 loopback 随机端口,不测旧基线、不跑全量或现有服务。
|
||||
- TLS、HTTP/2、流式响应、客户端池、非空 trailer、WebSocket/SSE 留待后续;N3 优先处理长连接协议。
|
||||
|
||||
## 前一阶段 N1:异步 Stream 与 TCP(2026-09-12,已完成)
|
||||
|
||||
用户批准继续,并明确这是全新的语言:无需旧源码兼容,不增加兼容别名、回退实现或推测性的防御分支。仓库调用方直接迁移。此决定取代下文历史阶段中的“网络暂停”和“兼容基线”要求。
|
||||
|
||||
- 增加 `AsyncStream<Item>`,支持在 async function 中按需 `each`、`reduce`、`reduce_until`,以及有界 `parallel_each`;handler 可为 async,关闭/提前结束释放生产端。
|
||||
- `dever.net` 直接采用 Tokio 异步 TCP;connect、listen、accept、read、write 为 async。资源名称仍为 Socket、Listener;无 sync/aio 两套 API。
|
||||
- 连接流和字节流不预取;并发消费先等待容量再拉取。复用现有结构化 Task/Group,停止后等待子任务清理,连接支持同时读写。
|
||||
- 保留协议必须的输入约束、失败输出、超时、关闭和取消语义;写入中断不得自动重发已写字节。
|
||||
- 现有 HTTP 传输调用链随 TCP 改为 async;成熟 HTTP 引擎接入属于 N2,WebSocket/SSE 属于 N3,本轮不实施。
|
||||
- 只做根 test/ 下定向检查及自己创建的 loopback 随机端口验证;不测旧性能基线,不运行全量测试、业务服务、全量 build 或全局安装。
|
||||
|
||||
## 前一阶段:并发基础(2026-09-12,已完成)
|
||||
|
||||
前一阶段先完成同步、异步和多线程(含协程/任务)基础,网络当时暂停;当前 N1 恢复异步 Stream/TCP。下述并发契约已经进入编译器前端、HIR、原生后端和 runtime;最终状态以本任务的定向验证和 `LANGUAGE.md` 公开契约为准。不测旧实现性能基线。
|
||||
|
||||
### 暂存的网络方案
|
||||
|
||||
- 后续需要 TCP、HTTP、WebSocket、SSE 长连接,复用成熟 Rust 库。
|
||||
- 候选栈:Tokio 统一网络调度,Hyper/hyper-util 处理 HTTP,Axum 复用服务路由、升级和 SSE,WebSocket 复用其 tungstenite 生态,bytes 管理共享缓冲区。实施前核对版本、工具链和 feature 兼容性。
|
||||
- 共用连接限额、有界队列、背压、超时、取消与关闭。长连接保活独立于普通请求超时;SSE 事件历史保存/重放属于应用责任。
|
||||
- 不在每次 I/O 上 block_on,也不把同步阻塞 handler 直接放入异步调度线程。HTTPS/WSS、HTTP/2 的首轮范围尚未确定。
|
||||
- 取消旧性能基线工作,不取消新能力必要的定向正确性验证;不启动业务服务或压测。
|
||||
|
||||
### 并发语言契约(已批准实施)
|
||||
|
||||
#### Goal
|
||||
|
||||
增加可明确推理的同步、异步协程和多线程能力,为 TCP、HTTP、WebSocket 与 SSE 提供统一运行基础。小机器只运行打包后的二进制;空闲任务不占用一个系统线程,任务、线程和队列都有明确上限。契约可以直接演进,维护值/资源语义的清晰性,不承担旧源码兼容义务。
|
||||
|
||||
#### In Scope
|
||||
|
||||
- 普通 function 保持同步;`async` 声明异步 function,`await` 等待异步调用或已启动任务。
|
||||
- `run` 启动异步调用并返回受限 Task;`stop` 采用“请求协作取消并等待清理完成”的安全语义,而不是仅发送信号。
|
||||
- 每个 async function 是默认结构化任务域;动态数量的零输出任务可由有界 `group` 统一拥有、等待和停止。
|
||||
- `parallel` 将 pure 同步计算交给有界多线程执行;`blocking` 供明确的阻塞边界使用。`parallel_each` 按序列类型复用相应的有界执行器。
|
||||
- 有界 `channel` 以及 `send`、`receive`、`close` 用于任务通信;禁止无界队列。
|
||||
- async 静态 handler、跨线程可传递性、任务消费、effects/failures、API 快照、Markdown 契约、格式化和原生代码生成均由编译器检查。
|
||||
- 运行时复用 Tokio 的协程与多线程调度;整个程序最多建立一个异步运行时,CPU/阻塞任务使用受限执行通道。
|
||||
|
||||
#### Out of Scope
|
||||
|
||||
- 本阶段不实现 TCP、HTTP、WebSocket、SSE、TLS 或数据库;网络方案按上节暂存。
|
||||
- 不加入裸线程、共享可变全局对象、用户锁、分离后无人管理的后台任务、无界 channel、强杀线程或副作用回滚。
|
||||
- 不同时加入 lambda、闭包、一等 function、用户泛型、用户递归、循环块或异常机制。
|
||||
- 同步 `Stream<Item>` 保持当前阻塞拉取契约;异步流在网络恢复前单独设计,不做隐式转换。
|
||||
|
||||
#### Acceptance Criteria
|
||||
|
||||
1. 完全同步的入口不启动 Tokio runtime;接口发生变化时直接迁移仓库源码。
|
||||
2. async function 和 async 静态 handler 的调用都必须直接位于 `await(...)` 或 `run(...)` 上下文;同步 function 中的异步调用在原生构建前拒绝。
|
||||
3. `await(call(...))` 顺序执行并保持原函数的命名输出;`task = run(call(...))` 先启动,`await(task)` 恰好消费一次任务并取得相同输出。
|
||||
4. Task 不能复制、存入 record/List/Map/Stream、作为普通参数/输出逃逸、重复等待或在 function 返回时仍未消费;必须 `await` 或 `stop`。
|
||||
5. `stop(...)` 第一阶段只接受零输出 Task 或 Group,协作取消并等待清理;已发生的副作用不回滚,长时间同步计算不承诺立即停止。
|
||||
6. `group(limit)` 的 limit 必须为正且有实现上限;只拥有零输出异步任务。容量已满时 `run(group, call(...))` 施加背压,不无限排队;`await(group)` 或 `stop(group)` 消费该 Group。
|
||||
7. `parallel(call(...))` 只接受 pure 同步 function,参数和输出必须可跨线程传递;`blocking(call(...))` 只接受编译器传递 effect 分析确认包含阻塞系统边界的同步调用。二者第一阶段只能用于 async function,并使用明确的有界容量;同步代码继续使用现有 `parallel_each`。
|
||||
8. `channel(Type, capacity)` 容量必须为正且有实现上限;send 在满时等待,receive 在空时等待并返回 `Item?`(值表示 Item,`null` 表示 Closed),close 唤醒等待方;调度器或 Channel 内部故障作为带源码位置的 fatal error 传播。
|
||||
9. async handler 的同步/异步属性是签名的一部分;所有同签名分句必须一致,专门化和递归检查不能因异步边界失效。
|
||||
10. 任务启动、等待、停止、channel、时间等待和 blocking 均进入传递 effect 分析;pure function 不能隐藏这些效果,失败义务不能因任务边界被吞掉。
|
||||
11. 异步入口只创建一次运行时;多个挂起任务不按任务创建线程。工作线程、阻塞线程、group、channel 与待处理任务均有保守默认上限及显式配置边界。
|
||||
12. 仅运行根 `test/` 下针对新增语法、检查、原生执行、取消/关闭和有界调度的离线定向测试;不跑全量测试、服务测试、旧实现基线或网络压测。
|
||||
|
||||
#### Key Naming Decisions
|
||||
|
||||
- 保留 `async`、`await`、`parallel`、`blocking`、`channel`、`send`、`receive`、`close`。
|
||||
- 使用 `run` 代替 spawn,使用 `stop` 代替 cancel,使用 `group` 表示动态任务所有者;不再增加 join,统一由 `await` 等待。任务操作沿用函数式调用外观,不提供第二套前缀语法。
|
||||
- 协程是 async Task 的运行时实现,不增加 coroutine 关键字。
|
||||
|
||||
## Markdown Source Follow-through (2026-09-09)
|
||||
|
||||
用户批准保留 `.dever`,新增 `.dever.md` 源码容器,并进一步要求编译器强制说明与代码一致。顶层 `dever` 或 `typescript dever` 围栏内写正常 Dever 声明,共用原有语法、契约、API 和原生路径。一个 H1 说明 package;每个 H2 只说明一个 type 或一个 `(函数名, 参数数量)` 及其全部分句。编译器核对 package 名、公开类型/方法/使用方式、类型字段/分支、函数输入输出的名称、类型、数量和顺序,空项显式写 `无`。`typescript dever` 的首个标记供编辑器尝试 TypeScript 语法高亮。跨格式同包重复拒绝;格式化保留说明,诊断定位原文并关联代码。此决定替代下方历史阶段“只加载 `.dever` 文件”及“标题说明无约束”的范围限制,不开放其它语言或 HIR/JSON 作为源码。正式写法见 `LANGUAGE.md` 的 Markdown 小节。
|
||||
|
||||
## Approved Performance Follow-through (2026-09-08)
|
||||
|
||||
用户批准实施本轮性能方案。保持现有语法、值/资源语义、错误位置、数值顺序和编译器契约。交付类型属性缓存、依赖驱动契约分析、记录更新复制消除、独占列表消费、直接消费字符列表的遍历优化、HTTP 增量扫描、标准库及原生产物缓存。循环融合必须证明副作用和失败顺序等价;并发分批以有限测量为依据,不要求线程池。补编译/运行/内存定向基准并记录优化前后证据。只运行离线定向测试、自有临时文件/进程和内存协议输入,不运行全量或服务压测,不提交或安装全局命令。
|
||||
|
||||
## Current Follow-through (2026-09-07)
|
||||
|
||||
用户在剩余项盘点后要求“实施剩下的”。继续完成已确定语言的工具、标准库和验证工作,并推进后续运行能力;既有语法、分句、静态 handler、值/资源语义保持兼容。下方历史里程碑的暂缓项不阻止本次明确要求的工作。
|
||||
|
||||
- 提供 `.dever` 的规范格式化及 CLI `fmt`/只读检查,保留注释、表达式含义和求值顺序;任一输入语法错误时不改写文件。
|
||||
- 补常用 Text、数值解析/格式化、进程参数/环境和时钟接口。公开接口与组合逻辑仍由普通 `.dever` package 定义。
|
||||
- 实现仅用于验证的 HIR 基准解释器,覆盖已实现核心语义并与原生结果、故障位置对照;生产 build/run 始终使用原生编译。
|
||||
- 实现保持值语义的最后使用优化,提供可复现、有限工作量的同语义性能基线,不对现有服务压测。
|
||||
- 继续推进 JSON、HTTP 与受控并发等官方包所需能力;协议与应用逻辑使用 Dever 基础语法,系统边界保持最小。
|
||||
- 数据库引擎此前未定,已向用户异步询问;这一选择不阻塞其余工作。
|
||||
- 编译器发行、跨平台沿用此前暂缓安排;自举仍是尚未交付的长期项。本次不安装或替换全局命令,不提交,不访问既有服务。
|
||||
|
||||
验收按每项真实完成的行为和定向证据记录,不将已完成的基础语法测试当作新增工具和库的验收。
|
||||
|
||||
## Goal
|
||||
|
||||
当前目标是实现已经确定的基础语言,使官方 package 与应用能够用同一套 `.dever` 语法编写。2026-09-07 用户批准实现基础类型、表达式、函数输出、分句、赋值和值语义、集合与处理函数、统一 package 编译及最小系统接口。原生 Hello World 里程碑已于 2026-09-06 完成,作为回归基线。
|
||||
|
||||
长期目标仍是改善 AI 开发中的硬编码、重复实现、无依据兜底和大项目上下文问题。表面语法保留 package、type、function、分句和值语义;用户所说的“用户类”用已有 `type User` 表达,不引入 class 或继承。Rust 等引导技术不进入用户源码或语言兼容契约。
|
||||
|
||||
基础阶段曾将 HTTP、JSON 和性能验证后移;当前 Follow-through 已推进这些能力。编译器发行与跨平台仍暂缓,数据库引擎未定;用户 CRUD 示例不是基础语言的额外交付。保留原生执行方向和既有表面语法,不增加契约 DSL。
|
||||
|
||||
## Approved Core Implementation
|
||||
|
||||
- 沿用既定条件分句、线性 body 和集合函数;不再把循环语法作为待确认项,不增加条件块、循环块或用户递归。
|
||||
- 每项语言能力贯通源码检查、typed HIR 与原生执行;不能以 AST 已解析代替支持。
|
||||
- 官方 `.dever` package 与本地 package 共用语言规则。官方命名空间由编译器随附源码提供,本地源码不能冒充官方来源。
|
||||
- 系统接口提供 Bytes、opaque 文件/TCP 资源、读写和显式关闭;普通值保持值语义,资源别名标识同一外部资源,关闭后操作得到显式失败。
|
||||
- 可恢复系统错误以官方源码声明的选择型结果返回;程序故障保持源码定位。系统原语不包含 HTTP 路由或应用业务。
|
||||
- 验收覆盖完整语言样例、负例诊断、分句顺序变化、集合顺序与值语义,以及隔离临时文件和本地回环连接。使用必要的最小定向检查,不运行全量测试、既有服务或压测。
|
||||
|
||||
## Approved Foundation Extension
|
||||
|
||||
Status: implemented and verified on 2026-09-07.
|
||||
|
||||
### Goal And Scope
|
||||
|
||||
补齐官方 `.dever` package 编写协议解析、持续 I/O 组合和宿主回调所需的最小表达能力,同时保留分句条件、线性 body、无循环 block 和无用户递归的长期规则。本阶段一次完成 `reduce`、`reduce_until`、Bytes 遍历、`Stream<Item>`、受限静态 handler 参数,以及文件/TCP 的流式包装;不在 runtime 中加入 HTTP 或业务特例。
|
||||
|
||||
### Sequence Operations
|
||||
|
||||
- 带状态遍历对外名称固定为 `reduce`;此前讨论中的 `fold` 和 `accumulate` 名称作废。
|
||||
- `reduce(handler, sequence, initial_state)` 固定从左到右执行,始终显式提供初始状态;空序列直接返回初始状态。
|
||||
- handler 依次接收当前元素和上一步状态,必须输出一个与状态类型相同的下一步状态:
|
||||
|
||||
```dever
|
||||
add(value: Int, total: Int) (next_total: Int) {
|
||||
next_total = total + value
|
||||
}
|
||||
|
||||
total(values: List<Int>) (result: Int) {
|
||||
result = reduce(add, values, 0)
|
||||
}
|
||||
```
|
||||
|
||||
- `reduce_until(handler, sequence, initial_state)` 使用相同顺序,但 handler 必须有两个输出:第一项是下一步状态,第二项必须命名为 `stop` 且类型为 Bool。处理完当前元素后,`stop` 为 true 就立即返回,不再请求下一个元素。
|
||||
- `reduce` 和 `reduce_until` 不提供额外 context 参数;共享配置应组合进状态,避免同一调用同时维护两套跨元素数据。
|
||||
- sequence 只接受 `List<Item>`、Bytes 或 `Stream<Item>`。Bytes 的元素静态类型为 Int,运行时值保证在 0 至 255,不先复制为 `List<Int>`。Text 如需按 UTF-8 遍历,必须显式使用 `dever.bytes.from_text`。
|
||||
- `each(List/Bytes)` 保留零输出动作和单输出 List 映射;`each(Stream)` 只接受零输出 handler,不把未知长度或无限输出隐式收集到内存。Stream 的最终状态由 `reduce`/`reduce_until` 返回。
|
||||
- `filter`、`find`、`sum` 本阶段仍只处理 List;不增加 Stream 到 Stream 的惰性 map/filter 管道。
|
||||
|
||||
### Static Handler Inputs
|
||||
|
||||
function 输入可以声明受限 handler 签名:
|
||||
|
||||
```dever
|
||||
serve(
|
||||
route: handler(request: Request) (response: Response),
|
||||
config: Config
|
||||
) (result: ServeResult) {
|
||||
result = serve_with(route, config)
|
||||
}
|
||||
```
|
||||
|
||||
- handler 类型只允许出现在 function 输入中;输入按位置匹配类型,命名输出同时匹配名称、顺序和类型。
|
||||
- 调用方只能传入签名匹配的具名 function,或转发当前 function 的 handler 参数。
|
||||
- handler 参数可以直接调用,也可以传给 `each`、`reduce`、`reduce_until` 或另一个 handler 输入;不能参与分句匹配,不能赋给局部值、存入 record/List/Map/Stream、比较或作为输出返回。
|
||||
- handler 不是运行时值。typed HIR 保留静态绑定,AOT 以 function 和实际 handler 绑定组成专门化实例,生成直接调用;不产生函数指针、闭包、虚调用或反射注册表。
|
||||
- 递归检查覆盖 handler 调用与转发后的专门化调用图,不能通过 handler 绕过无递归规则。
|
||||
|
||||
### Stream And Resource Contract
|
||||
|
||||
- `Stream<Item>` 是编译器提供的唯一新增标准泛型类型,用户仍不能声明泛型 type 或泛型 function。
|
||||
- Stream 是拉取式、顺序、一次消费的 opaque 资源;复制 Stream 只产生同一资源的别名,所有别名共享读取位置、结束状态和显式关闭状态。Stream 不可比较,也不能成为 Map key。
|
||||
- `reduce_until` 提前停止时 Stream 保持可用,调用方可从下一个未消费元素继续处理。正常耗尽后继续消费只得到结束,不会重新执行生产者。
|
||||
- 正常 EOF 使用 Stream 自然结束表示,不作为普通元素。可恢复 I/O 错误必须作为官方 choice 的 `Failed(message: Text)` 元素交给 handler;终止性错误产生一个 Failed 后结束 Stream,不能转换成默认值或程序故障。
|
||||
- 流式读取使用 `dever.io.ReadEvent`,其分支固定为 `Chunk(bytes: Bytes)` 和 `Failed(message: Text)`;现有单次 `read` 继续返回 `ReadResult.Read/End/Failed`,两种接口不混用结束语义。
|
||||
- 流创建结果固定为 `dever.io.ReadStreamResult`,其分支为 `Streaming(stream: Stream<ReadEvent>)` 和 `Failed(message: Text)`。`dever.io.chunks(file, limit)` 与 `dever.net.chunks(socket, limit)` 都返回该类型;非正数、无法表示的 limit 或创建时已经关闭的源立即返回 Failed。
|
||||
- `dever.net.connections(listener)` 直接产生 `Stream<ConnectResult>`;创建后关闭 listener 或终止性 accept 错误产生一个 `ConnectResult.Failed` 后结束。
|
||||
- 核心操作 `close(stream)` 没有输出并且幂等。它停止该 Stream 及其别名并释放 Stream 持有的底层资源引用,但不主动关闭调用方仍单独持有的 File、Socket 或 Listener;关闭后的 Stream 与正常耗尽一样不再产生元素。调用方先关闭底层资源时,依赖它的未关闭 Stream 产生一个 Failed 后结束;最后一个资源别名离开作用域时仍由原生资源析构兜底。
|
||||
- 首阶段只有阻塞、顺序执行;Socket 延续显式 timeout。没有预取、后台线程、async、await、并发消费或共享可变业务全局状态。
|
||||
|
||||
### Acceptance Criteria
|
||||
|
||||
1. List 和 Bytes 的 `reduce` 按源顺序传递状态,空序列返回初始状态;Bytes 不经过中间 List。
|
||||
2. `reduce_until` 在 stop 元素之后不调用 handler 或拉取 Stream;同一 Stream 随后从未消费位置继续。
|
||||
3. `each(Stream)` 接受零输出 handler,拒绝单输出或多输出 handler;List/Bytes 的既有映射和动作语义不回归。
|
||||
4. handler 输入支持具名 function、跨 package function 和多层静态转发;签名不匹配、存储、返回、比较和 handler 间接递归均在原生构建前拒绝。
|
||||
5. 生成程序中的 handler 是专门化直接调用;不引入通用 runtime Value、运行时函数指针或逐元素虚拟 handler 分派。
|
||||
6. Stream 别名共享游标、结束和关闭状态;自然 EOF、提前停止、幂等 `close`、底层关闭与终止性错误均有确定测试。
|
||||
7. 官方 `dever.io`/`dever.net` 流式接口作为普通 `.dever` 源码经过同一 parser、resolver、checker 和 HIR;runtime 只拥有系统读取和 Stream 拉取原语。
|
||||
8. 文件验证只使用测试自有临时目录,TCP 验证只使用 `127.0.0.1` 随机端口、有限数据和超时;不连接、启动或修改现有服务。
|
||||
9. 实际 `check`、`run`、`build` 与独立原生程序覆盖一个分块状态解析样例,证明结果来自 `.dever` handler 和状态,而非编译器特判。
|
||||
|
||||
### Out Of Scope
|
||||
|
||||
- HTTP、JSON、CRUD、数据库、并发服务器和异步语法;本阶段交付的是这些 package 可复用的底层表达能力。
|
||||
- 一般化用户泛型、lambda、闭包、一等 function、Stream 惰性转换、循环 block、用户递归和异常机制。
|
||||
- formatter、语义基准解释器、性能门槛、自举、package 分发、跨平台构建和全局命令迁移。
|
||||
|
||||
### Known Risks And Controls
|
||||
|
||||
- 静态 handler 转发可能产生重复原生实例;专门化键按 function 与完整 handler 绑定去重,并且只生成入口可达实例,不退化为运行时分派。
|
||||
- Stream 的内部生产者调用有固定边界成本;文件和 Socket 以 Bytes chunk 为单位拉取,不按单字节跨越动态边界,有限 List/Bytes 热路径仍是直接循环。
|
||||
- 首阶段的阻塞 Stream 不能承担并发服务器;这是明确范围限制,不能在 HTTP package 中用隐藏线程或全局队列规避。
|
||||
- 把 I/O 失败作为最后一个元素要求 handler 穷尽处理官方 choice;类型检查和终止状态测试共同防止错误被静默丢弃或无限重复。
|
||||
|
||||
## Completed Hello Milestone
|
||||
|
||||
- 示例位于 `examples/dever/hello/app/user.dever`,与 `package app.user` 路径一致。
|
||||
- 支持 Text 字面量、Text 参数、局部赋值、普通零输出函数调用和公开零输入入口。
|
||||
- 内置标准签名为 `dever.io.println(text: Text) ()`,输出 UTF-8 文本和一个换行;写入失败报告 Dever 调用位置并以非零状态退出。
|
||||
- 修改文本、调用其他自定义函数、跨包调用公开函数都必须由实际源码驱动;不能特判示例名称或内容。
|
||||
- 名称、参数、可见性、包路径和重复定义检查在原生编译前完成;递归及包依赖循环按既有契约拒绝。
|
||||
- 未实现的类型、表达式、分句和输出签名明确报不支持,不静默生成近似代码。
|
||||
- 提供本地 `check <source-root>`、`run <source-root> <package.function>`、`build <source-root> <package.function> --output <path>`;不替换全局命令。
|
||||
- 验收真实 stdout、错误定位、原生可执行文件和输出失败;不启动任何服务或执行全量测试。
|
||||
|
||||
## Deferred User API Proposal
|
||||
|
||||
以下保留之前的 API 讨论作为后续参考;其中持久化、并发与性能要求尚未重新确认,不属于当前验收或实施前置条件。
|
||||
|
||||
### Confirmed Requirements
|
||||
|
||||
- 应用业务使用 Dever 源码(`.dever` 或 `.dever.md` 的程序块);不能手写 Rust 用户 CRUD 再把 Dever 当作装饰。
|
||||
- 用户模型只有 ID、姓名、手机号,CRUD 和 HTTP JSON 交互必须实际可用。
|
||||
- 保留已经讨论的表面语法;只增加实际应用所需的标准 package 能力和必要语义。
|
||||
- 编译器与通用运行时不能特判 `User`、`name`、`phone` 或 `/users`;这些信息来自应用源码。修改业务类型和路由不能要求修改编译器。
|
||||
- 数据需要真实持久化;重启后仍可查询,不能用进程内 Map 冒充实际存储。
|
||||
- 性能验证覆盖真实读写、序列化和持久化,不用空接口成绩替代 CRUD 性能。
|
||||
|
||||
业务模型沿用现有语法:
|
||||
|
||||
```dever
|
||||
type User {
|
||||
id: Id
|
||||
name: Text
|
||||
phone: Text
|
||||
}
|
||||
```
|
||||
|
||||
### Proposed API Acceptance
|
||||
|
||||
以下为待最终收敛的最小 API 行为,不增加登录、管理页面或其它业务模块:
|
||||
|
||||
| Request | Behavior |
|
||||
| --- | --- |
|
||||
| `POST /users` | 提交姓名和手机号;服务端生成 ID,返回创建的用户 |
|
||||
| `GET /users/{id}` | 查询单个用户;不存在时返回明确的未找到结果 |
|
||||
| `GET /users` | 按稳定顺序、有上限地分页查询 |
|
||||
| `PUT /users/{id}` | 完整更新姓名和手机号,ID 不可变 |
|
||||
| `DELETE /users/{id}` | 删除指定用户,删除后无法查询到 |
|
||||
|
||||
- `name`、`phone` 使用 Text;不把手机号当数值,也不擅自添加特定国家的手机号规则或手机号唯一约束。
|
||||
- 缺少字段、非法 JSON、无效 ID、未知用户和存储失败需要明确响应;不能静默填值或伪装成功。
|
||||
- 并发访问不能产生重复 ID、半写入或未说明的丢失更新;具体并发写入契约随存储设计确定。
|
||||
- 吞吐、p50/p95/p99 延迟、错误率和资源使用需要在固定数据量、读写比例、并发和持久化配置下报告,并与同环境、同功能的原生基线比较。数值性能门槛仍待收敛,现有计算内核的 1.15 倍预算不能直接替代 API 指标。
|
||||
|
||||
### Open Decisions
|
||||
|
||||
- 后续 API 先允许内存测试数据;需要持久化时再讨论数据库、并发更新和性能预算。
|
||||
|
||||
### Deferred From This Milestone
|
||||
|
||||
- 契约 DSL、AI 生成器、全面重复语义检测和完整的大项目上下文工具。
|
||||
- 登录/RBAC、前端页面、多租户、分布式部署及其它没有被请求的用户业务。
|
||||
- 与用户 API 无关的完整数值标准库、全部集合组合、自举和组件分发系统;既有语言契约作为后续路线保留。
|
||||
|
||||
## Language Roadmap
|
||||
|
||||
后续章节保留原 Minimal Core 的语言契约,作为本轮定义讨论的基础。已确认的长期规则与首版能力限制分别标明;讨论中的功能不代表已经实现,编译器仍须明确拒绝尚未支持的源码。
|
||||
|
||||
## Repository Evidence
|
||||
|
||||
- 仓库当前没有已发布的 `.dever` parser、formatter 或兼容格式。
|
||||
- 2026-09-05 开工检查确认:当前仓库只有规划资料,没有 Cargo workspace、Rust 源码或测试。HEAD 也只包含两份旧规划文档。
|
||||
- 新语言没有兼容旧语义图、旧 CLI、旧生成结果或旧测试的义务。旧规划由 Git 文档历史保留,不在新实现中增加迁移层。
|
||||
- 从零建立 Rust workspace;复用源码位置诊断思路和仓库根目录 `test/` 约束。旧领域模型和旧后端契约不能决定新语法。
|
||||
|
||||
## Core Language Roadmap Scope
|
||||
|
||||
1. `.dever` 源文件、UTF-8 文本、注释、literal 和唯一 formatter。
|
||||
2. package 路径、公开名称、完整限定名和源码根目录内的自动依赖解析。
|
||||
3. 被动 type、字段型值、选择型值、可空值、List、Map、Bytes 和 opaque Stream 资源。
|
||||
4. 显式 function 边界、线性 body、局部类型推断和值语义修改。
|
||||
5. 通过同名 function 分句表达的穷尽、互斥条件规则。
|
||||
6. 算术、比较、布尔和文本连接表达式。
|
||||
7. `each`、`reduce`、`reduce_until`、`filter`、`find`、`sum` 以及最小 List/Map 标准函数。
|
||||
8. Int、Decimal、Float 的确定数值语义和最小 `math`/`decimal` 标准 package。
|
||||
9. parser、formatter、resolver、type checker、clause analyzer、语义基准解释器、原生 AOT 编译和 CLI。
|
||||
10. Rust 编写的首代引导编译器,以及不依赖 Rust 表面语法、可被未来 Dever 自举编译器复用的 typed HIR 和运行语义。
|
||||
|
||||
## Language Contract
|
||||
|
||||
### 1. Source And Package
|
||||
|
||||
- 源文件后缀固定为 `.dever`,编码为 UTF-8。
|
||||
- 代码标识符只使用 ASCII 英文;注释、字符串和文档可以使用任意 UTF-8。
|
||||
- `#` 开始单行注释;Core 0.1 不提供块注释。`//` 只表示整数除法,不具有第二种词法含义。
|
||||
- 语句和声明按换行或结构边界分隔,不写分号。
|
||||
- 一个文件完整拥有一个 package;同一 package 不能拆到多个文件。
|
||||
- 源文件相对 `src/` 的路径必须与 package 点分名称一致。
|
||||
|
||||
```text
|
||||
src/account/user.dever -> package account.user
|
||||
```
|
||||
|
||||
文件第一项必须是 package 声明:
|
||||
|
||||
```dever
|
||||
package account.user exposes (
|
||||
User
|
||||
create
|
||||
)
|
||||
```
|
||||
|
||||
`exposes` 只能列出当前 package 已声明的 type 或 function。未列出的名称只在当前 package 可见;公开 function 名称会公开该名称的全部签名和分句。
|
||||
|
||||
同 package 引用使用短名称,跨 package 引用必须使用完整限定名:
|
||||
|
||||
```dever
|
||||
normalized = normalize_email(email)
|
||||
user = account.user.create(id, name, email)
|
||||
```
|
||||
|
||||
Core 0.1 不提供 `import`、`use`、通配导入或别名。编译器从完整限定引用建立依赖图,并拒绝 package 循环依赖。`app`、`domain`、`feature`、`flow`、`policy`、`view` 和 `scenario` 都不是关键字,需要时只是普通 package 路径段。
|
||||
|
||||
#### Package Origins And Distributed Components
|
||||
|
||||
语言层只有 package,不新增 `component` 关键字。package 是源码和 API 命名空间;“组件”只是 registry 中用于安装、签名和版本管理的发布单元,可以包含一个根 package 及若干子 package。组件不能绕过各 package 的 `exposes` 边界。
|
||||
|
||||
package 来源固定分为三类:
|
||||
|
||||
| 来源 | 名称规则 | 示例 | 获取方式 |
|
||||
| --- | --- | --- | --- |
|
||||
| 核心标准 package | 编译器保留的单段名称 | `text`、`math`、`decimal` | 随编译器提供 |
|
||||
| Dever 官方组件 | `dever.<component>` 根路径 | `dever.http`、`dever.sql` | 显式安装 |
|
||||
| 公共第三方组件 | `<publisher>.<component>` 根路径 | `stripe.payment`、`shemic.robot` | 显式安装 |
|
||||
|
||||
本地业务 package 继续使用项目内路径,例如 `account.user`、`order.checkout`。本地源码不能声明核心标准名称或 `dever.*` 官方命名空间。同一个构建中如果本地源码、标准库或未来已安装组件提供了相同 package 名称,编译器直接报告重复定义,不进行覆盖或静默择优。
|
||||
|
||||
调用形式对所有来源一致,版本不会进入业务源码:
|
||||
|
||||
```dever
|
||||
user = account.user.create(input)
|
||||
name = text.trim(raw_name)
|
||||
response = dever.http.send(request)
|
||||
payment = stripe.payment.create(order)
|
||||
```
|
||||
|
||||
从 0.2 起,组件的稳定身份与下载来源相互独立。`shemic.contact` 是进入 package 名称和类型身份的 component id;GitHub、其他 Git 服务或 Dever registry 只是可以替换的 source。仓库迁移不会迫使业务源码改名。
|
||||
|
||||
公共组件必须通过命令显式加入,不能因为遇到未知名称就在 `check` 或 `build` 时自动联网:
|
||||
|
||||
```text
|
||||
dever add dever.http@1
|
||||
dever add stripe.payment@3
|
||||
dever add shemic.contact --git https://github.com/shemic/contact.git --tag v1.2.0
|
||||
dever add shemic.contact --git https://github.com/shemic/contact.git --rev 8f34c2a
|
||||
dever update stripe.payment
|
||||
dever fetch
|
||||
```
|
||||
|
||||
Git source 必须同时给出 tag 或 revision,不接受未固定的默认分支 HEAD。tag 在加入时解析为完整 commit;`dever.lock` 同时记录 source URL、完整 commit 和规范化源码内容的 SHA-256,后续 tag 被移动也不会改变构建。组件内全部 package 必须位于 component id 根路径下,例如 `shemic.contact` 可以提供 `shemic.contact.phone`,不能同时冒充 `account.user`。
|
||||
|
||||
0.2 的项目根目录增加两个由 CLI 维护、需要提交的元数据文件:
|
||||
|
||||
```text
|
||||
dever.mod # component id、直接依赖及其 registry/git/path 来源要求
|
||||
dever.lock # 完整依赖图、精确版本/commit、内容摘要和实际提供的 package
|
||||
```
|
||||
|
||||
开发者仍只手写 `.dever`;`dever add`、`dever update` 和未来的本地 link 命令负责规范化更新元数据。分开保存意图和精确结果,使直接依赖保持可读,同时保证所有机器解析出同一份源码。
|
||||
|
||||
下载源码不复制到每个项目。Dever 使用平台级、可由 `DEVER_HOME` 改址的全局只读内容寻址仓库:
|
||||
|
||||
```text
|
||||
$DEVER_HOME/
|
||||
git/<source-url-hash>/ # Git bare mirror,只负责取对象
|
||||
store/sha256/<content-hash>/ # 已校验、不可修改的组件源码
|
||||
build/<target>/<artifact-hash>/ # 可删除的编译缓存
|
||||
```
|
||||
|
||||
项目目录只保留 `src/`、`dever.mod`、`dever.lock` 和可删除的 `target/dever/` 构建结果。多个项目依赖相同 commit 时共享同一份 store 内容。`dever add`、`dever update`、`dever fetch` 是仅有的默认联网入口;普通 `check`、`build` 和 `run` 只读取本地源码、内置标准 package、lock 与 store,缺失时明确要求执行 `dever fetch`,不隐式下载。
|
||||
|
||||
Core 0.1 只实现本地 package 与随编译器提供的核心标准 package,同时锁定上述命名和解析边界。registry、`dever add`、签名验证和外部组件缓存确定延后到 0.2,不影响现有 `.dever` 调用形式。
|
||||
|
||||
### 2. Canonical Naming
|
||||
|
||||
| 对象 | 唯一格式 | 示例 |
|
||||
| --- | --- | --- |
|
||||
| package 路径段 | `lower_snake_case`,优先单数领域名 | `account.user`、`sales_order` |
|
||||
| 文件名 | `lower_snake_case` | `user.dever` |
|
||||
| type | `UpperCamelCase` | `User`、`CreateResult` |
|
||||
| 选择项 | `UpperCamelCase` | `Pending`、`Created` |
|
||||
| function | `lower_snake_case` | `create`、`can_sign_in` |
|
||||
| 输入、输出、局部值、字段 | `lower_snake_case` | `user_id`、`created_at` |
|
||||
| 标准泛型参数 | 有含义的 `UpperCamelCase` | `Item`、`Key`、`Value` |
|
||||
|
||||
大小写不控制公开性。缩写按普通单词处理:`Id`、`Url`、`HttpClient`、`user_id`、`callback_url`。编译器强制可机械判断的大小写、ASCII 和路径格式;“是否是好名称”只产生规范诊断,不依赖英语词典阻止编译。
|
||||
|
||||
### 3. Types And Literals
|
||||
|
||||
Core 0.1 的基础标量只有:
|
||||
|
||||
| 类型 | 语义 |
|
||||
| --- | --- |
|
||||
| `Bool` | `true` 或 `false` |
|
||||
| `Int` | 有符号 64 位整数,范围 `-9223372036854775808` 至 `9223372036854775807` |
|
||||
| `Decimal` | decimal128,最多 34 位有效十进制数字,round half to even |
|
||||
| `Float` | IEEE 754 binary64 近似数 |
|
||||
| `Text` | UTF-8 文本;相等按实际字符序列判断,不做隐式 Unicode 规范化 |
|
||||
| `Id` | 不透明稳定标识,只支持相等比较、传递和序列化 |
|
||||
|
||||
Core 0.1 不提供 `UInt`、`BigInt`、`Percent`、字符类型或隐式动态 `Json` 类型。
|
||||
|
||||
- 整数 literal 默认是 Int。
|
||||
- 带小数点的 literal 默认是 Decimal;在明确要求 Float 的静态上下文中直接成为 Float。
|
||||
- 科学计数 literal,例如 `1.25e6`,是 Float。
|
||||
- Decimal literal 必须能被 34 位 decimal128 精确表示;源码常量不会被静默舍入,超出精度或范围时由编译器拒绝。运行时算术仍按已确定的银行家舍入产生结果。
|
||||
- Text 使用双引号,支持 `\\`、`\"`、`\n`、`\r`、`\t` 和 `\u{HEX}` Unicode 转义。
|
||||
- `true`、`false` 和 `null` 是保留 literal。
|
||||
- 源码不提供 NaN 或 Infinity literal;Float 运算可以产生这些值。
|
||||
|
||||
用户定义 type 只有两种形状,不能混写:
|
||||
|
||||
```dever
|
||||
type User {
|
||||
id: Id
|
||||
name: Text
|
||||
phone: Text?
|
||||
}
|
||||
|
||||
type CreateResult {
|
||||
Created(user: User)
|
||||
InvalidPhone(reason: Text)
|
||||
EmailAlreadyUsed(email: Text)
|
||||
}
|
||||
```
|
||||
|
||||
字段型 type 是固定字段数据;选择型 type 表示同一时间只能是其中一种选择。type 没有方法、构造器、hook、继承或行为,也不能递归包含自身。
|
||||
|
||||
选择项必须通过所属 type 限定:
|
||||
|
||||
```dever
|
||||
result = CreateResult.Created(user)
|
||||
```
|
||||
|
||||
选择项携带的数据在声明中必须有名称和类型,构造时按声明位置传入。字段型值必须一次完整创建:
|
||||
|
||||
```dever
|
||||
user = User {
|
||||
id = id
|
||||
name = name
|
||||
phone = null
|
||||
}
|
||||
```
|
||||
|
||||
未知、重复或遗漏字段都是编译错误,包括值为 `null` 的可空字段。formatter 按 type 声明顺序输出字段。点号只访问或修改已经完整存在的字段型值,不能逐字段创建半初始化对象。
|
||||
|
||||
`Value?` 表示 `Value` 或 `null`。普通类型永远不能为 `null`,`Value??` 非法,也没有 `?.`、`??`、强制解包或隐式默认值。可空值必须交给穷尽的 function 分句处理。
|
||||
|
||||
标准泛型函数产生可空返回值时,可空化是幂等的:`first(List<Int?>)`、`find` 的同类调用及 `get(Map<Text, Int?>, key)` 都返回 `Int?`,不产生嵌套可空类型。返回 `null` 不区分“没有元素/键”和“已有值为 null”;需要区分时,业务使用带显式选择项的 Value 类型。源码仍禁止显式书写 `Int??`。
|
||||
|
||||
### 4. List And Map Values
|
||||
|
||||
List 使用方括号创建:
|
||||
|
||||
```dever
|
||||
users = [first_user, second_user]
|
||||
empty_users() (users: List<User>) {
|
||||
users = []
|
||||
}
|
||||
```
|
||||
|
||||
List 元素必须是同一静态类型。空 List 必须能从 output、参数或其他静态上下文推断元素类型,否则编译错误。
|
||||
|
||||
Map 是 `Map<Key, Value>`,使用裸大括号创建:
|
||||
|
||||
```dever
|
||||
default_labels() (labels: Map<Text, Text>) {
|
||||
labels = {
|
||||
"env" = "production"
|
||||
"region" = "china"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
同一 Map literal 的 key 类型一致、value 类型一致,重复 key 是编译错误;空 Map 也必须能推断完整类型。`Type { ... }` 是固定字段型值,裸 `{ ... }` 是动态 Map,二者不会合并成万能对象。
|
||||
|
||||
Map key 只允许 Text、Int、Bool、Id 和不携带数据的选择型 type。Decimal、Float、可空值、字段型值、List 和 Map 不能成为 key。
|
||||
|
||||
Map 保证插入顺序。literal 保留源码顺序;`put` 新 key 时追加,覆盖已有 key 不移动位置;`remove` 后重新写入视为新的末尾项。`entries`、显示和未来的 JSON 边界都必须遵守这一顺序。
|
||||
|
||||
### 5. Function Definitions And Calls
|
||||
|
||||
所有行为只有一种定义形式:
|
||||
|
||||
```dever
|
||||
line_total(line: Line) (total: Decimal) {
|
||||
total = line.price * line.quantity
|
||||
}
|
||||
```
|
||||
|
||||
- 第一组括号是输入,第二组是命名输出。
|
||||
- 普通输入和输出必须写成 `name: Type`;body 内局部值可以推断。
|
||||
- 没有输入或输出时仍写空括号。
|
||||
- 不使用 `function` 或 `return` 关键字。
|
||||
- 输入名称是当前分句的局部绑定;输出名称和输入输出类型属于稳定签名。
|
||||
- 调用只按位置传参,不提供命名参数调用。
|
||||
- 用户 function 以“package、名称、输入数量”确定签名;同名同参数数量的全部分句必须具有相同的基础输入类型和输出契约。不同参数数量可以形成独立签名。
|
||||
- 同一签名的全部分句必须在同一文件中连续书写。
|
||||
- Core 0.1 禁止直接或间接递归;重复执行只能通过 `each`、`reduce` 和 `reduce_until` 这些受检查的具名 handler 组合器进入。
|
||||
|
||||
选择项会提供所属选择型 type,普通 type 会提供自身类型;`null` 和 `other` 则从同组其他分句推断基础输入类型。只写 `null`/`other` 而没有任何可推断类型的分句组是编译错误。`Text` 与 `null` 两个分句共同形成 `Text?` 输入,而不是两个运行时重载。
|
||||
|
||||
单输出调用直接得到该值,零输出调用作为一条动作语句,多输出调用得到只能按输出名称访问的结果:
|
||||
|
||||
```dever
|
||||
allowed = can_sign_in(user.status)
|
||||
parts = split_name(name)
|
||||
display = parts.first + parts.last
|
||||
```
|
||||
|
||||
不提供按位置拆包。命名 function 只能在普通调用位置、作为标准序列/集合操作的 handler,或传给受限静态 handler 输入;Core 0.1 不提供 lambda、闭包,也不能把 function 存入局部值、字段、List、Map 或 Stream。
|
||||
|
||||
### 6. Function Clauses Replace Conditional Blocks
|
||||
|
||||
function 分句是 Dever 唯一的条件分派机制。这是 2026-09-07 用户确认的长期语言规则;条件 block 和条件表达式不属于后续待增加能力。Bool 表达式及其短路规则仍按第 8 节定义,业务分支通过调用具名 function 的分句选择。
|
||||
|
||||
示例:
|
||||
|
||||
```dever
|
||||
can_pay(status: OrderStatus.Draft) (allowed: Bool) {
|
||||
allowed = true
|
||||
}
|
||||
|
||||
can_pay(status: other) (allowed: Bool) {
|
||||
allowed = false
|
||||
}
|
||||
```
|
||||
|
||||
冒号左侧始终是当前分句的局部输入名称;不同分句可以使用不同名称。右侧允许:
|
||||
|
||||
- 普通类型,表示该类型的任意值;
|
||||
- `true`、`false`、`null`、Text 或数值常量;
|
||||
- 完整限定的选择项及其数据绑定,例如 `CreateResult.Created(user)`;
|
||||
- 选择项中的 `_`,表示忽略该携带值;
|
||||
- Int 或 Decimal 的静态常量比较;
|
||||
- 上述数值比较的一个上下界组合;
|
||||
- 上下文关键词 `other`。
|
||||
|
||||
数值范围直接放在输入中:
|
||||
|
||||
```dever
|
||||
absolute(value: Int < 0) (result: Int) {
|
||||
result = -value
|
||||
}
|
||||
|
||||
absolute(value: Int >= 0) (result: Int) {
|
||||
result = value
|
||||
}
|
||||
|
||||
grade(score: Int >= 60 and < 90) (name: Text) {
|
||||
name = "pass"
|
||||
}
|
||||
|
||||
grade(score: Int < 60) (name: Text) {
|
||||
name = "fail"
|
||||
}
|
||||
|
||||
grade(score: Int >= 90) (name: Text) {
|
||||
name = "excellent"
|
||||
}
|
||||
```
|
||||
|
||||
Float 不进入静态范围分句,因为 NaN 不具有普通全序;先通过 `math.is_nan` 等 function 得到 Bool,再对 Bool 写分句。
|
||||
|
||||
分句没有源码顺序优先级。编译器把同一签名的全部分句作为一组规则,拒绝类型不一致、重叠、遗漏和不可达情况。多输入 function 中,每个 `other` 是该输入位置全部明确模式的补集,编译器再检查各位置组合是否覆盖完整输入空间。`other` 只在分句输入冒号右侧具有该含义,不能作为普通值存储、传递或组合。
|
||||
|
||||
分句输入中不能调用任意 function 或读取运行时状态。更深一层的业务选择必须调用另一个有名称的 function,源码不提供 `if`、`else`、`switch`、`match`、`when` 或 `by` block。
|
||||
|
||||
### 7. Linear Body And Value Semantics
|
||||
|
||||
body 只包含顺序赋值和 function 调用:
|
||||
|
||||
```dever
|
||||
final_price(price: Decimal, rate: Decimal) (result: Decimal) {
|
||||
discounted = price * (1 - rate)
|
||||
result = decimal.round(discounted, 2)
|
||||
}
|
||||
```
|
||||
|
||||
表达式由 literal、名称、字段访问、值构造、function 调用、一元运算和二元运算组成。没有条件表达式、循环 block、匿名 function、复合赋值或隐藏控制流。
|
||||
|
||||
`=` 既用于初始化,也用于修改当前 function 的 input、局部值或 output。编译器强制:
|
||||
|
||||
- 读取前已经完整初始化;
|
||||
- 字段修改的宿主值已经完整初始化;
|
||||
- function 结束时全部命名输出都已赋值;
|
||||
- 赋值类型稳定,不通过再次赋值改变局部类型;
|
||||
- 无意义覆盖和写入后未读取至少产生诊断。
|
||||
|
||||
普通值的赋值、传参和输出采用值语义。修改只属于当前局部名称,调用方或其他名称不会观察到共享别名变化;变化只能通过命名 output 或未来的显式 effect function 离开当前调用。实现可以用唯一所有权或写时复制消除真实复制,但源码不暴露借用、生命周期或 `clone`。File、Socket、Listener 和 Stream 是显式 opaque 资源例外:复制只建立同一资源状态的别名,不复制外部资源。
|
||||
|
||||
### 8. Expressions And Operators
|
||||
|
||||
普通算术直接使用符号:
|
||||
|
||||
```dever
|
||||
subtotal = price * quantity
|
||||
ratio = 5 / 2
|
||||
page = 5 // 2
|
||||
remainder = 5 % 2
|
||||
eligible = user.active and user.age >= 18
|
||||
```
|
||||
|
||||
| 运算 | 规则 |
|
||||
| --- | --- |
|
||||
| `+ - *` | Int、Decimal 或 Float 的同类运算;Int 与 Decimal 混合时 Int 无损提升为 Decimal |
|
||||
| `/` | Int/Int 返回 Decimal;Decimal 与 Int 返回 Decimal;Float/Float 返回 Float |
|
||||
| `//` | 只接受 Int,结果向零截断 |
|
||||
| `%` | 只接受 Int,余数符号跟随被除数,并满足 `a = (a // b) * b + (a % b)` |
|
||||
| `+` | 也可连接两个 Text |
|
||||
| `== !=` | 相同可比较类型 |
|
||||
| `< <= > >=` | Int、Decimal 或 Float 的同类比较;Int 可提升为 Decimal |
|
||||
| `and or not` | 只接受 Bool,并具有短路语义 |
|
||||
|
||||
可比较类型包括上述标量,以及成员递归可比较的字段型、选择型、可空、List、Map 和 MapEntry。字段型按声明字段逐项比较;选择型比较选择项和携带值;List 按位置比较;Map 按插入顺序比较 key/value 对,因此顺序不同的 Map 不相等;可空值中只有两个 null 相等,两个非 null 值继续比较其内容。Float 保持下文的 NaN 规则,包括嵌套在集合或字段中时。命名多输出结果只能访问输出字段,不能直接比较。相等运算不做 Int/Decimal 提升。
|
||||
|
||||
Decimal 与 Float 不隐式混合,实际 Int 值转为 Float 也必须显式调用 `float.from_int`。Core 0.1 不提供 Float 到 Decimal 的隐式或有损转换。
|
||||
|
||||
运算优先级从高到低固定为:调用和字段访问、一元 `-`/`not`、`* / // %`、`+ -`、比较、`and`、`or`。同级二元运算从左到右;括号可以显式改变顺序。formatter 不依赖空白表达优先级。
|
||||
|
||||
### 9. Collection And Sequence Functions
|
||||
|
||||
Core 0.1 只保留以下集合行为,不增加循环语法:
|
||||
|
||||
```dever
|
||||
views = each(to_view, users)
|
||||
views = each(to_view, users, context)
|
||||
|
||||
active = filter(is_active, users)
|
||||
active = filter(is_active, users, context)
|
||||
|
||||
user = find(is_target, users)
|
||||
user = find(is_target, users, context)
|
||||
|
||||
total = sum(prices)
|
||||
total = sum(line_total, lines)
|
||||
total = sum(line_total, lines, context)
|
||||
|
||||
state = reduce(update_state, values, initial_state)
|
||||
state = reduce_until(update_until_done, values, initial_state)
|
||||
|
||||
parallel_each(consume, values, 4)
|
||||
parallel_each(consume, values, 4, context)
|
||||
```
|
||||
|
||||
- `each`、`filter`、`find` 和投影式 `sum` 最多有一个末尾 context;需要多项共享数据时先组合成字段型值,其 handler 先接收元素、再接收 context。
|
||||
- `reduce` 和 `reduce_until` 的第三项是必需的初始状态,不是可选 context;handler 先接收元素、再接收当前状态,且不接受第四项参数。
|
||||
- `each` 的处理 function 有一个输出时按输入顺序产生 `List<Output>`;没有输出时只按顺序执行动作;多个输出不合法。
|
||||
- `filter` 的处理 function 必须输出 Bool,并保留原列表顺序。
|
||||
- `find` 找到第一个 Bool 为 true 的元素后停止,返回 `Item?`;没有结果返回 `null`。
|
||||
- `sum(List<Number>)` 直接求和;投影形式要求处理 function 输出 Int、Decimal 或 Float。
|
||||
- 空 List 的 `sum` 返回相应数值类型的零。
|
||||
- 除显式 `parallel_each` 外,List 操作按列表顺序执行,Bytes 按字节位置执行,Stream 按拉取顺序执行;Float 求和不得为了优化而重排。
|
||||
- `reduce` 和 `reduce_until` 的完整 List/Bytes/Stream、状态和停止契约由 Approved Foundation Extension 定义;它们不开放循环 block 或用户递归。
|
||||
- `parallel_each` 接受 List、Bytes 或 Stream、1–256 个工作线程和可选 context;handler 必须零输出,输入依次是元素和 context。复用既有静态 handler 与专门化规则,不产生用户可存储的 function 值。
|
||||
- 生产端顺序拉取且队列有界,工作端的副作用顺序不保证。handler 输入与 context 不能递归包含 Stream,源 Stream 只在生产端拉取;文件与 Socket 等别名仍遵守共享资源规则。
|
||||
- `parallel_each` 返回前等待全部已启动动作;程序故障在后续拉取边界停止分派,保留第一个已记录故障并传播源码位置。已经阻塞的拉取或系统调用由显式系统超时约束,不提供强制取消或后台遗留任务。非法线程数在拉取前产生程序故障。
|
||||
|
||||
其他最小标准函数:
|
||||
|
||||
```dever
|
||||
users = append(users, user)
|
||||
user = first(users)
|
||||
|
||||
value = get(labels, "env")
|
||||
labels = put(labels, "env", "development")
|
||||
labels = remove(labels, "env")
|
||||
pairs = entries(labels)
|
||||
```
|
||||
|
||||
`append` 返回新 List;`first(List<Item>)` 返回 `Item?`。`get` 返回 `Value?`;`put` 和 `remove` 返回新 Map;`entries` 返回按插入顺序排列的 `List<MapEntry<Key, Value>>`。没有 `list.add`、数字点号索引、`map.key` 或 `map[key]`。
|
||||
|
||||
`any`、`all`、`min`、`max` 不进入首版;真实重复需求出现后再增加普通标准 function。
|
||||
|
||||
### 10. Recoverable Failures And Runtime Faults
|
||||
|
||||
可恢复业务失败使用选择型输出:
|
||||
|
||||
```dever
|
||||
create_message(result: CreateResult.Created(user)) (message: Text) {
|
||||
message = user.name
|
||||
}
|
||||
|
||||
create_message(result: CreateResult.InvalidPhone(reason)) (message: Text) {
|
||||
message = reason
|
||||
}
|
||||
|
||||
create_message(result: CreateResult.EmailAlreadyUsed(email)) (message: Text) {
|
||||
message = email + " already exists"
|
||||
}
|
||||
```
|
||||
|
||||
这同时替代 `throw` 和 `catch`。调用方接收完整选择值,再通过命名分句显式转换。Core 0.1 不提供 exception、自动错误传播、隐藏提前退出或类似 Rust `?` 的语法。
|
||||
|
||||
编译器可以证明的不变量错误直接拒绝编译。只能在运行时发现的程序故障终止当前执行边界,并至少报告故障类别、文件、行和列;普通 function 不能捕获、忽略或转换程序故障。执行边界由宿主确定,例如一次 CLI 调用,未来可以是一次请求或任务。
|
||||
|
||||
数据库、网络等只要存在恢复可能,就必须在未来以显式选择型结果返回,不能伪装成程序故障。
|
||||
|
||||
### 11. Numeric Semantics
|
||||
|
||||
- Int 是固定 i64;不环绕、不饱和。静态可证明的溢出是编译错误,运行时溢出是程序故障。
|
||||
- `Int / Int` 先无损提升为 Decimal 再除,因此 `5 / 2` 是 Decimal `2.5`。
|
||||
- `Int // Int` 向零截断;`Int % Int` 与商保持代数恒等式。除数为零以及 `-9223372036854775808 // -1` 属于溢出故障。
|
||||
- Decimal 使用 decimal128 的 34 位有效数字和银行家舍入;算术中的正常 inexact/rounded 状态产生舍入结果,指数上溢、下溢、除零或无效运算产生程序故障,不向源码暴露 Decimal NaN/Infinity。
|
||||
- 金额位数由 `decimal.round(value, places)` 显式处理;核心算术不根据变量名、字段名或业务场景猜测两位小数。
|
||||
- Float 遵守 IEEE 754 binary64 非捕获行为:溢出产生正负 Infinity,无效运算产生 NaN,除零产生 Infinity 或 NaN。
|
||||
- Float 的 NaN 与任何值的 `==` 都为 false,`!=` 为 true,有序比较均为 false;使用 `math.is_finite`、`math.is_nan` 和 `math.is_infinite` 分类。
|
||||
- 常用科学函数通过 `math.sqrt`、`math.sin`、`math.cos`、`math.log` 和 `math.pow` 等普通标准 package function 提供。
|
||||
- Decimal 与 Float 不隐式混合。任意精度整数/小数、向量、矩阵、复数、统计与单位系统以后由独立 package 提供。
|
||||
|
||||
## Standard Names
|
||||
|
||||
无需 import 即可使用的核心名称只有:
|
||||
|
||||
- Bool、Int、Decimal、Float、Text、Id、Bytes、List、Map、MapEntry、Stream;
|
||||
- true、false、null、other;
|
||||
- each、parallel_each、reduce、reduce_until、filter、find、sum、append、first、get、put、remove、entries、length、用于 Stream 的 close;
|
||||
- 仅用于 function 输入签名的上下文关键词 handler;
|
||||
- 算术、比较和布尔运算符。
|
||||
|
||||
其他标准行为使用完整 package 名,例如 `text.trim`、`text.lower`、`decimal.round`、`float.from_int` 和 `math.sqrt`。这避免大量隐式全局名称,也让标准库与业务 package 遵守同一调用模型。
|
||||
|
||||
## CLI Identity And Coexistence
|
||||
|
||||
- 语言、编译器产品和正式命令名保持为 `dever`,文档与命令语义以 `dever` 为准。
|
||||
- Core 0.1 与现有 Dever 框架 CLI 共存期间,系统 `PATH` 中可以暂时用 `deverc` 暴露语言编译器;不得覆盖、替换或遮蔽现有的 `dever` 命令。
|
||||
- `deverc` 只是指向同一编译器二进制的安装入口,不形成第二套命令、配置或行为契约。
|
||||
- 仓库构建与自动测试直接调用构建产物,不修改系统 `PATH` 或全局可执行文件;创建、更新或移除全局 `deverc` 入口必须单独获得用户授权。
|
||||
- 未来是否让语言编译器接管全局 `dever` 命令属于独立迁移决策,不在 Core 0.1 默认实施范围内。
|
||||
|
||||
## Complete Package Example
|
||||
|
||||
```dever
|
||||
public type UserStatus {
|
||||
Pending
|
||||
Active
|
||||
Disabled(reason: Text)
|
||||
}
|
||||
|
||||
public type CreateInput {
|
||||
id: Id
|
||||
name: Text
|
||||
email: Text
|
||||
phone: Text?
|
||||
score: Int
|
||||
labels: Map<Text, Text>
|
||||
}
|
||||
|
||||
public type CreateResult {
|
||||
Created(user: User)
|
||||
InvalidName(reason: Text)
|
||||
InvalidEmail(reason: Text)
|
||||
}
|
||||
|
||||
public type User {
|
||||
id: Id
|
||||
name: Text
|
||||
email: Text
|
||||
phone: Text?
|
||||
score: Int
|
||||
labels: Map<Text, Text>
|
||||
status: UserStatus
|
||||
}
|
||||
|
||||
public type UserView {
|
||||
id: Id
|
||||
name: Text
|
||||
email: Text
|
||||
phone: Text
|
||||
score: Int
|
||||
can_sign_in: Bool
|
||||
}
|
||||
|
||||
public create(input: CreateInput) (result: CreateResult) {
|
||||
normalized = normalize(input)
|
||||
result = create_name(normalized, normalized.name)
|
||||
}
|
||||
|
||||
normalize(input: CreateInput) (result: CreateInput) {
|
||||
result = input
|
||||
result.name = text.trim(input.name)
|
||||
result.email = text.lower(text.trim(input.email))
|
||||
}
|
||||
|
||||
create_name(input: CreateInput, name: "") (result: CreateResult) {
|
||||
result = CreateResult.InvalidName("name is required")
|
||||
}
|
||||
|
||||
create_name(input: CreateInput, name: other) (result: CreateResult) {
|
||||
result = create_email(input, name, input.email)
|
||||
}
|
||||
|
||||
create_email(input: CreateInput, name: Text, email: "") (result: CreateResult) {
|
||||
result = CreateResult.InvalidEmail("email is required")
|
||||
}
|
||||
|
||||
create_email(input: CreateInput, name: Text, email: other) (result: CreateResult) {
|
||||
user = User {
|
||||
id = input.id
|
||||
name = name
|
||||
email = email
|
||||
phone = input.phone
|
||||
score = input.score
|
||||
labels = input.labels
|
||||
status = UserStatus.Pending
|
||||
}
|
||||
result = CreateResult.Created(user)
|
||||
}
|
||||
|
||||
public activate(user: User) (result: User) {
|
||||
result = user
|
||||
result.status = UserStatus.Active
|
||||
}
|
||||
|
||||
public disable(user: User, reason: Text) (result: User) {
|
||||
result = user
|
||||
result.status = UserStatus.Disabled(reason)
|
||||
}
|
||||
|
||||
public can_sign_in(status: UserStatus.Active) (allowed: Bool) {
|
||||
allowed = true
|
||||
}
|
||||
|
||||
public can_sign_in(status: other) (allowed: Bool) {
|
||||
allowed = false
|
||||
}
|
||||
|
||||
phone_text(phone: Text) (result: Text) {
|
||||
result = phone
|
||||
}
|
||||
|
||||
phone_text(phone: null) (result: Text) {
|
||||
result = "Not provided"
|
||||
}
|
||||
|
||||
public to_view(user: User) (view: UserView) {
|
||||
view = UserView {
|
||||
id = user.id
|
||||
name = user.name
|
||||
email = user.email
|
||||
phone = phone_text(user.phone)
|
||||
score = user.score
|
||||
can_sign_in = can_sign_in(user.status)
|
||||
}
|
||||
}
|
||||
|
||||
public to_views(users: List<User>) (views: List<UserView>) {
|
||||
views = each(to_view, users)
|
||||
}
|
||||
|
||||
is_active(user: User) (result: Bool) {
|
||||
result = can_sign_in(user.status)
|
||||
}
|
||||
|
||||
public active_views(users: List<User>) (views: List<UserView>) {
|
||||
active = filter(is_active, users)
|
||||
views = each(to_view, active)
|
||||
}
|
||||
|
||||
has_id(user: User, expected: Id) (matches: Bool) {
|
||||
matches = user.id == expected
|
||||
}
|
||||
|
||||
public find_user(users: List<User>, id: Id) (user: User?) {
|
||||
user = find(has_id, users, id)
|
||||
}
|
||||
|
||||
public put_label(user: User, key: Text, value: Text) (result: User) {
|
||||
result = user
|
||||
result.labels = put(user.labels, key, value)
|
||||
}
|
||||
|
||||
public label(user: User, key: Text) (value: Text?) {
|
||||
value = get(user.labels, key)
|
||||
}
|
||||
|
||||
score_bonus(user: User, rate: Decimal) (amount: Decimal) {
|
||||
amount = user.score * rate
|
||||
}
|
||||
|
||||
public total_score_bonus(users: List<User>, rate: Decimal) (total: Decimal) {
|
||||
total = sum(score_bonus, users, rate)
|
||||
}
|
||||
```
|
||||
|
||||
该源码只要求开发者理解 package、type、function、值和普通表达式。它同时覆盖显式业务结果、局部修改、条件分句、可空处理、列表转换、筛选、查找、Map 更新和 Decimal 聚合,所有路径保持平铺且可由编译器完整检查。
|
||||
|
||||
## Original Core Deferrals
|
||||
|
||||
以下保留原 Core 0.1 的暂缓能力,具体版本安排在后续需求中确定。HTTP、JSON、持久化以及异步/并发 I/O 的应用扩展仍属暂缓 API 提案。
|
||||
|
||||
- AI、自然语言转译、画布和业务 DSL;
|
||||
- Web 页面、React,以及超出首个 API 需要的数据库、网络和部署能力;
|
||||
- 超出首个 API 需要的 effect/capability、异步、并发和事务能力;不开放任意共享可变业务全局变量;
|
||||
- package registry、版本解析和项目清单;
|
||||
- `for/while/break/continue/iterate/recur/repeat`、用户递归和其它通用循环结构;
|
||||
- class、继承、interface、annotation、macro、unsafe、FFI;
|
||||
- import、别名、命名参数、lambda、闭包和一般化一等 function;
|
||||
- 用户泛型 type、递归 type、Set 和动态 Json;首个 API 的 JSON 边界应由静态类型驱动;
|
||||
- UInt、BigInt、任意精度 Decimal、Percent、日期时间和单位类型;
|
||||
- 直接 LLVM/Cranelift backend、完成自举、所有权或生命周期表面语法。
|
||||
|
||||
这些内容保留为 Core 0.1 暂缓项,不改变 Dever 最终成为通用编程语言的方向。条件 block 已从暂缓清单移除,条件分派始终遵守第 6 节的长期规则。
|
||||
|
||||
## Core Roadmap Acceptance Criteria
|
||||
|
||||
这些是完整语言路线的验收项。2026-09-07 的基础语法、最小系统接口和后续工具/库分别验收,实际状态与证据见 `implement.md`;发行和自举不因基础里程碑完成而视为已交付。
|
||||
|
||||
1. 一个源码根目录中的多个 `.dever` 文件可以被加载;Core 0.1 只读取该根目录和内置标准 package,不隐式联网或搜索外部目录;路径与 package 不一致、保留命名空间、重复 package、未知公开名、未知引用和循环依赖均得到带源码位置的确定诊断。
|
||||
2. parser 覆盖本 PRD 的 package、两种 type、function、分句、value、statement 和 expression;拒绝已排除的关键字或语法。
|
||||
3. formatter 对合法程序产生唯一布局,连续执行两次结果不变,并保持注释和程序含义。
|
||||
4. 编译器强制命名格式、显式 function 边界、位置调用、一文件一 package、连续分句和无递归调用图;同 package 使用短名称,跨 package 必须使用完整限定名,并且只能访问对方 `exposes` 中的名称。
|
||||
5. type checker 拒绝未知/重复/遗漏字段、半初始化字段写入、未初始化读取、遗漏 output、非法 null、类型漂移、非法 Map key 和未授权隐式转换。
|
||||
6. clause analyzer 对选择型、可空、Bool、Text 常量、Int/Decimal 范围和多输入组合检查互斥、穷尽与可达性;分句移动顺序不改变执行结果。
|
||||
7. 本 PRD 的完整 package 示例可以通过解析、格式化、名称解析和类型检查;独立的零输入示例在语义基准解释器和原生程序中产生相同的确定命名输出。
|
||||
8. 局部赋值和字段修改不会改变调用方或其他名称持有的原值;编译器实现可以优化复制但不能改变可观察语义。
|
||||
9. `each`、`reduce`、`reduce_until`、`filter`、`find` 和 `sum` 的顺序、handler、context、初始/空结果、停止和类型规则全部有定向测试。
|
||||
10. List、Map、Bytes 和 Stream,以及 `append`、`first`、`get`、`put`、`remove`、`entries` 遵守可空返回、值/资源语义和稳定顺序。
|
||||
11. `5 / 2` 得到 Decimal `2.5`,`-5 // 2` 得到 Int `-2`,`-5 % 2` 得到 Int `-1`,并满足商余恒等式。
|
||||
12. Decimal 能证明 `0.1 + 0.2 == 0.3`,`1 / 3` 使用 34 位有效数字和 round half to even;`decimal.round` 显式控制业务位数。
|
||||
13. 静态 Int/Decimal 溢出或零除数被拒绝编译;动态故障终止当前执行边界并定位 `.dever` 源码,不环绕、饱和或返回默认值。
|
||||
14. Float 使用 binary64 和科学计数法,能够产生并通过 `math.is_nan`、`math.is_finite`、`math.is_infinite` 判断 NaN/Infinity;Decimal 与 Float 混用被拒绝。
|
||||
15. 可恢复失败只能通过选择型输出和穷尽分句传播;源码中不存在 exception、`throw`、`catch` 或自动传播语法。
|
||||
16. 正式 CLI 名为 `dever`,至少提供 `dever check <source-root>`、`dever fmt <source-root>`、`dever build <source-root> <package.function> --output <path>` 和 `dever run <source-root> <package.function>`;与现有框架 CLI 共存时,临时全局入口 `deverc` 必须调用同一编译器且不得覆盖现有 `dever`;build/run 首版只接受公开的零输入 function,run 执行与 build 相同的原生路径并确定性打印命名输出。
|
||||
17. 新实现不依赖旧 canonical JSON、SemanticGraph、Refiner、Workbench、温度示例或 Rust/React 生成后端,仓库文档不再把旧路线描述为当前架构。
|
||||
18. 生产产物不链接通用解释器,不携带运行时 type tag 分派或垃圾回收器;record、choice、List、Bytes 和静态 handler 在 AOT 路径中具有具体原生表示,热循环不发生逐元素动态 handler 分派或无必要堆分配;opaque Stream 只在 I/O 资源拉取边界保留内部生产者抽象。
|
||||
19. 在同一算法、数据布局、工具链和机器上的 release 基准中,Int/Float 算术及 List `each`/`filter`/`sum` 代表性热路径的中位执行时间不得超过等价 safe Rust 基线的 1.15 倍;Decimal 与有序 Map 分别对使用相同底层语义的 Rust 基线比较,编译时间单独报告。
|
||||
20. Rust 生成文件只存在于编译器管理的临时构建目录,不是用户源码、公共输出格式或兼容接口;删除这些文件不影响 `.dever` 工程。
|
||||
|
||||
## Risks And Deferred Items
|
||||
|
||||
- 条件分句的穷尽分析是首版最复杂的静态检查,应先支持有限选择域与一维 Int/Decimal 区间,再组合多个输入;不引入通用定理证明器。
|
||||
- decimal128 需要成熟实现与一致状态标志。Core 0.1 采用 Rust `dec` crate 的 Decimal128 和可配置 Context,并将其封装在内部数值适配层;语言级测试锁定行为,依赖 API 不得泄漏到 `.dever`。
|
||||
- 当前仍禁止用户递归,已按批准范围提供显式文件/TCP 系统操作和结构化异步并发;异步网络、一般化 effect 和事务模型尚未实现,因此不是最终完整运行时。
|
||||
- Float 运算遵守平台 IEEE 754 语义,但任何未来的快速数学优化都必须显式设计,首版不得重排计算。
|
||||
|
||||
# Current Source And Module API Contract (2026-09-18)
|
||||
|
||||
This user-approved contract supersedes historical `package/exposes`, arbitrary entry arguments and "API deferred" wording above. Source filenames relative to `module/` define package names in both `.dever` and `.dever.md`; top-level type/function declarations default private and may opt into cross-package access with `public`. `deverc run/build <project>` always invokes private `main()` from `module/main.dever` (or `.dever.md`) and accepts no entry argument. Markdown H1 documents path-derived package and public declarations with no executable H1 block.
|
||||
|
||||
Each module may own recursive `api/` source containing only private `get_`/`post_`/`delete_` ordinary functions with one `response` output. Routes are statically validated and compiled only when reachable `main()` calls `dever.api.serve()`. GET/DELETE query inputs and POST JSON-object inputs are typed Text/Int/Bool (nullable allowed), and HTTP responses have JSON `code/message/data` envelopes. Listener settings are read only from `config/setting.json`. No application-config environment variable, implicit listener, new auth policy or CMS HTTP business endpoint is part of this milestone. Current canonical contracts are in `LANGUAGE.md`, `MARKDOWN-SYNTAX.md` and `.trellis/spec/backend/`.
|
||||
|
||||
# Current AI-Oriented Source Architecture Contract (2026-09-19)
|
||||
|
||||
This section supersedes the 2026-09-18 application visibility and package rules above. An application starts only at `module/main.dever` or `module/main.dever.md`; `main()` is implicit and private, and HTTP starts only when it calls `dever.api.serve()`. Application source contains no `package`, `exposes`, `public`, `internal` or import declarations.
|
||||
|
||||
Business source uses `module/<component>/<domain>/<role>.dever` or `module/<component>/<domain>/<role>/<topic>.dever`, where role is exactly `app`, `domain`, `model`, `port`, `adapter` or `api`. A role file and its same-name directory are mutually exclusive. Non-API role directories are flat; only `api/` may add nested URL scopes. A role directory containing only one source file is rejected because it creates structure without separation; keep that implementation in the role file instead.
|
||||
|
||||
Files group cohesive behavior rather than individual functions. One role file may contain multiple related functions, and one topic file may contain multiple related functions. The topic filename never becomes part of an App call. All App functions are cross-domain capabilities and are addressed as `<component>.<domain>.<function>`; a same-component caller may use `<domain>.<function>`, and source in the same domain may use `app.<function>`. Every other role is domain-private. Cross-domain and cross-component calls may target only App. Model types and ID types may appear in relations and signatures across domains, but generated Model operations remain callable only inside their owning domain. API handlers are HTTP entry adapters and are never source-callable.
|
||||
|
||||
App inputs, outputs and inferred failure sets are one public contract. They cannot expose a private Domain/Adapter type; a business error that may leave the domain is declared in App and referenced from same-domain private source as `app.<ErrorType>`.
|
||||
|
||||
The dependency direction is `api -> app`, `app -> domain/model/port/adapter` plus another domain's App, while domain/model/port/adapter remain implementation details. Generic dumping grounds such as `common`, `shared`, `utils`, `helper`, `base` and physical `service/` are invalid application architecture. Keep one-use logic inline, same-topic reuse beside its callers, cross-topic domain rules in `domain`, persistence in `model`, and external integrations in `adapter`; introduce `port` only for a real replaceable boundary.
|
||||
|
||||
API route prefixes and JSON `code/message/data` envelopes remain as approved on 2026-09-18. Runtime settings still come only from `config/setting.json`; environment-variable configuration remains prohibited. Authentication remains business composition through App/domain capabilities rather than a compiler-owned HTTP policy.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Package Distribution Research
|
||||
|
||||
## Question
|
||||
|
||||
How should a Dever project consume a component downloaded from GitHub or another Git host without leaking transport details into `.dever` source or losing reproducible builds?
|
||||
|
||||
## Primary Evidence
|
||||
|
||||
- Go defines a module as a versioned collection of packages. The module path is also the prefix of package import paths and usually identifies where the module can be downloaded. Downloaded source is shared through a module cache, and hashes are verified against `go.sum`.
|
||||
- https://go.dev/ref/mod
|
||||
- https://go.dev/doc/modules/gomod-ref
|
||||
- Cargo permits registry, Git and local path sources. Git dependencies may select a tag or revision, and Cargo locks the resolved commit in `Cargo.lock` until an explicit update.
|
||||
- https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
|
||||
- Cargo and Go both separate downloaded source caches from project build artifacts. Go also supports optional vendoring for a fully project-local source tree.
|
||||
- https://go.dev/ref/mod#module-cache
|
||||
- https://go.dev/ref/mod#vendoring
|
||||
- https://doc.rust-lang.org/cargo/reference/config.html#cache
|
||||
|
||||
## Alternatives
|
||||
|
||||
### Git URL as package identity
|
||||
|
||||
Example: `github.com.shemic.contact.phone.parse(raw)`.
|
||||
|
||||
This is easy to locate but couples every source reference and type identity to the current hosting provider. Repository transfer, self-hosting or registry mirroring then becomes a source-breaking rename. It also creates long names that obscure the business API.
|
||||
|
||||
### Project-local copied dependencies
|
||||
|
||||
Example: clone every dependency under `vendor/`.
|
||||
|
||||
This is transparent and offline-friendly but duplicates source across projects, increases repository size and makes accidental dependency edits likely. It is useful as an explicit export mode, not the default store.
|
||||
|
||||
### Stable identity plus independent source
|
||||
|
||||
Example identity: `shemic.contact`; example source: `https://github.com/shemic/contact.git` at an exact resolved commit.
|
||||
|
||||
This preserves short, stable `.dever` names while allowing registry, Git, mirrors and local development to use the same package identity. It requires dependency metadata and identity verification, but those responsibilities belong to the package manager rather than business source.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Use the third model:
|
||||
|
||||
1. `component id` is the stable namespace and type-identity root.
|
||||
2. `source` is a replaceable registry, Git or local transport selected outside `.dever`.
|
||||
3. `dever.mod` records direct dependency intent and source requirements.
|
||||
4. `dever.lock` records the complete graph, full Git commits and normalized content hashes.
|
||||
5. A global immutable content-addressed store deduplicates verified source across projects.
|
||||
6. `check`, `build` and `run` never perform implicit network access; explicit `add`, `update` and `fetch` do.
|
||||
7. Package declarations must remain beneath the component root, preventing one dependency from supplying another component's namespace.
|
||||
|
||||
This deliberately combines Go's small module/package model and shared verified cache with Cargo's source flexibility and exact Git locking, while avoiding Go's coupling between source-level identity and repository location.
|
||||
@@ -0,0 +1,55 @@
|
||||
# Core 0.1 Runtime Dependency Research
|
||||
|
||||
- Checked: 2026-09-03
|
||||
- Scope: dependencies required by already-approved Decimal and Map semantics
|
||||
|
||||
## Decimal128
|
||||
|
||||
Selected for the MVP: `dec = "=0.4.11"`.
|
||||
|
||||
Evidence:
|
||||
|
||||
- The [dec crate documentation](https://docs.rs/dec/latest/dec/) describes `Decimal128` as a 128-bit decimal representation with 34 digits of precision and exposes a configurable `Context` with rounding and exceptional-condition status.
|
||||
- The [Decimal128 API](https://docs.rs/dec/latest/dec/struct.Decimal128.html) supports the required arithmetic and classification operations.
|
||||
|
||||
Reason:
|
||||
|
||||
- It directly implements the approved decimal128 contract instead of approximating it with a lower-precision financial decimal.
|
||||
- Context status lets Dever convert overflow, division by zero and invalid Decimal states into language-level runtime faults.
|
||||
- A reusable Context avoids the per-operation default-context overhead documented by the crate.
|
||||
|
||||
Constraint:
|
||||
|
||||
- `dec` is a safe Rust wrapper over libdecnumber and therefore introduces a native C build dependency. It must remain isolated behind `dever_runtime::number::DecimalValue`.
|
||||
- Dever conformance tests, not the crate's operator defaults or special-value surface, define public behavior.
|
||||
- A future pure-Rust replacement is allowed only when it passes the same conformance suite; this does not change `.dever` semantics.
|
||||
|
||||
Rejected for Core 0.1:
|
||||
|
||||
- `rust_decimal`: pure Rust, but its 96-bit coefficient does not provide the approved 34-digit decimal128 contract.
|
||||
- Hand-written decimal arithmetic: correct rounding, exponent handling and status behavior are too risky for the language MVP.
|
||||
- Newly published decimal128 implementations: potentially useful later, but less established than the selected reference implementation.
|
||||
|
||||
## Insertion-Ordered Map
|
||||
|
||||
Selected for the MVP: `indexmap = "=2.14.0"`.
|
||||
|
||||
Evidence:
|
||||
|
||||
- The [IndexMap project](https://github.com/indexmap-rs/indexmap) documents hash-based lookup with iteration independent of hash order.
|
||||
- The [IndexMap API](https://docs.rs/indexmap/latest/indexmap/map/struct.IndexMap.html) documents that insertion appends new keys, overwriting preserves the existing position, and order-preserving removal is available.
|
||||
|
||||
Reason:
|
||||
|
||||
- Those operations match the approved Dever Map contract without maintaining a duplicate vector-plus-index implementation.
|
||||
- Lookup remains hash based while iteration is deterministic.
|
||||
|
||||
Constraint:
|
||||
|
||||
- Dever wraps IndexMap and exposes only `get`, `put`, `remove` and `entries`.
|
||||
- Removal uses the order-preserving operation rather than swap removal.
|
||||
- Dependency-specific index access never appears in `.dever` or public diagnostics.
|
||||
|
||||
## Dependency Discipline
|
||||
|
||||
These are planned pins; the initial parser milestone has no external dependencies. Verify availability and pin each version when the runtime first consumes it. No dependency becomes a public language contract. Upgrading either dependency requires running the focused Decimal/Map conformance tests and confirming that serialized/displayed Dever values remain unchanged.
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"id": "dever-language-mvp",
|
||||
"name": "dever-language-mvp",
|
||||
"title": "Dever Language Compiler Contracts And Library Follow-through",
|
||||
"description": "N5 HTTP/2、定向性能矩阵与有界稳态/恢复压测、typed ORM 及双源码 CMS 合同修正已完成;业务 API 等用户重新设计,编译器发行/跨平台与自举仍未交付,根语言路线图保持进行中。",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": ".",
|
||||
"package": null,
|
||||
"priority": "P1",
|
||||
"creator": "Antigravity",
|
||||
"assignee": "Antigravity",
|
||||
"createdAt": "2026-09-04",
|
||||
"completedAt": null,
|
||||
"branch": "main",
|
||||
"base_branch": "main",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [
|
||||
"09-12-runtime-performance",
|
||||
"09-12-runtime-performance-p2",
|
||||
"09-12-http2",
|
||||
"09-12-http2-performance",
|
||||
"09-13-http2-ceiling-soak",
|
||||
"09-13-typed-orm",
|
||||
"09-18-cms-dual-source-contracts",
|
||||
"09-19-application-testing"
|
||||
],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "2026-09-18: HTTP/2 有界饱和扫描、128/64 MiB 各 60 秒稳态与各 100 轮重连验收完成;typed ORM 子任务也已完成。原始结果见 test/performance/README.md,历史阶段证据见 implement.md。根任务仍需单独界定发行/跨平台、自举等后续路线;未运行全量测试、操作现有服务、安装全局命令或提交。",
|
||||
"meta": {
|
||||
"planning_workflow": "trellis",
|
||||
"execution_mode": "inline"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user