Appendices
A. Language vocabulary
Keywords are case-insensitive. Canonical source uses lowercase. An indivisible multiword token uses snake_case; compositional grammar keeps independently meaningful words separate. end if is a closing keyword followed by a construct qualifier, not end_if. Escaped identifiers use @ where a name would otherwise conflict with language vocabulary.
The tables group vocabulary by its language role. A word's appearance in a contextual grammar does not make an arbitrary .NET member with that name a globally reserved keyword.
| Area | Canonical vocabulary |
|---|---|
| Source organization | project, root_namespace, auto_import_directsharp, namespace, import, alias, Global, default_wrapper_engine |
| Types | class, data, interface, enum, flags, class kind, inherits, exposes, implements, is, of, one of |
| Generic restrictions | where with inherits, implements or the contextual phrase has constructor |
| Indexer property modifiers | virtual, override, abstract on property [parameters]; action modifiers retain their own rules |
| Access and member modifiers | public, private, protected, internal, static, readonly, abstract, overridable, overrides |
| Construction | new, constructor, with, properties, fields, arguments, self |
| Actions and callables | action, returns, return, yields, yield, from, call, async, await |
| Declarations and values | let, let_if, outer, const, constants, nothing, default, true, false, lazy, as |
| Conditions and selection | if, then, else, elseif, select, case |
| Enumeration | for_each, in, where, consume, from |
| Ordinary loops | for_each, range, to, step, where, order_by, skip, take, while, repeat, times, forever, until, continue |
| Loop exits | break, continue, exit, for as the target in exit for; with name: identifier names an enclosing loop for break/continue |
| Statement destinations | mark identifier, goto identifier |
| Exception handling | try, catch, finally, throw, retry, try_get, LastAttempt |
| Contracts | require, ensure, otherwise, result, old_value_of |
| Receiver and resource scopes | use, use_if, using, take, dispose, block, end |
| Conversion and copying | convert, tryconvert, conversions, implicit, from, to, copy_of |
| Concurrency | concurrent, all, first, any, run, returns, limit, timeout, collects, collect, task_of, enter, leave, atomic |
| Events | event, add_handler, remove_handler, raise_event, handles_event |
| Services | needs, replaceable, services, provide, another, all, singleton, scoped, transient, key |
| Metadata | attributes, assembly, description |
| Extension/adapters | extension, feature, target, operation, calls, creates, sets, current, captured, expression, context, declares |
| Wrapper application | wrap, engine |
| Boolean and numeric operators | not, and, or, div, mod, checked, unchecked |
| Case-explicit equality | eq_case_sensitive, not_eq_case_sensitive |
| Type/identity predicates | is a, is exactly, is same_as and applicable is not forms |
| Absence/state predicates | is nothing, is empty, is whitespace, is initialized, is working, is faulted and their negations |
| Text/pattern predicates | ascii, numeric, integer, decimal, iso_date, containing, starting_with, ending_with, parsable_as, like, match and applicable _case_sensitive forms after is |
| Flag operations | has_flag, has_not_flag, set_flag, clear_flag, toggle_flag |
| Compiler context | __compiler__ and its compiler-defined members |
| Preprocessing | #if, #elif, #else, #endif, #ifdef, #ifndef, #define, #define override, #undef, #include |
Gate, IConsumable<T>, IConcurrentConsumable<T>, ILiveConsumable<T>, Consumables, ServiceProvider, ServiceScope, ServiceScopeFactory, MainServiceProvider, Chars, Unicode and ordinary type names such as String belong to type/library binding. GetService, RuleFor, NotEmpty, AddDbContext, WriteLine and SaveChangesAsync are APIs, not newly reserved language statements.
Retired forms must not be inferred from this inventory. Current source uses constructor rather than on create, for_each rather than for each, try_get rather than tryget, and contract otherwise rather than or throw. Core does not define deep_copy_of, has_any_flag, has_no_flag, is default, a validation keyword DSL, a project feature-activation block or a standalone generate construct.
B. Operator binding
Parentheses explicitly group expressions without changing once-only operand evaluation in source order. The following groups are ordered from highest to lowest binding:
| Expression family | Binding/associativity |
|---|---|
| Primary access/calls/indexing; postfix increment/decrement | Forms a value before surrounding operations |
Unary numeric +/-, complement ~, prefix increment/decrement, await |
Apply to their immediate operand; await requires an awaitable |
*, /, div, mod |
Left-to-right |
Binary +, - |
Left-to-right |
Shifts <<, >>, >>> |
Left-to-right; supported operand types only |
Relational <, <=, >, >=; all is/is not predicates |
Above equality, including identity, regex and like patterns |
Equality =, <>, eq, not_eq and explicit case variants |
Left-to-right in expression context |
Bitwise & |
Above bitwise ^ |
Bitwise ^ |
Above bitwise \| |
Bitwise \| |
Above Boolean not |
Boolean not |
Below comparisons/equality/predicates/bitwise; above and/or |
Boolean and |
Left-to-right; short-circuit |
Boolean or |
Left-to-right; short-circuit |
?? |
Right-associative; short-circuit |
| Assignment/compound assignment statements | Statement context only; chains use simple writable locals/parameters and right-to-left writes |
convert operand to T consumes one immediate operand; its completed conversion binds strongly as defined in chapter 8. It does not absorb surrounding arithmetic without parentheses. Normal binary operators associate left-to-right unless specified otherwise; this table does not admit invalid operand types or general mathematical comparison chains. Predicate-local type/pattern grammar remains governed by its construct rules.
let total = convert (subtotal + tax) to Integer
let next = (convert amount to Integer) + 1
let eligible = not (balance > limit) and isActive
Composite conversion sources require parentheses. Bitwise/comparison/predicate combinations should use parentheses wherever grouping would otherwise obscure the intended operation. Assignment is a statement-context operation, not a freely nestable C-style assignment expression.
C. Predicate contracts
| Predicate | Accepted subject | Meaning and important boundary |
|---|---|---|
is nothing |
Absence-capable value | Exact absence |
is empty |
Applicable value/collection | Absence, effective default where meaningful equality exists, or no sequence elements |
is whitespace |
String | Null/empty/whitespace test corresponding to IsNullOrWhiteSpace |
is a T |
Runtime type-compatible subject | Assignability and permitted flow narrowing |
is exactly T |
Runtime-typed subject | Exact runtime type rather than assignability |
is same_as |
Reference subjects | Reference identity rather than value equality |
is in |
Applicable membership source | Membership under the source's supported semantics |
is like |
String or supported ordered/indexable sequence | Wildcard/sequence pattern matching |
is match |
String | Ordinary .NET regex matching with default case policy |
is initialized/working/faulted |
Language lazy value | Nonforcing state inspection |
has_flag/has_not_flag |
Flags enum | Flag-condition presence or logical negation |
is ascii |
String | Characters/code units within ASCII range |
is numeric/integer/decimal |
String | Approved input shape plus finite Double/Long/Decimal range respectively; Boolean only |
is iso_date |
String | Narrow culture-independent valid yyyy-MM-dd calendar date |
is containing/starting_with/ending_with |
String | String relation with deterministic default case policy |
is parsable_as T |
String with supported target parsing contract | Boolean parse capability rather than a converted result |
Scalar defaults count as empty: 0, false and Guid.Empty are examples. String absence and "" are empty; " " is not empty but is whitespace. A non-absent collection with zero items is empty without requiring equality to a particular empty collection object. Enumerable emptiness may probe enumeration; an efficient non-enumerating check is permitted where observably equivalent.
An ordinary reference type with no meaningful non-absent default/equality contract is empty only when absent. No structural equality is invented for this test. value = default is the contextual default comparison; is default is not a current predicate.
is not negates an applicable predicate. Explicit _case_sensitive String forms override the normal case-insensitive comparison for their operation; they do not change identifier binding. Built-in predicates are distinct from recognized Boolean Is*/Has* members, which still bind as normal APIs. Email, IBAN, JSON and telephone policies belong in libraries.
D. Conversion contracts
| Source/target relationship | Supported path | Failure boundary |
|---|---|---|
| Identity/assignable value | Ordinary assignability or convert |
Static incompatibility diagnosed |
| Runtime reference/interface | Runtime compatible conversion | tryconvert can report ordinary mismatch as absence |
| Valid boxing/unboxing | CLR type rules | Preserve runtime compatibility failures |
| Numeric conversion | Applicable .NET-style conversion | Narrowing warning; overflow follows checked policy |
| Nullable lifting/unwrapping | Supported optional conversion | Preserve absence; conversion does not imply default |
| String to recognized parse target | Literal context or explicit conversion | Invalid recognized literal diagnosed; runtime input can fail |
| String to one-String-constructor type | Direct named-target construction | User constructor executes at runtime |
| String to enum | Case-insensitive declared name | Unknown name is failure |
| Number to ordinary enum | Value must identify declared member | Undeclared value is failure |
| Number to flags enum | In-range underlying bit pattern | Preserve unknown bits; out-of-range is failure |
| Imported user conversion | Actual CLR implicit/explicit operator | Preserve its side effects and exceptions |
| Authored conversion | One applicable from/to contract |
Ambiguous candidates diagnosed |
| Safe authored/recognized conversion | tryconvert with genuine safe protocol |
Ordinary inability yields absence; unexpected exceptions propagate |
A conversion selects one recognized step. It does not search A→B→C chains, serializers, TypeConverter, unrestricted reflection or arbitrary Convert.ChangeType fallbacks.
Target-typed String literals may initialize recognized targets or satisfy unambiguous parameters. An arbitrary runtime String does not implicitly parse merely because assignment has a target type: use text as T or convert text to T. One accessible exactly-one-String constructor can participate in direct construction; compiler selection does not execute that user constructor during compilation.
Explicit target-typed fractional-to-integral narrowing truncates toward zero and warns about possible loss. This does not silently add lossy conversions to unrelated overload resolution. Untargeted fractional literals infer Decimal. Integer-operand / yields a fractional Double result; div truncates its quotient toward zero.
tryconvert is not try_get convert: the former requires a real safe protocol; the latter explicitly catches normally catchable computation failures. Ordinary culture-stable conversions use recognized deterministic contracts. Explicit .NET Parse/TryParse APIs remain available for application-specific culture, styles and format policy.
E. Construct grammar summary
These shapes describe already-defined constructs. Brackets denote optional grammar, braces repeated grammar and capitalized labels syntactic categories. They are notation rather than literal DirectSharp source.
Project := project { ProjectSetting } end project
AutoImport := auto_import_directsharp (true | false)
Action := [Access] [async] action Name(Parameters)
[returns Type | yields Type] Body end action
Await := await UnaryExpression
TaskCapture := task_of(Expression)
Constructor := [Access] constructor(Parameters) Body end constructor
Class := [Access] class Name [GenericParameters] [ClassHeader]
{ Member } end class
InterfaceBody := implements Interface { Member } end implements
ClassKind := [Access] class kind Name [GenericParameters]
{ KindContribution } end class kind
Extension := extension Type { ExtensionAction } end extension
If := if Condition then Body { elseif Condition then Body }
[else Body] end if
Enumeration := [concurrent] for_each Binding in Source [LoopInputs]
Body end for_each
Consumption := [concurrent] consume Binding from Source [LoopInputs]
Body end consume
Concurrent := concurrent (all | first | any) [PublishedResults]
[with Inputs] Body end concurrent
RunCall := [ResultBinding =] run Invocation
RunBlock := [ResultBinding =] run Body end run
GateRegion := enter Expression [with Inputs] Body leave
AtomicRegion := atomic Body end atomic
AtomicSwap := atomic swap(Location, Location)
Extraction := let from Expression { ExtractionLocal } end let
ConditionalExtraction := let_if from Expression { ExtractionLocal } end let_if
ExtractionLocal := Identifier [ as Type ] = Expression
Needs := needs { NeedDeclaration } end needs
Services := services Name [Parameters] Body end services
Using := using ResourceDeclarations Body end using
Use := (use | use_if) Expression [Refinement] Body end (use | use_if)
TryGet := try_get Expression | try_get Body take Expression end try_get
Metadata := attributes AttributeList | attributes { Attribute } end attributes
Description := description String
Full type/member/pattern/parameter rules in the chapters constrain these shapes. The notation does not permit every combination mechanically: resource ownership, async ABI, legal attributes, constructor placement and supported concurrent sources still apply. Qualified endings verify the construct they close. Keyword normalization does not fuse closing qualifiers.
An applicable generic declaration places its parameter list after the declaration name and its restrictions in the header. The Action shape above is the nongeneric case; generic actions use that same callable/result model with these additional pieces:
GenericParameters := < of Identifier { , Identifier } >
GenericArguments := < of Type { , Type } >
GenericConstraint := where Identifier
( inherits Type | implements Type | has constructor )
These angle brackets are literal delimiters in the source. Commas separate parameters/arguments; each nested constructed type has its own list. Chapter 4 defines the legal CLR restriction boundary, and the generic reference shows complete declarations.
F. Required diagnostic conditions
The specification names conditions rather than inventing implementation diagnostic numbers.
| Area | Required diagnostic examples |
|---|---|
| Lexical/names | Invalid identifiers; case-insensitive duplicate symbols; mismatched endings |
| Declarations | Uninitialized ordinary local; duplicate effective project; illegal access/modifier |
| Binding/types | Inaccessible member; ambiguous import/overload/conversion; violated generic constraints |
| Values | Writable operation on readonly/lazy storage; unsupported implicit runtime String conversion |
| Selection/contracts | Missing expression result path; invalid take; invalid snapshot source |
| Construction | Abstract construction; inaccessible constructor; missing required need |
| Resources | Ownership-taking disposal of known borrowed needs/services |
| Async | Fresh awaitable call without await/task_of/run; suspension in a fixed synchronous contract; unavailable Cancellation; incompatible imported contract |
| Async warnings | Locally provable captured-operation abandonment; capture-only try/catch does not observe later failure |
| Concurrency | Nonpositive limit; statically producer-free first/any; premature result use; return across an iteration boundary; provable shared write; run without an owner; missing/incompatible inline branch result; control transfer out of a run body |
| Atomic | Unsupported atomic operation; explicit/implicit suspension in atomic block |
| Consumption | Unsupported source; raw database-reader concurrent consume |
| Events | Incompatible handler; external raise; untrackable declarative event source |
| Services | Invalid key match; dependency cycle; singleton path to scoped service |
| Metadata | Invalid attribute target/arguments; declaration metadata on unsupported item |
| Features | Unavailable feature/library; conflicting feature names; forbidden generation |
| Wrappers | Missing/unknown engine; unsupported target; recursion; invalid expansion/name collision |
| Preprocessing | Undefined live substitution; conflicting definition; missing/non-replaceable override target; malformed include literal; include cycle/path escape |
Warnings/analyzers address cases that cannot be statically proved, such as imported aliases hiding shared mutation or opaque registration graphs. A diagnostic must explain the actionable source condition and preserve relevant DirectSharp locations. Backend compilation success does not excuse accepting a source program whose language contract requires rejection.
G. Library contracts referenced by the language
The language's required library relationships are distinct from grammar and from optional conveniences.
| Contract | Required behavior |
|---|---|
| Gate | Named async-capable capacity; structured acquisition/release; acquisition timeout |
IConsumable<T> / ConsumeResult<T> |
Awaitable acquisition with item presence separate from normal completion; failures propagate |
IConcurrentConsumable<T> |
Custom source capability for overlapping acquisition and valid acquired items, without blanket payload thread safety |
| Reader adapters | Ephemeral current record, current-result-set-only consumption, no concurrent raw cursor |
| Service provider/scope/factory | Explicit scopes, required/eager multiple retrieval, exact non-null keys, borrowed ownership |
ServiceNotFoundException |
Missing required registration; InvalidOperationException subclass with requested ServiceType and exact nullable ServiceKey |
| Lazy runtime support | Once-only safe publication, cached absence/failure, nonforcing state, recursion detection |
| Concurrent result support | Structured ownership, whole-iteration limits, ordered publication and producer identity |
| Text/conversion support | Deterministic language formatting/parsing contracts and normal CLR interoperability |
| Source/diagnostic support | Source correlation through includes and expanded programs |
Application-facing APIs use the DirectSharp namespace. The implementation is largely C#/.NET and may use a small required runtime assembly. The language does not prescribe an invented final interface signature for every helper: an API must implement the observable contract while preserving ordinary .NET compatibility. Optional mapping, serialization, copying and framework adapters remain separate packages/capabilities.
H. Version and backend scope
This specification describes the DirectSharp v1.0 core design and its initial .NET/C# backend relationship. The language semantics are independent of a particular SDK, runtime release or editor.
Source semantics, CLR representation and compiler/runtime package versions are separate compatibility concerns. A reference C# example illustrates semantics within its shown context; it is not a universal promise about all historical .NET targets. Imported libraries keep their own versioned API contracts. Optional libraries/features do not become core language guarantees merely by being available through a reference.
Specification contents · Previous: 28. Reference C# lowering