Dev Diaries - May 28, 2018
If you haven't heard of glish before, check out the post What is Glish?
Most of my work this week went into thinking about how glish programs will be run. Writing What is Glish? was part of that process and helped me crystalize what the main interfaces should be. There are basically 2 ways that glish programs will be run:
Embedded in a dedicated app. This is the main case. Some host program keeps track of domain specific items, like items and carts and discounts, and glish is brought in to control the interactions between those items. Glish manuals will define some well-known rulebooks and/or phrases, and the host program will call them.
As a standalone program. This is actually a special case of the dedicated app case. Here, the host program is very minimal, only looking for an initial rulebook export to call and then letting glish take over. In this mode, there is deliberately minimal sandboxing, so the glish manual can use code literals to do things like import other modules or interact with the system.
This means that the overall structure of an application that uses glish (either glish-node standalone or embedding programs) will look like this:
- Core application logic, written in the native language, including code to load glish and call well-known rulebooks and phrases.
- Domain-specific glish runtime, written in glish and bundled with the application. This should create the well-known rulebooks and create interfaces for any exposed native interfaces (for example, if your native code provides an
applyDiscount
method, this manual would set up the phrase, "To take (x - a number) from (c - a cart)"). - Manual with business logic, also written in glish and loaded by the app at runtime. This will add rules to the rulebooks and defines the actual "business logic" that glish is responsible for.
Implementation
Based on this, I've taken the approach that glish compiles to a CommonJS module, and there are some helpers to load the module with or without sandboxing. But what should the exports of these modules be?
- Objects are difficult to export because glish property names don't make convenient JS identifiers, and because properties in glish are type checked at compile time, but the exposed properties should be type checked at run time. The generator will need to provide a wrapper with get/set methods for the properties.
- Phrases are very easy to export because method calls already have runtime type checking. However, if objects are received/returned, they will need to be unwrapped/wrapped.
- Variables could be exported similarly to object properties, but I'm not actually sure that exporting variables is a common enough use case to merit being built in to glish. It's trivial to manually create a getter/setter phrase and export that.
- Rulebooks are the main use case for glish so exporting them should be built in. It's easy to create a syntactic sugar for exporting a "follow rulebook" phrase automatically. I don't think editing the rules of rulebooks will be a common use case, and again the user could manually create phrases to accomplish this quite easily.
Putting this together, here's a sample hello world manual and script:
To run the program (exported as `main`):
say "Hello, world!".
To say (x - a value): `console.log(x)`.
const source = compile([ "stdlib.glish", "manual.glish");
const mod = loadModule(source, { console });
mod.main();
In the future
The progress this week was mostly conceptual rather than code, but was useful for helping me lay down the proper interfaces.
I need to move the compiler to using a visitor pattern. This will make it much easier for me to do things like static overload resolution, dead code removal, function inlining, and type checking; plus it will be easier to test specific parts of the generator. This will require me making the Program
internal representation a little more homogenous that currently, and I need to think about how indexes will be generated as well, which will be affected.
My upcoming project list:
- Create a board game app that can load glish manuals for the rules. I probably won't be able to finish this, but it should be a good highlight of the missing glish features.
- Migrate the code generator to a visitor pattern; build a program index data structure.
- Have the generator create wrappers for object types returned from phrases.
- Continue working on the glish langauge (self-referential descriptions, etc).