@gent-js/gent
Version:
template-based data generator.
160 lines (159 loc) • 5.62 kB
JavaScript
import { pickFirst, pickMany } from "../../utils.js";
import { commandParser, lex } from "./commandParser.js";
const BaseVisitor = commandParser.getBaseCstVisitorConstructor();
class CommandVisitor extends BaseVisitor {
constructor() {
super();
this.validateVisitor();
}
commandExpression(children, param) {
const commandNameNode = children.commandName[0];
if (commandNameNode === undefined) {
return undefined;
}
const commandNameFragment = pickFirst(this.visit(commandNameNode));
if (commandNameFragment?.type !== "name") {
return undefined;
}
let hasOption = false;
const commandOptions = {};
const commandOptionNodes = children.commandOption;
pickMany(commandOptionNodes)
.flatMap((commandOptionNode) => this.visit(commandOptionNode))
.forEach((commandOptionFragment) => {
if (commandOptionFragment === undefined) {
return;
}
if (commandOptionFragment.type !== "option") {
return;
}
commandOptions[commandOptionFragment.key] = commandOptionFragment.value;
hasOption = true;
});
let commandExpressionFragment;
if (hasOption) {
commandExpressionFragment = {
type: "command",
name: commandNameFragment.content,
options: commandOptions,
};
}
else {
commandExpressionFragment = {
type: "command",
name: commandNameFragment.content,
};
}
return commandExpressionFragment;
}
commandName(children, param) {
const commandNameToken = children.Identifier[0];
if (commandNameToken === undefined) {
return undefined;
}
const commandNameFragment = {
type: "name",
content: commandNameToken.image,
};
return commandNameFragment;
}
commandOption(children, param) {
const commandOptionKeyNode = children.commandOptionKey[0];
if (commandOptionKeyNode === undefined) {
return undefined;
}
const commandOptionKeyFragment = pickFirst(this.visit(commandOptionKeyNode));
if (commandOptionKeyFragment?.type !== "option-key") {
return undefined;
}
let commandOptionValueFragment;
const commandOptionValueNode = children.commandOptionValue?.[0];
if (commandOptionValueNode !== undefined) {
const possibleCommandOptionValue = pickFirst(this.visit(commandOptionValueNode));
if (possibleCommandOptionValue?.type === "option-value") {
commandOptionValueFragment = possibleCommandOptionValue;
}
}
let commandOptionFragment;
if (commandOptionValueFragment === undefined) {
commandOptionFragment = {
type: "option",
key: commandOptionKeyFragment.content,
value: true,
};
}
else {
commandOptionFragment = {
type: "option",
key: commandOptionKeyFragment.content,
value: commandOptionValueFragment.content,
};
}
return commandOptionFragment;
}
commandOptionKey(children, param) {
const commandOptionKeyToken = children.CommandOptionKey[0];
if (commandOptionKeyToken === undefined) {
return undefined;
}
const key = commandOptionKeyToken.image;
let actualKey;
if (key.startsWith("--")) {
actualKey = key.substring(2);
}
else if (key.startsWith("-")) {
actualKey = key.substring(1);
}
else {
actualKey = key;
}
const commandOptionKeyFragment = {
type: "option-key",
content: actualKey,
};
return commandOptionKeyFragment;
}
commandOptionValue(children, param) {
const numberToken = children.NumberLiteral?.[0];
if (numberToken !== undefined) {
const numberValue = Number.parseInt(numberToken.image);
if (!Number.isNaN(numberValue)) {
return {
type: "option-value",
content: numberValue,
};
}
}
const identifierToken = children.Identifier?.[0];
const literalToken = identifierToken ?? children.Literal?.[0];
if (literalToken !== undefined) {
return {
type: "option-value",
content: literalToken.image,
};
}
const quotedLiteralToken = children.QuotedLiteral?.[0];
if (quotedLiteralToken !== undefined) {
const quotedValue = quotedLiteralToken.image;
return {
type: "option-value",
content: quotedValue.substring(1, quotedValue.length - 1),
};
}
return undefined;
}
}
const visitor = new CommandVisitor();
export function toAstVisitor(input) {
const lexResult = lex(input);
commandParser.input = lexResult.tokens;
const cst = commandParser.commandExpression();
if (commandParser.errors.length > 0) {
throw Error("parsing errors detected!\n" + commandParser.errors[0]?.message);
}
const out = pickFirst(visitor.visit(cst));
if (out?.type !== "command") {
return undefined;
}
return out;
}