linx-simulator2/node_modules/toml/lib/compiler.js
2019-09-18 11:11:16 +03:00

196 lines
4.9 KiB
JavaScript

"use strict";
function compile(nodes) {
var assignedPaths = [];
var valueAssignments = [];
var currentPath = "";
var data = {};
var context = data;
var arrayMode = false;
return reduce(nodes);
function reduce(nodes) {
var node;
for (var i = 0; i < nodes.length; i++) {
node = nodes[i];
switch (node.type) {
case "Assign":
assign(node);
break;
case "ObjectPath":
setPath(node);
break;
case "ArrayPath":
addTableArray(node);
break;
}
}
return data;
}
function genError(err, line, col) {
var ex = new Error(err);
ex.line = line;
ex.column = col;
throw ex;
}
function assign(node) {
var key = node.key;
var value = node.value;
var line = node.line;
var column = node.column;
var fullPath;
if (currentPath) {
fullPath = currentPath + "." + key;
} else {
fullPath = key;
}
if (typeof context[key] !== "undefined") {
genError("Cannot redefine existing key '" + fullPath + "'.", line, column);
}
context[key] = reduceValueNode(value);
if (!pathAssigned(fullPath)) {
assignedPaths.push(fullPath);
valueAssignments.push(fullPath);
}
}
function pathAssigned(path) {
return assignedPaths.indexOf(path) !== -1;
}
function reduceValueNode(node) {
if (node.type === "Array") {
return reduceArrayWithTypeChecking(node.value);
} else if (node.type === "InlineTable") {
return reduceInlineTableNode(node.value);
} else {
return node.value;
}
}
function reduceInlineTableNode(values) {
var obj = {};
for (var i = 0; i < values.length; i++) {
var val = values[i];
if (val.value.type === "InlineTable") {
obj[val.key] = reduceInlineTableNode(val.value.value);
} else if (val.type === "InlineTableValue") {
obj[val.key] = reduceValueNode(val.value);
}
}
return obj;
}
function setPath(node) {
var path = node.value;
var quotedPath = path.map(quoteDottedString).join(".");
var line = node.line;
var column = node.column;
if (pathAssigned(quotedPath)) {
genError("Cannot redefine existing key '" + path + "'.", line, column);
}
assignedPaths.push(quotedPath);
context = deepRef(data, path, {}, line, column);
currentPath = path;
}
function addTableArray(node) {
var path = node.value;
var quotedPath = path.map(quoteDottedString).join(".");
var line = node.line;
var column = node.column;
if (!pathAssigned(quotedPath)) {
assignedPaths.push(quotedPath);
}
assignedPaths = assignedPaths.filter(function(p) {
return p.indexOf(quotedPath) !== 0;
});
assignedPaths.push(quotedPath);
context = deepRef(data, path, [], line, column);
currentPath = quotedPath;
if (context instanceof Array) {
var newObj = {};
context.push(newObj);
context = newObj;
} else {
genError("Cannot redefine existing key '" + path + "'.", line, column);
}
}
// Given a path 'a.b.c', create (as necessary) `start.a`,
// `start.a.b`, and `start.a.b.c`, assigning `value` to `start.a.b.c`.
// If `a` or `b` are arrays and have items in them, the last item in the
// array is used as the context for the next sub-path.
function deepRef(start, keys, value, line, column) {
var traversed = [];
var traversedPath = "";
var path = keys.join(".");
var ctx = start;
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
traversed.push(key);
traversedPath = traversed.join(".");
if (typeof ctx[key] === "undefined") {
if (i === keys.length - 1) {
ctx[key] = value;
} else {
ctx[key] = {};
}
} else if (i !== keys.length - 1 && valueAssignments.indexOf(traversedPath) > -1) {
// already a non-object value at key, can't be used as part of a new path
genError("Cannot redefine existing key '" + traversedPath + "'.", line, column);
}
ctx = ctx[key];
if (ctx instanceof Array && ctx.length && i < keys.length - 1) {
ctx = ctx[ctx.length - 1];
}
}
return ctx;
}
function reduceArrayWithTypeChecking(array) {
// Ensure that all items in the array are of the same type
var firstType = null;
for (var i = 0; i < array.length; i++) {
var node = array[i];
if (firstType === null) {
firstType = node.type;
} else {
if (node.type !== firstType) {
genError("Cannot add value of type " + node.type + " to array of type " +
firstType + ".", node.line, node.column);
}
}
}
// Recursively reduce array of nodes into array of the nodes' values
return array.map(reduceValueNode);
}
function quoteDottedString(str) {
if (str.indexOf(".") > -1) {
return "\"" + str + "\"";
} else {
return str;
}
}
}
module.exports = {
compile: compile
};