gfd3
Version:
API for d3 trees with gf
215 lines (214 loc) • 8.57 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.GFD3 = void 0;
const d3 = __importStar(require("d3"));
//
class GFD3 {
constructor() {
this.grammar = null;
this.abstractAST = null;
this.grammarMode = 'abstract';
this.selectedConcrete = null;
}
loadGrammarFromFile(file) {
return __awaiter(this, void 0, void 0, function* () {
const text = yield file.text();
this.setGrammar(JSON.parse(text));
});
}
loadGrammarFromURL(url) {
return __awaiter(this, void 0, void 0, function* () {
const response = yield fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const json = yield response.json();
this.setGrammar(json);
});
}
setGrammar(grammar) {
this.grammar = grammar;
this.abstractAST = this.transformAbstractToTree(grammar);
this.grammarMode = 'abstract';
const concreteLanguages = this.getConcreteLanguages();
if (concreteLanguages.length > 0) {
this.selectedConcrete = concreteLanguages[0];
}
}
transformAbstractToTree(grammar) {
const startCat = grammar.abstract.startcat;
const buildTree = (cat, visited) => {
if (visited.has(cat)) {
return { name: cat, type: 'cat' };
}
visited.add(cat);
const node = { name: cat, children: [], type: 'cat' };
const funs = Object.entries(grammar.abstract.funs)
.filter(([, funDetails]) => funDetails.cat === cat)
.map(([funName]) => funName);
node.funs = funs;
if (grammar.concretes) {
node.concreteFunctions = {};
Object.entries(grammar.concretes).forEach(([lang, concrete]) => {
if (concrete.productions[cat]) {
node.concreteFunctions[lang] = concrete.productions[cat]
.map(prod => concrete.functions[prod.fid].name);
}
});
}
Object.values(grammar.abstract.funs)
.filter(fun => fun.cat === cat)
.forEach(fun => {
fun.args.forEach(arg => {
var _a, _b;
if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.some(child => child.name === arg))) {
(_b = node.children) === null || _b === void 0 ? void 0 : _b.push(buildTree(arg, new Set(visited)));
}
});
});
visited.delete(cat);
return node;
};
return buildTree(startCat, new Set());
}
getGrammar() {
return this.grammar;
}
getAbstractAST() {
return this.abstractAST;
}
getConcreteLanguages() {
if (!this.grammar || !this.grammar.concretes)
return [];
return Object.values(this.grammar.concretes).map(concrete => concrete.flags.language);
}
setGrammarMode(mode) {
this.grammarMode = mode;
}
getGrammarMode() {
return this.grammarMode;
}
setSelectedConcrete(language) {
this.selectedConcrete = language;
}
getSelectedConcrete() {
return this.selectedConcrete;
}
getOptionsForNode(node) {
if (!this.grammar)
return [];
const category = node.name;
if (this.grammarMode === 'abstract') {
return Object.entries(this.grammar.abstract.funs)
.filter(([, funDetails]) => funDetails.cat === category)
.map(([funName]) => funName);
}
else if (this.selectedConcrete) {
const concreteLang = Object.keys(this.grammar.concretes).find(key => this.grammar.concretes[key].flags.language === this.selectedConcrete);
if (concreteLang) {
const concrete = this.grammar.concretes[concreteLang];
if (concrete.productions[category]) {
return concrete.productions[category]
.map(prod => concrete.functions[prod.fid].name);
}
}
}
return [];
}
updateNodeName(node, newName) {
node.originalName = node.originalName || node.name;
node.name = newName;
}
resetNodeName(node) {
if (node.originalName) {
node.name = node.originalName;
}
}
parseLins(lins, sequences) {
return lins.map(linIndex => {
const sequence = sequences[linIndex];
return sequence.map(seq => {
if (seq.type === 'SymKS') {
return seq.args[0];
}
if (seq.type === 'SymCat') {
return `{${seq.args[1]}}`;
}
if (seq.type === 'SymLit') {
return seq.args.join('');
}
return '';
}).join(' ');
}).join(' ');
}
resolveSequence(sequence, cats) {
return sequence.map(seq => {
if (seq.type === 'SymKS') {
return seq.args[0];
}
if (seq.type === 'SymCat') {
const catIndex = seq.args[0];
return cats[catIndex] || `{${catIndex}}`;
}
if (seq.type === 'SymLit') {
return `<${seq.args.join(',')}>`;
}
return '';
}).join(' ');
}
replaceLins() {
if (!this.grammar)
throw new Error("Grammar not loaded");
const resolvedGrammar = Object.assign(Object.assign({}, this.grammar), { concretes: {} });
const cats = new Set();
Object.values(this.grammar.abstract.funs).forEach(fun => {
cats.add(fun.cat);
fun.args.forEach(arg => cats.add(arg));
});
const catsArray = Array.from(cats);
for (const [concreteName, concreteGrammar] of Object.entries(this.grammar.concretes)) {
const resolvedFunctions = concreteGrammar.functions.map(func => (Object.assign(Object.assign({}, func), { resolvedLins: func.lins.map(linIndex => this.resolveSequence(concreteGrammar.sequences[linIndex], catsArray)) })));
resolvedGrammar.concretes[concreteName] = Object.assign(Object.assign({}, concreteGrammar), { functions: resolvedFunctions, resolvedSequences: concreteGrammar.sequences.map(seq => this.resolveSequence(seq, catsArray)) });
}
return resolvedGrammar;
}
// return data
getTreeData() {
if (!this.abstractAST)
return null;
return d3.hierarchy(this.abstractAST);
}
}
exports.GFD3 = GFD3;