@grammar/son
Version:
SON grammar.
396 lines • 16 kB
JavaScript
import $ from './spellu-engine.mjs';
var grammar$son;
(function (grammar$son) {
grammar$son.recipe = {
name: 'son',
rules: {
'root': {
parser: 'value',
},
'value': {
parser: '|', argument: [
{ parser: 'array' },
{ parser: 'object' },
{ parser: 'string' },
{ parser: 'number' },
{ parser: 'boolean' },
{ parser: 'null' },
],
},
'array': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "son.token.bracket-[" /* OpenBracketToken */, pattern: '[' } },
{
parser: '*', argument: [
{ parser: 'array-item' },
{ parser: '?', argument: { syntax: "son.token.comma" /* CommaToken */, pattern: ',' } },
], options: { allowTrailingSeparator: true },
optional: true,
},
{ parser: '?', argument: { syntax: "son.token.bracket-]" /* CloseBracketToken */, pattern: ']' } },
],
},
'array-item': {
parser: 'value',
},
'object': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "son.token.brace-{" /* OpenBraceToken */, pattern: '{' } },
{
parser: '*', argument: [
{ parser: 'object-item' },
{ parser: '?', argument: { syntax: "son.token.comma" /* CommaToken */, pattern: ',' } },
], options: { allowTrailingSeparator: true },
optional: true,
},
{ parser: '?', argument: { syntax: "son.token.brace-}" /* CloseBraceToken */, pattern: '}' } },
],
},
'object-item': {
parser: '&', argument: [
{ parser: 'object-key' },
{ parser: '?', argument: { syntax: "son.token.colon" /* ColonToken */, pattern: ':' } },
{ parser: 'value' },
],
},
'object-key': {
parser: '|', argument: [
{ parser: 'string' },
{ parser: 'number' },
{ parser: 'identifier' },
],
},
'identifier': {
parser: '?', argument: { syntax: "son.token.identifier" /* IdentifierToken */, pattern: /[a-zA-Z_$][0-9a-zA-Z_$]*/ },
},
'string': {
parser: '|', argument: [
{ parser: 'doublequoted-string' },
{ parser: 'singlequoted-string' },
],
},
'doublequoted-string': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "son.token.double-quote" /* DoubleQuote */, pattern: '"' } },
{
parser: '#', argument: [
{ syntax: "son.token.escaped-unicode-character" /* EscapedUnicodeCharacterToken */, pattern: /\\u[0-9a-fA-F]{4}/ },
{ syntax: "son.token.escaped-sign-character" /* EscapedSignCharacterToken */, pattern: /\\[\\tnr"]/ },
{ syntax: "son.token.error" /* ErrorToken */, pattern: /\\u[0-9a-fA-F]{1,3}/ },
{ syntax: "son.token.error" /* ErrorToken */, pattern: /\\./ },
{ syntax: "son.token.text" /* TextToken */, pattern: /[^\\"]+/ },
], multiplicity: 0,
},
{ parser: '#', argument: { syntax: "son.token.double-quote" /* DoubleQuote */, pattern: '"' } },
],
},
'singlequoted-string': {
parser: '&', argument: [
{ parser: '?', argument: { syntax: "son.token.single-quote" /* SingleQuote */, pattern: "'" } },
{
parser: '#', argument: [
{ syntax: "son.token.escaped-unicode-character" /* EscapedUnicodeCharacterToken */, pattern: /\\u[0-9a-fA-F]{4}/ },
{ syntax: "son.token.escaped-sign-character" /* EscapedSignCharacterToken */, pattern: /\\[\\tnr"]/ },
{ syntax: "son.token.error" /* ErrorToken */, pattern: /\\u[0-9a-fA-F]{1,3}/ },
{ syntax: "son.token.error" /* ErrorToken */, pattern: /\\./ },
{ syntax: "son.token.text" /* TextToken */, pattern: /[^\\']+/ },
], multiplicity: 0,
},
{ parser: '#', argument: { syntax: "son.token.single-quote" /* SingleQuote */, pattern: "'" } },
],
},
'number': {
parser: '?', argument: [
{ syntax: "son.token.number" /* NumberToken */, pattern: /[-]?(?:0|[1-9][0-9]*)(?:[.][0-9]+)?(?:[eE][+-]?[0-9]+)?/ },
],
},
'boolean': {
parser: '?', argument: [
{ syntax: "son.token.boolean" /* BooleanToken */, pattern: 'true' },
{ syntax: "son.token.boolean" /* BooleanToken */, pattern: 'false' },
],
},
'null': {
parser: '?', argument: [
{ syntax: "son.token.null" /* NullToken */, pattern: 'null' },
],
},
},
};
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
grammar$son.processors = {};
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
grammar$son.processors['cst'] = {
recipe: grammar$son.recipe,
parts: {}
};
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
grammar$son.processors['ast'] = {
recipe: grammar$son.recipe,
parts: {
'value'(_) {
return _;
},
'array'(_) {
return $.createNode(_, "son.Array" /* Array */, { items: _[1] || [] });
},
'array-item'(_) {
return _;
},
'object'(_) {
return $.createNode(_, "son.Object" /* Object */, { items: _[1] || [] });
},
'object-item'(_) {
return [_[0], _[2]];
},
'string'(_) {
const value = _[1].map(_ => convertStringLiteral(_)).join('');
return $.createNode(_, "son.String" /* String */, { value, tokens: _[1] });
},
'number'(_) {
return $.createNode(_, "son.Number" /* Number */, { value: Number(_.value), token: _ });
},
'boolean'(_) {
return $.createNode(_, "son.Boolean" /* Boolean */, { value: _.value === 'true' ? true : false, token: _ });
},
'null'(_) {
return $.createNode(_, "son.Null" /* Null */, { value: null, token: _ });
},
},
};
const escapedSigns = {
'\\\\': '\\',
'\\t': '\t',
'\\r': '\r',
'\\n': '\n',
'\\"': '\"',
};
function convertStringLiteral(token) {
switch (token.syntax) {
case "son.token.text" /* TextToken */: return token.value;
case "son.token.escaped-unicode-character" /* EscapedUnicodeCharacterToken */: return String.fromCharCode(parseInt(token.value.substring(2), 16));
case "son.token.escaped-sign-character" /* EscapedSignCharacterToken */: return escapedSigns[token.value] || token.value;
case "son.token.error" /* ErrorToken */: return token.value;
default: return '';
}
}
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
/**
* literal.string
* literal.number
* literal.boolean
* literal.null
* entity.object-key.literal.string
* entity.object-key.literal.number
* entity.object-key.identifier
*/
grammar$son.processors['syntax'] = {
recipe: grammar$son.recipe,
parts: {
'object-key'(_) {
return $.createSyntaxScope('entity', $.createSyntaxScope('object-key', _));
},
'identifier'(_) {
return $.createSyntaxScope('identifier', _);
},
'string'(_) {
return $.createSyntaxScope('literal', $.createSyntaxScope('string', _));
},
'number'(_) {
return $.createSyntaxScope('literal', $.createSyntaxScope('number', _));
},
'boolean'(_) {
return $.createSyntaxScope('literal', $.createSyntaxScope('boolean', _));
},
'null'(_) {
return $.createSyntaxScope('literal', $.createSyntaxScope('null', _));
},
},
};
const escapedSigns = {
'\\\\': '\\',
'\\t': '\t',
'\\r': '\r',
'\\n': '\n',
'\\"': '\"',
};
function convertStringLiteral(token) {
switch (token.syntax) {
case "son.token.text" /* TextToken */: return token.value;
case "son.token.escaped-unicode-character" /* EscapedUnicodeCharacterToken */: return String.fromCharCode(parseInt(token.value.substring(2), 16));
case "son.token.escaped-sign-character" /* EscapedSignCharacterToken */: return escapedSigns[token.value] || token.value;
case "son.token.error" /* ErrorToken */: return token.value;
default: return '';
}
}
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
grammar$son.processors['value'] = {
recipe: grammar$son.recipe,
parts: {
'array'(_) {
return _[1] || [];
},
'array-item'(_) {
return _;
},
'object'(_) {
return Object.fromEntries(_[1] || []);
},
'object-item'(_) {
return [_[0], _[2]];
},
'identifier'(_) {
return _.value;
},
'string'(_) {
return _[1].reduce((v, _) => v.concat(convertStringLiteral(_)), '');
},
'number'(_) {
return Number(_.value);
},
'boolean'(_) {
return _.value === 'true' ? true : false;
},
'null'(_) {
return null;
},
},
};
const escapedSigns = {
'\\\\': '\\',
'\\t': '\t',
'\\r': '\r',
'\\n': '\n',
'\\"': '\"',
};
function convertStringLiteral(token) {
switch (token.syntax) {
case "son.token.text" /* TextToken */: return token.value;
case "son.token.escaped-unicode-character" /* EscapedUnicodeCharacterToken */: return String.fromCharCode(parseInt(token.value.substring(2), 16));
case "son.token.escaped-sign-character" /* EscapedSignCharacterToken */: return escapedSigns[token.value] || token.value;
case "son.token.error" /* ErrorToken */: return token.value;
default: return '';
}
}
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
let ProcessorSuite;
(function (ProcessorSuite) {
ProcessorSuite["CST"] = "cst";
ProcessorSuite["AST"] = "ast";
ProcessorSuite["Syntax"] = "syntax";
ProcessorSuite["Value"] = "value";
})(ProcessorSuite = grammar$son.ProcessorSuite || (grammar$son.ProcessorSuite = {}));
function selectProcessorSuite(suite) {
return [grammar$son.processors[suite]];
}
grammar$son.selectProcessorSuite = selectProcessorSuite;
function scan(source, suite = ProcessorSuite.AST, rule, options = {}) {
options.processors = selectProcessorSuite(suite);
return $.scan($.createSource(source), rule ?? grammar$son.recipe.name, options);
}
grammar$son.scan = scan;
function tokenize(source, options = {}) {
return $.tokenize(scan(source, ProcessorSuite.Syntax, undefined, options));
}
grammar$son.tokenize = tokenize;
function parse(source, options = {}) {
return scan(source, ProcessorSuite.Value, undefined, options);
}
grammar$son.parse = parse;
})(grammar$son || (grammar$son = {}));
(function (grammar$son) {
const printOptions = {
pretty: false,
};
function print(value, options = {}) {
options = { ...printOptions, ...options };
const printer = new SONPrinter(options);
return printer.print(value);
}
grammar$son.print = print;
class SONPrinter extends $.TextPrinter {
constructor(options = {}) {
super({
space: options.pretty ? ' ' : '',
lineBreak: options.pretty ? '\n' : '',
indent: options.pretty ? 'tab' : 0,
});
}
print(value) {
this.node(value);
return this.flash();
}
node(...nodes) {
for (const node of nodes) {
let block = this._blocks[node.syntax];
if (!block) {
// throw new Error(`Syntax printer "${value.syntax}" is not defined.`)
block = printer => printer.text('#ERROR#');
}
block(this, node);
}
return this;
}
_blocks = {
["son.Array" /* Array */](printer, _) {
if (_.items.length == 0) {
printer.text('[]');
}
else {
printer.text('[').newLine().indentUp();
{
const items = [..._.items];
const lastValue = items.pop();
for (const value of items) {
printer.node(value).text(',').newLine();
}
{
printer.node(lastValue).newLine();
}
}
printer.indentDown().text(']');
}
},
["son.Object" /* Object */](printer, _) {
if (_.items.length == 0) {
printer.text('{}');
}
else {
printer.text('{').newLine().indentUp();
{
const items = [..._.items];
const [lastKey, lastValue] = items.pop();
for (const [key, value] of items) {
printer.node(key).text(':').node(value).text(',').newLine();
}
{
printer.node(lastKey).text(':').node(lastValue).newLine();
}
}
printer.indentDown().text('}');
}
},
["son.String" /* String */](printer, _) {
const string = _.tokens.map((_) => _.value).join('');
printer.quote('"', string);
},
["son.Number" /* Number */](printer, _) {
printer.text(_.token.value);
},
["son.Boolean" /* Boolean */](printer, _) {
printer.text(_.token.value);
},
["son.Null" /* Null */](printer, _) {
printer.text(_.token.value);
},
};
}
})(grammar$son || (grammar$son = {}));
export default grammar$son;
//# sourceMappingURL=grammar-son.mjs.map