benjamn / benjamn/ast-types

alternate builder / copier

Open
#122 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
1.2k
Forks
194
Avg merge
22h 43m
Merged PRs (30d)
10

Description

An idea I've been playing with:

I have got a situation where I am going to take my custom AST, perform some optimizing transforms, and then use that AST to build nodes that actually perform the work. In my case, I intend to target two different platforms (primitive `Strings` and Node.js `Streams`), and the built nodes will be so drastically different, I intend to just create separate instances for each. Also there will be some optimizing transforms that I will only want to perform for one platform or the other (so I need a way to create an identical deep copy after I perform the common transforms).

My idea is to provide a `copy` function that takes an alternate `builders` implementation to create the copy. If an alternate `builders` implementation is not provided, it uses the default one (`types.builders`), essentially creating a deep copy of the AST. Providing an alternate `builders` implementation requires you provide all the methods in `types.builders` (with identical signatures), but you are free to return whatever you want from each method (whatever you return will be used as an argument to the buildFn of the parent element).

Was my explanation clear? Is this worth including in `ast-types`, or is it to niche?

This relies on the buildFn metadata exposed by #121.

``` js
var types = require('ast-types/lib/types');
var shared = require('ast-types/lib/shared');
var isPrimitive = shared.isPrimitive;
var b = types.builders;

function copy(type, builder) {
builder = builder || b;

if (isPrimitive.check(type)) {
return type;
}

if (type instanceof Array) {
return type.map(function(child) {
return copy(child, builder);
})
}

if ('string' !== typeof type.type) {
throw new Error('not an AST node: ' + JSON.stringify(type));
}

var builderName = types.getBuilderName(type.type);
var buildFn = b[builderName];

if (!buildFn) {
throw new Error(type.type + ' does not have a registered builder');
}

var buildFn2 = builder[builderName];

if ('function' !== typeof buildFn2) {
throw new Error('builder does not have function: ' + builderName);
}

var args = [];
for (var i = 0; i < buildFn.paramCount; i++) {
var p = copy(type[buildFn[i].name], builder);
if (typeof p !== 'undefined') {
args[i] = p;
}
}

return buildFn2.apply(builder, args);
}
```

P.S. As this is a completely custom AST I'm working with, I anxiously await the resolution of #57.

Contributor guide

No contributing guide indexed for this repository

Research direction

Review the proposed use of buildFn metadata from #121 alongside lib/types and lib/shared, including the existing types.builders and shared.isPrimitive entry points. Determine whether an alternate-builder deep-copy API fits ast-types, then verify that default builders, custom builders, primitives, arrays, and missing builder methods have defined behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.