Disorder!
parent
e2c0e79751
commit
c13eafb9b3
|
@ -7,13 +7,13 @@ const pathlib = require('path');
|
|||
const extractors = require('./extractors');
|
||||
const Command = require('./commands');
|
||||
const Scope = require('./scope');
|
||||
const {log} = require('./utils');
|
||||
const {consume, log} = require('./utils');
|
||||
|
||||
class Collector {
|
||||
constructor(parser) {
|
||||
this.parser = parser;
|
||||
this.schemas = [];
|
||||
this.scope = null;
|
||||
this.waiters = Object.create(null);
|
||||
}
|
||||
|
||||
collect(path) {
|
||||
|
@ -25,13 +25,13 @@ class Collector {
|
|||
// TODO: customize it.
|
||||
const namespace = pathToNamespace(path);
|
||||
|
||||
this.scope = global.extend(namespace);
|
||||
const scope = global.extend(namespace);
|
||||
|
||||
this._visit(ast.program);
|
||||
this._visit(ast.program, scope);
|
||||
}
|
||||
|
||||
// Given the AST output of babylon parse, walk through in a depth-first order.
|
||||
_visit(root) {
|
||||
_visit(root, scope) {
|
||||
let stack;
|
||||
let parent;
|
||||
let keys = [];
|
||||
|
@ -55,7 +55,9 @@ class Collector {
|
|||
const {type} = node;
|
||||
|
||||
if (type && type in extractors) {
|
||||
this._collect(node);
|
||||
const task = this._collect(node, scope);
|
||||
|
||||
this._schedule(task);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -68,11 +70,11 @@ class Collector {
|
|||
} while (stack);
|
||||
}
|
||||
|
||||
_collect(node) {
|
||||
* _collect(node, scope) {
|
||||
const extractor = extractors[node.type];
|
||||
|
||||
if (!extractor) {
|
||||
this._visit(node);
|
||||
this._visit(node, scope);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -92,37 +94,78 @@ class Collector {
|
|||
} else if (value instanceof Command) {
|
||||
switch (value.name) {
|
||||
case 'provide':
|
||||
assert(this.scope);
|
||||
this.scope.addSchema(value.data);
|
||||
this.schemas.push(value.data);
|
||||
const schema = value.data;
|
||||
|
||||
scope.addSchema(schema);
|
||||
this.schemas.push(schema);
|
||||
this._wakeup(schema.name);
|
||||
|
||||
break;
|
||||
case 'query':
|
||||
const info = this.scope.query(value.data);
|
||||
let info;
|
||||
|
||||
while (!(info = scope.query(value.data))) {
|
||||
yield value.data;
|
||||
}
|
||||
|
||||
// TODO: support externals.
|
||||
assert(info.type, 'local');
|
||||
result = info.schema;
|
||||
|
||||
break;
|
||||
case 'enter':
|
||||
this.scope = this.scope.extend();
|
||||
scope = scope.extend();
|
||||
|
||||
break;
|
||||
case 'exit':
|
||||
assert(this.scope);
|
||||
this.scope = this.scope.parent;
|
||||
assert(scope.parent);
|
||||
scope = scope.parent;
|
||||
|
||||
break;
|
||||
case 'namespace':
|
||||
result = this.scope.namespace;
|
||||
result = scope.namespace;
|
||||
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
} else if (Array.isArray(value)) {
|
||||
result = value.map(val => this._collect(val));
|
||||
result = [];
|
||||
|
||||
for (const val of value) {
|
||||
result.push(yield* this._collect(val, scope));
|
||||
}
|
||||
} else {
|
||||
assert(isNode(value));
|
||||
result = this._collect(value);
|
||||
result = yield* this._collect(value, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_schedule(task) {
|
||||
const {done, value} = task.next();
|
||||
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
|
||||
const waiters = this.waiters[value] = this.waiters[value] || [];
|
||||
|
||||
waiters.push(task);
|
||||
}
|
||||
|
||||
_wakeup(name) {
|
||||
if (!this.waiters[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tasks = this.waiters[name];
|
||||
delete this.waiters[name];
|
||||
|
||||
for (const task of tasks) {
|
||||
this._schedule(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isNode(it) {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
const assert = require('assert');
|
||||
|
||||
const {provide, query, enter, exit, namespace} = require('./commands');
|
||||
const {partition, log} = require('./utils');
|
||||
const {partition} = require('./utils');
|
||||
|
||||
const extractors = {
|
||||
* TypeAlias(node) {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
type X = {
|
||||
y: Y,
|
||||
};
|
||||
|
||||
type Y = {
|
||||
z: Z,
|
||||
};
|
||||
|
||||
type Z = string;
|
||||
|
||||
// ###
|
||||
[
|
||||
{
|
||||
type: 'string',
|
||||
name: 'Z',
|
||||
namespace: 'disorder',
|
||||
},
|
||||
{
|
||||
type: 'record',
|
||||
name: 'Y',
|
||||
namespace: 'disorder',
|
||||
fields: [{name: 'z', type: 'Z'}],
|
||||
},
|
||||
{
|
||||
type: 'record',
|
||||
name: 'X',
|
||||
namespace: 'disorder',
|
||||
fields: [{name: 'y', type: 'Y'}],
|
||||
},
|
||||
]
|
Loading…
Reference in New Issue