Feature and wrapper declarations
Features adapt typed library calls. Wrappers transform an existing DirectSharp target at compile time. They have different jobs, and neither is required to call an ordinary .NET API. Start with normal classes and libraries; use this reference when a repeated integration benefits from a declared adapter or transformation.
The library API catalogue covers runtime contracts. This page records the compile-time source/reference contract. It does not prescribe a public C# compiler-plugin interface, metadata wire format or template registration API.
Feature declaration and effects
A feature declaration lives in ordinary .ds source or comes from referenced declarations/metadata. It selects a target and declares operations with explicit effects. The statement_rows example shows a complete synchronous feature over ordinary LINQ and a writer.
| Declaration form | Effect and binding |
|---|---|
| feature name … end feature | Introduce one compile-time feature definition, not a runtime instance/type |
| target Type | Establish the adapted source type under ordinary type binding |
| operation name(parameters) … end operation | Declare vocabulary and typed operands local to the feature |
| Nested operation | Introduce vocabulary local to its containing operation |
| calls member | Bind the ordinary library/adapter call using CLR overload resolution and inference |
| creates current | Describe the effect that creates the contextual value |
| sets current from result | Replace that value and its contextual type with the call result |
| returns result | Supply the operation result under its actual type |
| declares name as type | Introduce a typed runtime-bound symbol supplied by the adapter/environment |
| declares name as result | Infer that symbol's type from the ordinary call result |
There is one structural operation declaration. No separate source, terminal, pipeline or section declaration family is needed. An operation name such as export is feature vocabulary, not a globally reserved language statement.
Current values and captured expressions
Leading-dot access refers to the current contextual subject. Replacing current changes the type used by later dot access; it does not preserve the original receiver type secretly. When several subjects are active, name the contexts instead of making the dot ambiguous.
A captured expression binds to the delegate/expression representation the underlying API expects. The library signature carries the types. A feature does not provide an independent type checker or turn arbitrary code into an expression tree accepted by a database provider.
Declared runtime-bound symbols obtain their values at runtime from the adapter/environment. They are not compile-time runtime values. Ordinary blocks passed through operations retain normal declarations, contracts, return, cancellation and resource rules. Operation effects do not create a blanket implicit-await rule or change an imported API's return type. Apply the async intent rules to ordinary calls inside those blocks.
Discovery and cross-project use
| Step | Required behavior |
|---|---|
| Read project source | Collect its available feature declarations |
| Read known project/package references | Collect the feature declarations/metadata those references expose |
| Bind an invocation | Find one unambiguous available feature and resolve its required types/members |
| Encounter a missing definition/library | Diagnose the source use; do not silently install a package/reference |
| Encounter an unused available feature | Do not force its underlying optional library into the project merely because the feature exists |
| Encounter a name collision | Diagnose the conflicting definitions; no reference-order winner or hidden shadowing |
There is no required project or per-file feature activation list. A feature exposes its declared name; it has no special alias mechanism. Ordinary namespace/type aliases still follow their own rules. Deterministic discovery from known references is a compile-time requirement, not runtime assembly scanning.
Cross-project transport must preserve the declaration's name, target, operations/effects and type-binding information needed to apply those rules. This is a compatibility requirement, not a selected serialized field schema, file extension or public metadata API. The compiler/tooling can choose that encoding while retaining ordinary references and diagnostics.
Wrapper applications and engine selection
The following fragments assume that cached is an available wrapper definition and that the named engines are supplied through compiler/tooling references:
wrap cached with engine: scriban
An application can instead use the project's configured default:
project
default_wrapper_engine scriban
end project
wrap cached
The resolution order is exact: explicit application engine, otherwise project default, otherwise a diagnostic. An unknown/unavailable selected engine is also diagnosed. Scriban is not hard-coded as a language requirement. A required wrapper_engines registration list is not part of the grammar.
The fragments illustrate alternatives within one project; do not add a second project declaration if one already exists. An engine identifier is a compile-time selection, not a runtime object supplied by application business logic.
Source, assets and expansion boundaries
| Artifact/boundary | Contract |
|---|---|
| Feature declaration | Ordinary .ds compile-time declaration |
| Wrapper declaration | Ordinary .ds compile-time source |
| External template asset | May retain the engine's natural extension, such as .scriban |
| Binding an asset to its wrapper | Compiler/tooling detail; file presence alone does not specify that binding |
| Engine input | Restricted wrapper model/host API, not unrestricted compiler/system access |
| Engine output | DirectSharp source for normal parsing, binding and type checking |
| C# backend | Runs after DirectSharp expansion; engine output is not backend-specific C# |
| General standalone generation | Separate tooling; not silently included as a new core wrapper/generator construct |
Engine-neutral selection preserves the existing safety contract: deterministic order and identity, stable application anchors, name hygiene/collision diagnostics, recursion/cycle guards and bounded expansion. Source maps connect generated DirectSharp to its wrapper/template/application. Tooling must support inspecting the expanded DirectSharp. A template engine must not bypass the final language checks.
The external asset-binding syntax, engine-host ABI and reference-metadata encoding can be specified with the compiler/tooling. Their absence here does not authorize new source keywords, a runtime feature registry or a public plugin surface.
Diagnostics and implementation cases
| Case | Required result |
|---|---|
| Missing feature or required CLR member | Compile-time diagnostic at its use, with relevant declaration context |
| Competing feature names | Diagnostic identifying the conflicting definitions |
| Feature operation has incompatible operands/result | Ordinary type/binding diagnostic; no untyped macro fallback |
| Changed current type makes later member unavailable | Diagnose against the resulting contextual type |
| Captured query expression is unsupported by its provider | Preserve the provider/binding boundary; do not promise successful translation |
| No wrapper engine selected | Diagnostic; no implicit default engine |
| Unknown engine or unresolved declared asset | Source/tooling diagnostic; no arbitrary runtime discovery |
| Expansion cycles or generated-name collision | Enforce the established guards and identify the application/expansion |
| Generated DirectSharp is invalid | Normal language diagnostics with source-map context |
Native adapter factories, portable service APIs and private compiler encodings are separate surfaces. Use the API catalogue, the standard-library plan and the normative feature/wrapper chapters for their respective contracts. No DirectSharp compiler or engine integration has yet executed these cases in this repository.