DC Reference
From Create Wiki
dC (Create data) is a language meant to make writing Create Framework applications as quick as possible.
Contents |
Introduction
dC is a data specification language. This means that it allows you to define objects.
dC is both typed and non-typed. This is because there are two kind of types in dC: native types, and object types. A native type is a type which is defined in C++ (or, possibly, in another language). An object type is not really a type, but an object, which may be "inherited" from to create objects of that type.
This leads to great flexibility.
The Basics
dC is a simple language. It has a few basic items:
- Primitives. These include strings, numbers, booleans, and names.
- Arrays. These are collections of primitives, other arrays, structures, or definitions.
- Structures. These are simple key/value mappings.
- Definitions. These define objects. They may contain any number of primitives, arrays, structures, or other definitions. In the global scope, definitions must be named. Outside of the global scope, they must not be.
Here's an example using all of the above:
//first, a definition, defining an object of type Frame, named myFrame: (Frame) myFrame: [ //providing the definition with an array. (Frame) [ 1 1 5 5 ] // another frame. This one has no name, but has //an array passed to it specifying the position and size. //it only ends when it sees a semicolon or comma, so it is still there. { //we are now inside a structure //you can add fields like this: myName: some-name-value, //or, if you prefer semicolons... myNumber: 25; myBoolean: true; } ];
Elements
Primitives
String
The String primitive represents a standard (ASCII) string. This isn't to say you can't put UTF-8 values inside, just that dC won't get it. The application using dC might, though.
Strings are surrounded by quotes. Inside, they may have a few escaped characters: \r represents a carriage return, \n represents a newline, and \t represents a tab. For any other character following a slash, that character is written (the slash itself being skipped). This allows you to write \\, and get a single backslash.
Quotes may be either single or double, but both start and end quotes must match.
//sample string with a newline character at the end: "Hello, World!\n"
Number
The Number primitive represents a double-precision floating point number. Numbers may be made up of any character from 0-9, -, and .
Nothing else is allowed currently, but that could change.
//sample numbers: 9.5 .144 -52.34
Boolean
A boolean has two possible values: true and false. In dC, you may specify either of these two values in four possible ways:
- true, false
- TRUE, FALSE
- yes, no
- YES, NO
In short, true, false, yes, and no all work, in either all caps or no caps. No partial caps allowed, however. Sorry, Python users.
The safest are true and false, as they are truest to convention.
//example booleans true, false, TRUE, FALSE yes, no, YES, NO
Name
A name is a bit like a string. However, it is not marked by a beginning or ending quote, or anything else; it just is.
A name can be anything starting with an alphabetic character, a dash, or an underscore, and may contain any alphanumeric characters, dashes, and/or underscores.
The parser currently does support names starting with numbers, but this is not officially supported. If it ever becomes convenient, this may be removed.
//example names hello-world, hello_world, HelloWorld, _helloWorld, -55-in_iron_pen
Arrays
An array is a collection of other items. An array starts with a left bracket [, and ends with a right bracket ].
Items in the array do not need to be delimited. If you wish, you may put semicolons or commas in to delimit the items. These are simple "end" instructions, meant to end definitions, that have no effect outside of a definition itself.
dC tells them apart because it knows when they begin and end. Primitive children are easy to tell apart, as they are each one item. Other arrays are similarly easy, as they end on the right bracket ]. Structures end on a right }. Definitions always end with an semicolon or comma. In this scenario, the semicolon or comma is not technically a delimiter, as it is a simple instruction to the definition to end.
//example arrays [1 5 9 5] [1, 5, 9, 5] [1; 5; 9; 5;] //please don't do this (though it is perfectly supported). It's confusing. [1, 5 9 7] [1, 5; 7 9] //and something more complicated [ 1, { "test": 5 }, true, (RGBColor) 0 1 0, SomeObject]
Structures
Structures are key/value maps. They are very simple. They begin with left brace {, and end with right brace }. They have multiple key/value pairs, which should be delimited (although the current parser does not require it) by semicolon or comma. The semicolon and comma are not technically needed by the parser, as it knows when objects begin and end, but should always be there, just because the list could look confusing without some form of set delimiter.
Each key/value pair has a key (which may be a name or a string) and a value (which may be any kind of object: primitive, array, another structure, or a definition). They are separated by a simple colon.
//example structure { key: value, another-key: "another value"; "another-key": (RGBColor) 1 0 1; }
Advanced
Namespaces
Namespace functionality is largely in-development at the moment, and may not work Namespaces in dC are, at their core, fancy object names. Consider:
(Frame) MyNamespace.MyObject;
That is simply an object name with a dot in it.
But things are a bit more elegant than that. Although that is all a namespace technically is in dC (keep it simple!), there are several areas where dC helps out. For instance, there is a processor directive you can give dC to tell it to make all definitions after that point be in a specific namespace. There is another to add namespace "search paths" in which dC should look for objects.
Namespace Directive
The first helper is the namespace directive. It is used very simply:
#namespace My.Namespace.NameNote that this only applies within the current file:
#namespace My.Namespace.Name //things here are under My.Namespace.Name #include "some-file.dc" //things in this file are NOT //things here are //things in file including this one WILL NOT BE
To go to a clean namespace (no namespace), use:
#namespace;Discrimination
Discrimination is a technique where you force enclose an included file into a namespace. This feature has not been fully planned yet. It may work something like this:
#include :Discrimination.Namespace "file.dc"
This is useful if you believe the included file either does not namespace properly on its own, or will interfere with your own namespace.
Implied Scope
As mentioned above, sometimes search paths are added automatically. There are a few instances where this occurs.
Consider:
#namespace Postcards.Framework (Frame) Postcard: [ // inside the postcard definition, Postcards.Framework (the "parent" namespace // of Postcard itself) is automatically included. (Postcard.Postal); (Postal); //so is Postcard itself. (Framework); //does not work. Any higher levels are NOT auto-scoped. ];
The Scope List for Postcards.Framework.Postcard is:
- Postcards.Framework.Postcard
- Postcards.Framework
- (global namespace)
Now, consider an object inheriting from Postcard:
#namespace; //in global namespace (Postcards.Framework.Postcard) myPostcard; (Frame) Postal; //replaces Postcard's instance of "Postal" //does not, however, replace its instance of Postcard.Postal. //search paths never search within each other. (Frame) Postcard.Postal; //replaces Postcard's instance of Postcard.Postal. (Frame) myPostcard.Postal; //replaces Postcard's instance of "Postal" //does not, however, replace its instance of Postcard.Postal. //search paths do not search within each other. (Frame) myPostcard.Postcard.Postal; //replaces Postcard's instance of "Postcard.Postal"
The scope list for myPostcard, inheriting from Postcards.Framework.Postcard, will be:
- myPostcard
- (global namespace)
- Postcards.Framework.Postcard
- Postcards.Framework
- (global namespace)
The order is pretty simple (examples are for an object named Postcard.Postal:
- Argument Namespace Imports.
- Namespace of Object (Postcard.Postal).
- Object's Namespace's Parent (Postcard).
- For items inside object's definition: active scopes (from #with directive)
- Namespace of object's base (Create.Print.Frame if Postal is based on Frame).
- Base's namespace's parent's namespace (Create.Print)
- For items inside object's base definition: active scopes (from #with directive)
- Global Namespace.
Note that the inclusion of active scopes only applies to the definition in which the scopes are active. You cannot use #with myNamespace from a derived definition and expect the base's reference to SomeObject to match myNamespace.SomeObject. The SomeObject object type will have to be defined in one of the namespaces that would be in scope, or you will have to use Arguments.
Chance of Collision
The chance of collision is low. The most likely area where collisions could occur would be between object types and instances; however, instances are usually (by convention) named with lower case letters, while object types are named with upper case letters.
In all other instances, the inheritance of scopes is mostly controlled. Even if you use the #with directive to import a scope, these scopes are the last ones in line.
Arguments
In development, so may not work Arguments may be passed to objects. Arguments may only be objects, as it works by simply defining aliases for objects. Arguments may be simple aliases (one-to-one maps), or an entire namespace import.
Example:
(Frame) Postcard: [8.5 5.5] [ Postal; //include postal directly (Postal) { right:.25; top:.25; }; //or define a new version at a specific place. ]; (Frame) My.Postal: [1 1] /* Some definition here */; //first way: direct alias (Postcard Postal:My.Postal) My.Postcard; //second way: namespace import (Postcard :My) My.Postcard;