In my current project, I'm developing a JavaScript collator/compositor using Java. While the implementation works, I feel there must be a more efficient way to handle it. I'm considering exploring the use of a Lexer for this purpose, although I'm still uncertain about how to proceed.
I have devised a meta syntax for the compositor, which represents a subset of the JavaScript language. This meta syntax is valid in terms of a standard JavaScript interpreter but lacks functionality (I utilize synonyms for reserved words as labels followed by code blocks, expecting the compositor to interpret them). Currently, I rely on a scanner and regex to identify this meta syntax in source files and perform a basic lexical transformation based on legal expressions.
The close interconnection between the modified javascript and the scanner/parser concerns me since the rewritten javascript depends on features from a specialized object support library that may undergo changes.
I am considering defining the meta syntax in Backaus-Naur or EBNF, feeding it to a lexer such as ANTLR, and directing the compositor based on detected meta syntax expressions in source files to perform various actions like inserting a required script into another, declaring variables, generating text for a parameterized library function call, or even compressing a script.
Is leveraging a Scanner/Parser/Lexer approach appropriate for building a compositor? Should I pursue this path for composing JavaScript? Any feedback is welcome as I seek guidance on how to proceed :)
UPDATE: Let's delve into a concrete example - an object declaration featuring meta syntax:
namespace: ie.ondevice
{
use: ie.ondevice.lang.Mixin;
use: ie.ondevice.TraitsDeclaration;
declare: Example < Mixin | TraitsDeclaration
{
include: "path/to/file.extension";
// implementation here
}
}
This snippet describes the object ie.ondevice.Example, inheriting Mixin and incorporating traits similar to TraitsDeclaration. The compositor would detect the use statements, verify if the namespace corresponds to a valid file location, and prepend scripts where the object declarations exist, preprocessing meta syntax before collating.
Through rewrite rules utilizing the aforementioned object support library, the resulting file could potentially resemble this format (multiple object representations have been explored):
module("ie.ondevice.Example", function (mScope)
{
// mScope acts as a delegate
mScope.use("ie.ondevice.lang.Mixin");
mScope.use("ie.ondevice.TraitsDeclaration");
// With two use statements, mScope.localVars would contain:
// "var Mixin= ie.ondevice.lang.Mixin, TraitsDeclaration= ie.ondevice.TraitsDeclaration"
// Through eval, imported objects are introduced with their local names
eval(mScope.localVars);
// Extension of Function.prototype with functions like inherits, define, defineStatic, resembles, and getName
// Prototypal inheritance employing an anonymous bridge constructor
Example.inherits(Mixin);
// Addition of named methods and properties to Example.prototype
Example.define
(
// list of functions and properties
);
// Guaranteeing that Example.prototype mirrors TraitsDeclaration.prototype in terms of property names and types,
// throwing an exception if discrepancies arise.
// Optionally disabled in production - solely executed during object declaration,
// avoiding additional overhead during instantiation
Example.resembles(TraitsDeclaration);
// Constructor
function Example ()
{
Mixin.call(this);
};
// If necessary, generates the ie.ondevice object hierarchy
// and makes the constructor accessible to it
mScope.exports(Example);
});
While it's possible that I might be overcomplicating my needs, my ideal scenario involves an event-driven collator where listeners can be loosely associated with directive detections.