yyd 0.2.0

y.Yd - Template and mixin combinators for parsers and yy routing


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:

y.Yd - Mixin template combinators for D

Sequential combinators for templates.

The library allows us to bind to compiler constructs as identifiers using templates and mixin templates.

This code was created to address the issue that we can't bind the templates in phobos to, for example, a static foreach block without reference to unnecessary nested or exposed code blocks. A prime example of this is mixin templates which have the special feature of having both an inherited scope for context and a nested scope for definitions - highly desirable, but little support in the templates libraries.

The only external import is std.typecons : AliasSeq from phobos. This is probably redundant.

These issues aren't ususally a problem for most apps, however when writing compilers or other apps that generate code, we end up with huge amounts of unnecessary code in the generated output and potenitially deep nesting. So yYd attempts to make this output more readable, and in the future will also try to create more meaningful error messages.

One of the differences between mixin templates and ordinary templates is that we can't alias the name of the template to another symbol. To access any kind of output from a mixin template then we are forced to introduce a symbol into the local scope. So the mixin templates in this library use the underscore symbol to represent the namespace of each instance of a mixin template. Some of the algorithms that take a parameter of a symbol representing a mixin template will expect that the passed in template will create a local underscore symbol in order to access the result. In future there will be a method to detect this and perform indirection where necessary.

identity!T :== alias _ = T

evaluate!T :== enum _ = T

partial!(T, U...) :== (V...) => T!(U,V) 

rpartial!(T, U...) :== (V...) => T!(V,U) 

etc...

Many of the mixin templates start with a single underscore _ . This indicates that this mixin template defines a single identifier in scope comprising an underscore which represents an alias binding to the result of the combinator.

    mixin _identity!"Some string" s;
    static assert (s._ == "Some string");

The identity template is the same as doing an alias, except that one cannot pass in alias as a symbol to another template in order to indicate that the parameter should be extracted, so it's very useful indeed.

    static assert (identity!"Some string" == "Some string");

The underscore may evaluate to an alias, or it might be a template or a mixin template. The syntax might be modified in future to indicate which type of structure has been exported.

So we can pass an identifier to a mixin template as an argument to a combinator template. The template then instantiates the mixin as defined by its semantics of the combinator.

So for example to iterate an AliasSeq using a mixin template:

    mixin template mixinTemplate(T) { ... }
    eachApply!(mixinTemplate,AliasSeq...);

"mixinTemplate" will be applied for each member of the sequence.

Some of the templates define the result as a template that can be access _!(...) This might be changed in future to a different symbol for returned templates, and another one for returned mixin templates.

This makes sense because we might want a compiler to generate a mixin template for the output, rather than a string that we mixin. Then we can decide the scope of the compiled code and include it at top level or inside a class or function body.

Some of the conditional templates only bind the underscore alias if the condition is met, otherwise

is(typeof(_!()))==false

or

is(typeof(_))==false

mixin .. m; is(typeof(m._))==false

An envisioned CTFE compiler in D language

Since we can run pegged inline at compile time, it makes sense to start looking at ways to leverage this into creating languages that can be directly imported into a D program during compilation.

Although classes, structs, etc, are ideal for representing application level programs, there is absolutely no reason that code generated by a compiler or script language should ever need to use them. The reason is that we don't want to bind the user to requiring class creation and so on. It makes more sense to create code that can be imported at any level.

A compiler doesn`t need virtual methods because it can generate it's own dispatch very easily. In our envisioned compiler, any declared types are represented as tuples. These are generated in client code by creating an instance of a mixin template returned by the compiler for a particular piece of source code input.

If I then wanted to duplicate a type defined in my script in for example, a struct in my D application, I would add a member instance referencing the tuple and make it alias this. I've then got the type, and the data, and also it's in the form expected by my compiler so I can use my struct as a parameter inside my script.

The only issue here is that multiple alias this statements for a type are not supported, therefore we'll probably have to resort to mixin templates again to implement type mechanics such as multiple inheritence.

Maybe our language could use some kind of identity/prototyping technique similar to the one used in javascript.

Functions and procedures would be resolved as inline lambda fields inside the tuple, and these could be template instatiations where the mechanisms such as virtual dispatch are implemented. However, we can't declare our own templates inside a tuple so we'd need a separate namespace for each type that contained the primitives to access these.

Since my tribe has a taboo against creating unnecessary extrusions into process space, I'm anticipating that methods and proceedures in a virtual class defined in a script would be exposed as templates in the exported namespace, and procedures would be represented by inline lambda fields that would be more easily resolved at compile time where possible.

So let's say I've generated a template from my script function, and I'm going to use it in my application, without accessing any variables. The result should be accessibleat compile time. This is exciting because we can now create nested compilers and make mixin languages from multiple grammars, without needing to generating any runtime output at all!

It's not necessary for D to generate any code, if our solution can be resolved inline. The output of our program could be to stderr from dmd, for example if we wanted to generate a table from static data.

Authors:
  • logicfish
Dependencies:
none
Versions:
0.2.0 2023-Feb-09
0.1.1 2023-Feb-02
0.1.0 2023-Feb-01
~main 2023-Oct-22
Show all 4 versions
Download Stats:
  • 0 downloads today

  • 1 downloads this week

  • 1 downloads this month

  • 27 downloads total

Score:
0.3
Short URL:
yyd.dub.pm