Skip to content

Instantly share code, notes, and snippets.

@triplefox
Created December 4, 2014 11:59
Show Gist options
  • Save triplefox/d6560bb694a06a138ce8 to your computer and use it in GitHub Desktop.
Save triplefox/d6560bb694a06a138ce8 to your computer and use it in GitHub Desktop.
package com.ludamix.ds;
class Deli
{
/*
Deli - "Better than your usual hashmap"
A syntax that maps text data to lists of numbers and strings by declaration,
vs. by position and context as in most textual formats.
Deli data is primarily intended as a human-editable source format and an efficient means
of describing deeply nested structures. It does not aim for reproducability after processing.
Syntax:
Linebreak-delimited.
Lines starting with @ describe enumerated schema keys of integers:
"@<name>(=value),<name>(=value)..."
@wall, floor, start, end // 0, 1, 2, 3
@GREEN_KEY=100, RED_KEY, BLUE_KEY // 100, 101, 102...
Lines starting with a number or name describe data.
"<key>.<key>...=<type><data>
message.0=$hello
message.1=$goodbye
Data types:
$ - string
# - number
@ - schema key
Tricks:
A schema can refer to a previously declared schema.
@red, green, blue, scarlet=red // scarlet = 0
A schema actually contains an array of integers, making this valid:
@nested=0.0.0
nested=$i am in 0.0.0
Likewise:
@nested=0.0.0
nested=@nested // [[[[0,0,0]]]] - a way to store an integer array
You can mix in schema keys with indexes in an arbitrary way:
patch.0.part.1.envelope.0.attack=#0.3
*/
public static function parse(s : String) {
var r /*result*/ : Array<Dynamic> = [];
var m /*mapping of name to enumerated idx*/ = new Map<String, Array<Int>>();
var li : Int = 0;
var flat /*flatten schema keys*/ = function(ka : Array<String>, l : String) : Array<Int>
{
var kia = new Array<Int>();
for (n in 0...ka.length)
{
if (ka[n].length == 0) throw 'line $li: contains extraneous ".": $l';
var idx = Std.parseInt(ka[n]);
if (idx == null) { /*fallback to schema search if it can't parse an int*/
if (m.exists(ka[n])) { for (j in m.get(ka[n])) kia.push(j); } /*concat*/
else throw 'line $li: key not found "${ka[n]}": $l';
}
else kia.push(idx); /*concat*/
}
return kia;
}
for (l /*line*/ in s.split("\n")) { li += 1;
if (l.charAt(0) == "@")
{
var idx /*enumeration start point*/ : Dynamic = 0;
var i /*enumeration counter*/ : Int = 0;
var sa /*schema array*/ = l.substr(1).split(",");
for(sc in sa) {
var eq = sc.split("="); eq[0] = StringTools.trim(eq[0]);
if (eq.length == 1) { m.set(eq[0], [i + idx]); } /*ordinary incrementing enum*/
else { /*fancy traversal*/
var kia /*key index array*/ = flat(eq[1].split("."), sc);
idx = kia[0]; i = 0; /*reset the counter to start incrementing from the indicated base*/
m.set(eq[0], kia);
}
i += 1;
}
}
else
{
var i0 = l.indexOf("=");
var kia /*key index array*/ = flat(l.substr(0, i0).split("."), l);
var cur = r;
for (n in 0...kia.length)
{
var idx = kia[n];
if (n < kia.length - 1) /*all but the last entry needs to populate a new array*/
{
if (cur[idx] == null) { cur[idx] = []; } cur = cur[idx];
}
else /*set data*/ { var v = l.substr(i0 + 2); var t = l.charAt(i0 + 1);
switch(t)
{
case '@': /*use enum value*/ v = StringTools.trim(v);
if (m.exists(v)) { cur[idx] = m.get(v);
/*reduce single enums to ints*/ if (cur[idx].length == 1) cur[idx] = cur[idx][0]; }
else throw 'line $li: key not found "$v": $l';
case '$': /*use string value*/ cur[idx] = v;
case '#': /*use number value*/ cur[idx] = Std.parseFloat(v);
}
}
}
}
}
return {m/*mapping*/:m,d/*data*/:r};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment