Expressor - A structured scripting language based on YAML syntax

Expressor is currently a library in progress that I am working on to aid in structuring objects.

Currently, the project is just a concept and has not been completed yet (I may need some help polishing it up, as well). You can view the code here.

The basic syntax is similar to YAML, and is as follows:

// This is a comment

bitmap = new Bitmap(Assets.getBitmapData("img/haxe-logo.png"))

sample = new Sprite()
    x = 30
    y = 30
    addChild(bitmap)
    graphics
        beginFill(0xFF0000)
        drawRect(0, 0, 50, 50)

I’m thinking of using this library as the subject for learning Haxe macros and have a separate Parser that also generates code at compile-time.

You may have also noticed the graphics block.

That very code would generate to:

sample.graphics.beginFill(0xFF0000);
sample.graphics.drawRect(0, 0, 50, 50);

This ultimately speeds up programming by introducing the concept that every member variable is part of a data hierarchy.

When it eventually works, this is how you would use it in your project:

import expressor.Parser;

class Main extends Sprite
{
    public function new()
    {
        super();

        var parser = new Parser();
        if (parser.parse("path/to/script.doe"))
            parser.execute();
        else
            trace(parser.error);
    }
}

If this is any indication, any time you want to do anything remotely complicated, you’ll have to type out the Haxe code for it. Without code completion or syntax highlighting.

And if you’re happy typing out that much code, you might as well type out “new” in front of Bitmap. That will make it much easier to feed into HScript’s parser, and open up the option of a static method call.


It’s cool if you’re trying to simplify Haxe code, but while you’re still in the design stage, you should review the similar projects out there.

First, HaxeUI does something very similar using XML, including the part where it uses HScript to run arbitrary Haxe code. I assume you’re already aware of this one, but I’m mentioning it just in case.

Second, Tinkerbell Template can (among other things) generate Haxe code from source data. Its intended use is different, but you’ll want to check out how it uses macros and what features it supports. (Actually, just use Tinkerbell Syntax Hub for the macros. No need to reinvent the wheel here.)

Finally, there’s Groovy, the logical conclusion of a project like this. (Except it’s for Java, not Haxe.) If your goal is to make a full-fledged replacement language, then use Groovy for ideas. In fact, you should download it, try it out, and keep track of what you liked and didn’t like.

//HelloWorld.java
public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

//HelloWorld.groovy
println "Hello, world!"

Haxe uses this instead of self. I strongly suggest following Haxe’s convention.

While I’m at it, you should support // comments. This library will be used by Haxe programmers, and your goal is to be as intuitive as possible. (That said, it’s up to you whether to support /* */. There are practical reasons why it might not work.)

That’s two different ways of doing the same thing. And the second way can duplicate the results of the first:

sample : Sprite
    :x = 30
    :y = 30
    :addChild(bitmap)

Which means there’s no need for the first option to exist. And once you take it out, you can simplify the syntax:

sample = new Sprite()
    x = 30
    y = 30
    addChild(bitmap)
    graphics
        beginFill(0xFF0000)
        drawRect(0, 0, 50, 50)

Technically, that isn’t data-driven programming.

What you have here is a way to simplify Haxe’s syntax, which in turn makes data easier to enter. Entering data easily is a totally valid goal, as is separating data from logic. However, neither of those things are what people mean by “data-oriented programming.”

Anyway, if this is really about data, then I think you should start small. Implement this as an extension to HaxeUI. Specifically, implement it as an alternative to XML.

Why? Because HaxeUI already has something very similar, with all the details worked out. You’ll have something to refer to whenever you run into a stumbling block.

You don’t have to stop after implementing this extension. It’s just the logical first step. It’ll be relatively simple to implement while still being useful in the end, because HaxeUI’s code will tell you what to focus on.

Once you finish, you can expand your focus beyond UI, but you’ll have a solid, working base.

I was referring to this article when explaining my point:

Also, my main aim for this project is simply experimentation. I might not even finish it but it’s interesting to experiment and learn new things.

Ah. It looks like “data-oriented design” is different from “data-driven programming.” (Unfortunately, the latter is what came up when I searched for “data-oriented programming.”)

But in any case, what the article describes is different from what you’re implementing. The article is talking about how data is stored in memory while the program is running, not so much about how you input that data.

Example from StackOverflow:

//Object-oriented
class Ball {
  Point  position;
  Color  color;
  double radius;

  void draw();
};

//Data-oriented
class Balls {
  vector<Point>  position;
  vector<Color>  color;
  vector<double> radius;

  void draw();
};

Think of how you put a bunch of data in a single array when using the Tilesheet class. Because it’s contiguous in memory, the Tilesheet class can load it efficiently, which speeds things up. That’s the main idea behind data-oriented design.

You’re still creating individual Sprite and Bitmap objects, which is the opposite of what data-oriented design suggests. However, the article accepts that OOP is appropriate for UI elements, which is what you’re doing. And I’m not trying to discourage you either. I just want to clarify some terminology.

Absolutely.

I’d still suggest doing the extension for HaxeUI, because that’s a clearly-defined goal. That way, you get the satisfaction of finishing a project, rather than the mixed feelings of saying “I guess I’ll stop here.”

(Also, HaxeUI could use an importer like the one you described. XML is unnecessarily complicated.)

Okay, perhaps it’s better to say it’s “a design concept that aids in structuring objects in a tree-like fashion”.

Not data-oriented. It is built on top of HScript, so it would simply be the case of passing variables to use certain parts of a framework, like HaxeUI, so it’s more of a generic solution to speed up runtime scripting rather than a specific solution for a specific framework.

YML … cool that should be haxelib

YAML, actually. YML is something else.

And I’m going to try and implement a partial YAML parser this weekend. It’s more complicated than JSON, so I don’t expect to be able to implement everything by then. Watch this repository to see my progress.

I did notice already a YAML parser on Github and on Haxelib which I downloaded and took a look at before designing Expressor. It was a bit more complicated than I liked it to be so I just decided to implement my own.

Also, Expressor isn’t going to follow all conventions of YAML, quite literally just the structure of it.

Not all of the features I want it to have are currently implemented.

You can always use haxelib git expressor https://github.com/tienery/Expressor.git to download the latest build and use it in your projects.

Guess I should have taken five seconds to search before posting about my plans. Oops!

It doesn’t look that bad, and you can make it simpler if you want. Make a function like this:

public static inline function parseYaml(data:String):Dynamic {
    return Yaml.parse(data, Parser.options().useObjects());
}

Then you can use it like you’d use Json.parse():

var yaml = parseYaml("hello: world\ntwo: 2");
trace(yaml.hello); //world
trace(yaml.two + 2); //4

var json = Json.parse('{"date":"2016-03-05", "three":3}');
trace(json.date); //2016-03-05
trace(json.three < 4); //true