Architect
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 offoo.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> }