DSM & Definitions

DSM classes provide parsing and introspection of Digital Substrate Model files.

When to use: Use DSMBuilder to parse .dsm files and introspect the resulting definitions (structures, enumerations, attachments, functions).

Quick Start

>>> from dsviper import *
>>> MODEL = """
... namespace MyApp {8f14e45f-ceea-467a-9575-1c14b48f0b7e} {
...     concept User;
...     struct Profile { string city; uint16 age; };
...     attachment<User, Profile> profile;
... };
... """
>>> builder = DSMBuilder()
>>> builder.append("model.dsm", MODEL)
>>> report, dsm_defs, defs = builder.parse()
>>> report.has_error()
False
>>> defs.inject(globals())             # MY_APP_T_USER, MY_APP_A_USER_PROFILE, …

The declarations are reachable from dsm_defs:

>>> for struct in sorted(dsm_defs.structures(), key=str):
...     print(struct.type_name())
...     for field in struct.fields():
...         print(" ", field.name(), ":", field.type())
MyApp::Profile
  city : string
  age : uint16
>>> for att in dsm_defs.attachments():
...     print(att.type_name(), "-- key:", att.key_type(), "doc:", att.document_type())
MyApp::profile -- key: MyApp::User doc: MyApp::Profile

inject() fills the namespace with one constant per definition. The prefix is derived from the DSM namespace, split on camel case — MyApp gives MY_APP_, not MYAPP_:

>>> ns = {}
>>> defs.inject(ns)
>>> sorted(ns)
['MY_APP_A_USER_PROFILE', 'MY_APP_K_USER', 'MY_APP_P_PROFILE_AGE',
 'MY_APP_P_PROFILE_CITY', 'MY_APP_S_PROFILE', 'MY_APP_T_USER']

A parse that failed reports why, and hands back None for both definitions:

>>> bad = DSMBuilder()
>>> bad.append("broken.dsm", "namespace Oops { struct S { string };")
>>> bad_report, bad_dsm, bad_defs = bad.parse()
>>> bad_report.has_error()
True
>>> (bad_dsm, bad_defs)
(None, None)
>>> for err in bad_report.errors()[:1]:
...     print(err.line(), err.message())
1 expected a UUID before `{`.

Parsing

dsviper.DSMBuilder

Assembles a DSM model from several sources.

dsviper.DSMBuilderPart

One content appended to a DSMBuilder, and where it landed in the assembled text.

dsviper.DSMDefinitions

A parsed model, whole.

dsviper.DSMDefinitionsInspector

Retrieves parsed declarations by TypeName, and attachments by identifier.

dsviper.DSMParseReport

Collects the errors found while parsing the assembled sources.

dsviper.DSMParseError

One parse failure.

Model Elements

dsviper.DSMConcept

A concept as declared: its qualified name and the concept it specialises, if any.

dsviper.DSMClub

A club as declared: its qualified name and the concepts it gathers.

dsviper.DSMStructure

A struct as declared: its qualified name and its fields, in order.

dsviper.DSMStructureField

One field of a struct, as declared: its name, its type, and the value it defaults to.

dsviper.DSMEnumeration

An enum as declared: its qualified name and its cases, in order.

dsviper.DSMEnumerationCase

One case of an enum, as declared: its name.

dsviper.DSMAttachment

An attachment as declared: its qualified name, the concept it keys on, and the type of the document it holds.

DSM Types

dsviper.DSMType

A type as a parsed model declares it: the base of the declared type family.

dsviper.DSMTypeKey

The key<element_type> as a parsed model declares it.

dsviper.DSMTypeVector

The vector<element_type> as a parsed model declares it.

dsviper.DSMTypeSet

The set<element_type> as a parsed model declares it.

dsviper.DSMTypeMap

The map<key_type, element_type> as a parsed model declares it.

dsviper.DSMTypeXArray

The xarray<element_type> as a parsed model declares it.

dsviper.DSMTypeOptional

The optional<element_type> as a parsed model declares it.

dsviper.DSMTypeTuple

The tuple<T0, ...> as a parsed model declares it.

dsviper.DSMTypeVec

The vec<numeric_type, size> as a parsed model declares it.

dsviper.DSMTypeMat

The mat<numeric_type, columns, rows> as a parsed model declares it.

dsviper.DSMTypeVariant

The variant<T0, ...> as a parsed model declares it.

dsviper.DSMTypeReference

A type a parsed model names rather than spells out.

Functions

dsviper.DSMFunction

A function as declared: its prototype.

dsviper.DSMFunctionPool

A function pool as declared: the uuid it is declared under, its name, and its functions.

dsviper.DSMFunctionPrototype

A function signature as declared: its name, its parameters and their types, and what it returns.

dsviper.DSMAttachmentFunction

An attachment function as declared: its prototype, and whether it mutates the document or only reads it.

dsviper.DSMAttachmentFunctionPool

An attachment function pool as declared: the uuid it is declared under, its name, and its functions.

Literals

dsviper.DSMLiteral

What a declaration writes as a literal: the base of DSMLiteralValue and DSMLiteralList.

dsviper.DSMLiteralValue

A single literal written in a declaration: which kind it is, and its text.

dsviper.DSMLiteralList

A list literal written in a declaration: the literals it holds.

Definitions

Definitions is the registry a DSM model is loaded into: the concepts, clubs, attachments and types an application declares. Everything else on this page describes the model; these classes hold it at runtime.

dsviper.Definitions

Registers concepts, clubs, enums, structs and attachments.

dsviper.DefinitionsConst

Retrieves registered types and attachments by runtime id.

dsviper.DefinitionsCollector

Gathers the types a subset of definitions references, to hand to DefinitionsConst.extract.

dsviper.DefinitionsInspector

Retrieves registered types by TypeName, and attachments by identifier.

dsviper.DefinitionsExtendInfo

The runtime ids an extension added: what Definitions.extend or a database's extend_definitions gained from the definitions it was given, and what a synchronization added (CommitSynchronizerInfo.extend_info).

dsviper.DefinitionsMapper

Rewrites a Type, a Value or an Attachment of source_definitions into the matching declaration of target_definitions, matched by name.

Source Map

Pass a DSMSourceMap to DSMBuilder.parse(source_map=…) and the parser records, as a by-product, the exact source span of every declaration, field, case, namespace, type sub-expression and resolved type-reference. This is what makes a span-precise codemod possible: patch a hand-authored .dsm in place under a transformation — file split, comments and ordering preserved — instead of regenerating it. Opt-in; a parse without a source map is unchanged.

from dsviper import DSMBuilder, DSMSourceMap

source_map = DSMSourceMap()
report, dsm_defs, defs = DSMBuilder.assemble("model.dsm").parse(source_map=source_map)

dsviper.DSMSourceMap

A source-map collected while parsing DSM: the exact source spans of every declaration, field, case, namespace, resolved type-reference and type sub-expression.

dsviper.DSMSourceSpan

A source span: a 1-based line, and the [start, stop] character offsets into the content the builder assembled.

dsviper.DSMSourceDeclaration

A declaration - struct, enum, concept, club or attachment - with its identifier and its source spans (name, block, documentation).

dsviper.DSMSourceField

A struct field and its source spans (name, type, whole declaration, doc).

dsviper.DSMSourceCase

An enumeration case and its source spans (name, doc).

dsviper.DSMSourceNameSpace

A namespace declaration and its source spans (name, uuid).

dsviper.DSMSourceReference

A resolved type-reference site: its source span and its referent TypeName.

dsviper.DSMSourceType

A type sub-expression occurrence: its source span and its fully-qualified DSM representation - the name-based identity of a type, such as 'vector<Shop::Order>'.