Architect

From SignalWiki

A Rust library for parsing a data serialization format of the same name to Rust, and for serializing data from Rust. Designed for IPC, human readability, and code reuse.

Design

Schema

Definitions for object types. Includes structs, enums, and tuple structs. Used to make IPC more efficient, for code generation, and for error checking.

Objects

Units of data, including built-in primitive types, structs, enums, and tuples. The latter three can be either anonymous or defined.

Modules

Separate schema and objects into namespaces. Usually based on files, but modules can be declared within files for finer control. File-level modules can be referenced by other modules.

Variables

These are module-level, named objects. They are intended to be referenced by anonymous objects or other

Semantics

  • Expression: A block of tokens
  • Value: An expression that evaluates to literal data
  • Reference: An expression that evaluates to a reference to some other expression

Syntax

Meta

  • take(url)
Reference expression to data pointed to by url. Must evaluate to an expression.
  • embed_utf8(url)
Reference expression that embeds the data pointed to by the url as a str
  • embed_bytes(url)
Reference expression that embeds the data pointed to by the url as a [u8]
  • mod { <expression>, ... }
Defines a module block. Files are considered to be modules, named after their filename. May be anonymous.
  • use <ident>(::<ident>)*(( as <ident>) | (::\*))?
Imports symbols into the current scope. Asterisks import all symbols.
  • &?<expr>\[<expr>\]
Indexers copy objects from the referenced object by indexing into them. So, for example, foo["bar"] would take the object keyed "bar" from a hashmap variable named foo; lists and strings can also be indexed, using integer expressions. Modules can also be indexed in the same way as a list; this copies objects from the module's DOM. Can be made into a reference expression by prepending &.
  • &?<expr>.(<ident>|{expr})
Copies an object from a struct or tuple, similar to an indexer. If you want to evaluate the value of an ident and reference the field named after that value (instead of just referencing the field with that ident as its name), you must surround it with curly braces. Ex. foo.{bar} instead of foo.bar. Can be made into a reference expression by prepending &.

Built-In Types

Primitives

() // unit tuple
bool // true / false
u# // unsigned integers of arbitrary length >= 0
i# // signed integers
f{16, 32, 64, 128} // floating-point numbers
[T] // array
str // string

Structs

<schema ident>? (<value>, ...) // tuple
(struct | <schema ident>) { <ident>: <value>, ... } // struct


Structs & Enums

HashMap<T: Eq + Hash, T>
Option<T>

Schema

Structs & Tuple Structs

// Struct
struct <ident>\<generic type, ...\>[: <tag> + ...] {
  <ident>: <type> [! <default value>],
  ...
}
// Tuple Struct
struct <ident>\<generic type, ...\>[: <tag> + ...](<type> [! <default value>], ...);
// Unit Struct
struct <ident>[: <tag> + ...];

A unit struct is, functionally, just a tuple struct with zero fields.

Enums

enum <ident>\<generic type, ...\>[: <tag> + ...] {
  <struct def>,
  ...
}

Objects

Primitives

Same as Rust. Integers may have any length >= 0. Floats may have lengths 16 and 128, in addition to the usual 32 and 64.

Array

[a, b, c, ...]

Anonymous arrays may hold any kind of value. Schema definitions may specify a set of tags or a type to constrain possible array values.

HashMap

{ key: val, ... }

The key type must be tagged Eq + Hash. Most primitives, except floats, have these tags, and anonymous structs inherit these if all of their fields are Eq + Hash. An anonymous hashmap may contain keys and values of multiple types, in the same way as an array.

Struct

(struct | <schema ident>) { (<ident>: <expr>(, <ident>: <expr>)*)? }

Tuple

<schema ident>? \((<expr>(, <expr>)*)?\)

Enum

[<enum type>::]<variant>[<definition block>]

Ex:

Option::Some(5)
None
Foo::Bar { Baz: 5 }

The enum type identifier is only necessary if the variant identifier hasn't been imported into the current scope.

Module

Deserialization

Architect is designed to be deserialized directly into specific types, but it can also be deserialized into a generic DOM. In Rust, this is represented as:

struct Module {
  id: String,
  modules: HashMap<String, Module>,
  vars: HashMap<String, Object>,
  schema: HashMap<Type, Schema>,
  objects: Vec<Object>
}

See Also