Skip to content
A generic graph object for the CLR
C# Batchfile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
magic.node.expressions
magic.node.extensions
magic.node.tests
magic.node
.gitignore
.travis.yml
LICENSE
README.md
build.cmd
magic.node.sln

README.md

Magic Node for .Net

Build status

Magic Node is a simple name/value/children graph object, in addition to a "Hyperlambda" parser, allowing you to create a textual string representations of graph objects easily transformed to its relational graph object syntax, and vice versa. This allows you to easily declaratively create syntax trees using a format similar to YAML, for then to access every individual node, its value, name and children, from your C# or CLR code.

It is perfect for creating a highly humanly readable relational configuration format, or smaller DSL engines, especially when combined with Magic Signals. Below is a small example of Hyperlambda to give you an idea of how it looks like.

/*
 * This is a multiline comment, ignored by the parser.
 * Below is a single node, with a value of 'bar' and a name of 'foo'.
 */
foo:bar

// This is a single line comment, below is another node with an integer value.
foo:int:5

/*
 * Node with two children.
 * Notice, the value is optional, and childrne are declared
 * by adding 3 spaces in front of the child's name.
 */
foo
   child1:its-value
   child2:its-value

To traverse the nodes later in for instance C#, you could do something such as the following.

// Parse some piece of Hyperlambda from a string.
var root = var result = new Parser(hyperlambda).Lambda();

// Retrieving name and value from root node.
var name = root.Name;
var value = root.Value;

// Iterating children nodes of root node.
foreach (var idx in root.Children)
{
   /* ... do stuff with idx here ... */
}

This allows you to read Hyperlambda from files, over the network, etc, to dynamically send relational tree structures around, and serialize these in a human readable format.

Supported types

Although the node structure itself can hold any value type you need inside of its Value property, Hyperlambda only supports the following types.

  • string = System.String
  • int = System.Int32
  • uint = System.UInt32
  • long = System.Int64
  • ulong = System.UInt64
  • decimal = System.Decimal
  • double = System.Double
  • single = System.Single
  • bool = System.Boolean
  • date = System.DateTime
  • guid = System.Guid
  • char = System.Char
  • byte = System.Byte
  • x = magic.node.expressions.Expression
  • node = magic.node.Node

The type declaration should be declared in your Hyperlambda in between the name and its value, separated by colon (:). The default type if ommitted is string.

String literals

Hyperlambda also support strings the same way C# supports string, using any of the following string representations.

// Single quotes
foo:'howdy world this is a string'

// Double quotes
foo:"Howdy world, another string"

// Multiline strings
foo:@"Notice how the new line doesn't end the string
    here!"

Escape characters are supported for both single quote strings, and double quote strings, the same way they are supported in C#, allowing you to use e.g. \r\n etc.

Lambda expressions

Lambda expressions are kind of liek XPath expressions, except (of course), the will references nodes in your Node graph object, instead of XML nodes. Below is an example to give you an idea.

/*
 * Some node with some value.
 */
.foo:hello world

/*
 * Referencing the above node's value.
 */
get-value:x:@.foo

// After invocation of the above slot, its value will be "hello world".

Most slots in Magic can accept expressions to reference nodes, values of nodes, and children of nodes somehow. This allows you to modify the lambda graph object, as it is currently being executed, and hence allows you to modify "anything" from "anywhere".

An expression is constructed from one or more "iterators". Each iterator ends with a "/", and before its end, its value defines what it does. For instance the above iterator in the [get-value] invocation, starts out with a "@". This implies that the iterator will find the first node starting out with whatever follows its "@", for the above this means looking for the first node who's name is ".foo". Below is a list of all iterators that exists in magic. Substitute "xxx" with any string, and "n" with any number.

  • * Retrieves all children of its previous result.
  • # Retrieves the value of its previous result as a node.
  • - Retrieves its previous result set's "younger sibling" (previous node).
  • + Retrieves its previous result set's "elder sibling" (next node).
  • . Retrieves its previous reult set's parent node(s).
  • .. Retrieves the root node.
  • ** Retrieves its previous result set's descendant, with a "breadth first" algorithm.
  • {n} Substitutes itself with the results of its n'th child, possibly evaluating expressions found in its child node, before evaluating the result of the expression.
  • =xxx Retrieves the node with the "xxx" value, converting to string if necessary.
  • [n,n] Retrieves a subset of its previous result set, implying "from, to" meaning [n1,n2>.
  • @xxx Returns the first node "before" in its hierarchy that matches the given "xxx" in its name.
  • n (any number) Returns the n'th child of its previous result set.

Notice, you can escape iterators by using backslash "\". This allows you to look for nodes who's names are for instance "3", without using the n'th child iterator, which would defeat the purpose. Below is an example of a slightly more advanced expression.

.foo
   howdy:world
   jo:nothing
   howdy:earth

/*
 * Loops through all children of [.foo] who's names
 * are "world".
 */
for-each:x:../*/.foo/*/world
   set-value:x:@.dp/#
      :thomas was here

After evaluating the above Hyperlambda, all of your [howdy] nodes' values will be "thomas was here".

Documenting nodes, arguments to slots, etc

When referencing nodes in the documentation for Magic, it is common to reference them like [this], where "this" would be the name of some node - Implying in bold characters, wrapped by square [brackets].

License

Although most of Magic's source code is publicly available, Magic is not Open Source or Free Software. You have to obtain a valid license key to install it in production, and I normally charge a fee for such a key. You can obtain a license key here. Notice, 5 hours after you put Magic into production, it will stop functioning, unless you have a valid license for it.

You can’t perform that action at this time.