@jplorg/jpl
Version:
JPL interpreter
2,377 lines (2,344 loc) • 45.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.opAnd = opAnd;
exports.opArrayConstructor = opArrayConstructor;
exports.opComparison = opComparison;
exports.opConstant = opConstant;
exports.opDifference = opDifference;
exports.opEquality = opEquality;
exports.opErrorSuppression = opErrorSuppression;
exports.opFunctionDefinition = opFunctionDefinition;
exports.opGroup = opGroup;
exports.opIf = opIf;
exports.opMultiplication = opMultiplication;
exports.opNamedFunctionDefinition = opNamedFunctionDefinition;
exports.opNegation = opNegation;
exports.opNot = opNot;
exports.opNullCoalescence = opNullCoalescence;
exports.opNumber = opNumber;
exports.opObjectConstructor = opObjectConstructor;
exports.opOr = opOr;
exports.opOutputConcat = opOutputConcat;
exports.opPipe = opPipe;
exports.opStringLiteral = opStringLiteral;
exports.opSubPipe = opSubPipe;
exports.opSubRoute = opSubRoute;
exports.opTry = opTry;
exports.opValueAccess = opValueAccess;
exports.opVariableAccess = opVariableAccess;
exports.parseAccess = parseAccess;
exports.parseAssignment = parseAssignment;
exports.parseEntrypoint = parseEntrypoint;
exports.parseFunctionHeader = parseFunctionHeader;
exports.parseNumber = parseNumber;
exports.parseProgram = parseProgram;
exports.parseString = parseString;
var _library = require("../library");
var _util = require("./util");
/**
* Parse a single program at i.
* Throws an error if src contains additional content.
*/
async function parseEntrypoint(src, i, c) {
let n = i;
const result = await parseProgram(src, n, c);
({
i: n
} = result);
if (!(0, _util.eot)(src, n, c).is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'program',
message: 'expected EOT'
});
return result;
}
/** Parse program at i */
function parseProgram(src, i, c) {
let n = i;
({
i: n
} = (0, _util.walkWhitespace)(src, n, c));
return opPipe(src, n, c);
}
/** Parse function header at i */
function parseFunctionHeader(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: '('
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'function definition',
message: "expected '('"
});
const argNames = [];
m = (0, _util.matchWord)(src, n, c, {
phrase: ')'
});
if (m.is) ({
i: n
} = m);else for (;;) {
const v = (0, _util.safeVariable)(src, n, c);
if (!v.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'function definition',
message: 'expected argument name'
});
let name;
({
i: n,
value: name
} = v);
argNames.push(name);
m = (0, _util.matchWord)(src, n, c, {
phrase: ')'
});
if (m.is) {
({
i: n
} = m);
break;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ','
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'function definition',
message: "expected ',' or ')'"
});
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ':'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'function definition',
message: "expected ':'"
});
return {
i: n,
argNames
};
}
/** Parse access at i */
async function parseAccess(src, i, c, {
identity
} = {}) {
let n = i;
const selectors = [];
let canAssign = true;
for (;;) {
let m = (0, _util.matchWord)(src, n, c, {
phrase: '.'
});
const isIdentity = identity && selectors.length === 0;
if (!isIdentity && m.is) {
({
i: n
} = m);
const v = (0, _util.safeVariable)(src, n, c);
if (!v.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'field access operator',
message: 'expected field name'
});
let name;
({
i: n,
value: name
} = v);
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_FIELD,
params: {
pipe: [{
op: _library.OP_STRING,
params: {
string: name
}
}],
optional
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '['
});
if (m.is) {
({
i: n
} = m);
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
if (m.is) {
({
i: n
} = m);
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_ITER,
params: {
optional
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ':'
});
if (m.is) {
({
i: n
} = m);
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
if (m.is) {
({
i: n
} = m);
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_SLICE,
params: {
from: [{
op: _library.OP_CONSTANT_NULL
}],
to: [{
op: _library.OP_CONSTANT_NULL
}],
optional
}
});
continue;
}
let opsRight;
({
i: n,
ops: opsRight
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'array slice operator',
message: "expected ']'"
});
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_SLICE,
params: {
from: [{
op: _library.OP_CONSTANT_NULL
}],
to: opsRight,
optional
}
});
continue;
}
let opsLeft;
({
i: n,
ops: opsLeft
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
if (m.is) {
({
i: n
} = m);
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_FIELD,
params: {
pipe: opsLeft,
optional
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ':'
});
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'variable access operator',
message: "expected ':' or ']'"
});
({
i: n
} = m);
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
if (m.is) {
({
i: n
} = m);
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_SLICE,
params: {
from: opsLeft,
to: [{
op: _library.OP_CONSTANT_NULL
}],
optional
}
});
continue;
}
let opsRight;
({
i: n,
ops: opsRight
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'array slice operator',
message: "expected ']'"
});
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_SLICE,
params: {
from: opsLeft,
to: opsRight,
optional
}
});
continue;
}
let bound;
m = (0, _util.matchWord)(src, n, c, {
phrase: '->'
});
if (m.is) ({
i: n,
is: bound
} = m);
m = (0, _util.matchWord)(src, n, c, {
phrase: '('
});
if (!m.is && bound) {
return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'bound function call',
message: "expected '('"
});
}
if (m.is) {
({
i: n
} = m);
const args = [];
m = (0, _util.matchWord)(src, n, c, {
phrase: ')'
});
if (m.is) ({
i: n
} = m);else for (;;) {
let opsArg;
({
i: n,
ops: opsArg
} = await opSubPipe(src, n, c));
args.push(opsArg);
m = (0, _util.matchWord)(src, n, c, {
phrase: ')'
});
if (m.is) {
({
i: n
} = m);
break;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ','
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'function call',
message: "expected ',' or ')'"
});
}
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_FUNCTION,
params: {
args,
bound,
optional
}
});
canAssign = false;
continue;
}
break;
}
return {
i: n,
is: selectors.length > 0,
selectors,
canAssign
};
}
/** Parse assignment at i */
async function parseAssignment(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: '=',
notBeforeSet: '='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_SET,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '|='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_UPDATE,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '+='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_ADDITION,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '-='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_SUBTRACTION,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '*='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_MULTIPLICATION,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '/='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_DIVISION,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '%='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_REMAINDER,
params: {
pipe: ops
}
}
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '?='
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
is: true,
assignment: {
op: _library.OPU_NULL_COALESCENCE,
params: {
pipe: ops
}
}
};
}
return {
i: n,
is: false
};
}
/** Parse number at i */
function parseNumber(src, i, c) {
let n = i;
let is = false;
let value = '';
for (;;) {
const set = (0, _util.matchSet)(src, n, c, {
set: '0123456789'
});
if (!set.is) break;
({
i: n
} = set);
is = true;
value += set.value;
}
if (!is) return {
i: n,
is: false
};
const m = (0, _util.match)(src, n, c, {
phrase: '.'
});
if (m.is) {
({
i: n
} = m);
value += '.';
for (;;) {
const set = (0, _util.matchSet)(src, n, c, {
set: '0123456789'
});
if (!set.is) break;
({
i: n
} = set);
value += set.value;
}
}
let set = (0, _util.matchSet)(src, n, c, {
set: 'eE'
});
if (set.is) {
({
i: n
} = set);
value += set.value;
set = (0, _util.matchSet)(src, n, c, {
set: '+-'
});
if (set.is) {
({
i: n
} = set);
value += set.value;
}
let isE;
for (;;) {
set = (0, _util.matchSet)(src, n, c, {
set: '0123456789'
});
if (!set.is) break;
({
i: n
} = set);
isE = true;
value += set.value;
}
if (!isE) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'number',
message: 'expected digit'
});
}
const number = +value;
if (!Number.isFinite(number)) {
return (0, _util.errorGeneric)(src, n, c, {
operator: 'number',
message: `invalid number ${number}`
});
}
({
i: n
} = (0, _util.walkWhitespace)(src, n, c));
return {
i: n,
is: true,
ops: [{
op: _library.OP_NUMBER,
params: {
number
}
}]
};
}
/** Parse string at i */
async function parseString(src, i, c) {
let n = i;
let value = '';
const set = (0, _util.matchSet)(src, n, c, {
set: '"\'`'
});
if (!set.is) return {
i: n,
is: false
};
let boundary;
({
i: n,
value: boundary
} = set);
const multilineString = boundary === '`';
const interpolations = [];
for (;;) {
let m = (0, _util.match)(src, n, c, {
phrase: boundary
});
if (m.is) {
({
i: n
} = m);
break;
}
const end = (0, _util.eot)(src, n, c);
if (end.is) {
({
i: n
} = end);
return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'string',
message: 'incomplete string literal'
});
}
m = (0, _util.match)(src, n, c, {
phrase: '\\'
});
if (m.is) {
({
i: n
} = m);
m = (0, _util.matchWord)(src, n, c, {
phrase: '('
});
if (m.is) {
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opPipe(src, n, c));
m = (0, _util.match)(src, n, c, {
phrase: ')'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'string interpolation',
message: "expected ')'"
});
interpolations.push({
before: value,
pipe: ops
});
value = '';
continue;
}
if (multilineString) {
switch (src[n]) {
case '\n':
n += 1;
continue;
case '\r':
n += 1;
if (!(0, _util.eot)(src, n, c).is && src[n] === '\n') n += 1;
continue;
default:
}
}
switch (src[n]) {
case '"':
value += '"';
n += 1;
continue;
case "'":
value += "'";
n += 1;
continue;
case '`':
value += '`';
n += 1;
continue;
case '\\':
value += '\\';
n += 1;
continue;
case '/':
value += '/';
n += 1;
continue;
case 'b':
value += '\b';
n += 1;
continue;
case 'f':
value += '\f';
n += 1;
continue;
case 'n':
value += '\n';
n += 1;
continue;
case 'r':
value += '\r';
n += 1;
continue;
case 't':
value += '\t';
n += 1;
continue;
case 'u':
{
n += 1;
let hexVal = '';
for (let j = 0; j < 4; j += 1) {
m = (0, _util.hex)(src, n, c);
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'string',
message: 'incomplete unicode escape sequence: expected hex digit'
});
hexVal += m.value;
}
value += String.fromCodePoint(parseInt(hexVal, 16));
continue;
}
default:
return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'string',
message: 'invalid escape sequence'
});
}
}
if (multilineString) {
switch (src[n]) {
case '\n':
case '\r':
case '\t':
value += src[n];
n += 1;
continue;
default:
}
}
if (src.charCodeAt(n) < 0x20) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'string'
});
value += src[n];
n += 1;
}
({
i: n
} = (0, _util.walkWhitespace)(src, n, c));
if (interpolations.length === 0) return {
i: n,
is: true,
ops: [{
op: _library.OP_STRING,
params: {
string: value
}
}]
};
return {
i: n,
is: true,
ops: [{
op: _library.OP_INTERPOLATED_STRING,
params: {
interpolations,
after: value
}
}]
};
}
/** Parse pipe at i */
async function opPipe(src, i, c) {
// Call stack decoupling - This is necessary as some browsers (i.e. Safari) have very limited call stack sizes which result in stack overflow exceptions in certain situations.
await undefined;
let n = i;
const pipe = [];
for (;;) {
let ops;
({
i: n,
ops
} = await opOutputConcat(src, n, c));
pipe.push(...ops);
const m = (0, _util.matchWord)(src, n, c, {
phrase: '|',
notBeforeSet: '='
});
if (!m.is) break;
({
i: n
} = m);
}
return {
i: n,
ops: pipe
};
}
/** Parse subpipe at i */
async function opSubPipe(src, i, c) {
// Call stack decoupling - This is necessary as some browsers (i.e. Safari) have very limited call stack sizes which result in stack overflow exceptions in certain situations.
await undefined;
let n = i;
const pipe = [];
for (;;) {
let ops;
({
i: n,
ops
} = await opTry(src, n, c));
pipe.push(...ops);
const m = (0, _util.matchWord)(src, n, c, {
phrase: '|',
notBeforeSet: '='
});
if (!m.is) break;
({
i: n
} = m);
}
return {
i: n,
ops: pipe
};
}
/** Parse subroute at i */
async function opSubRoute(src, i, c) {
// Call stack decoupling - This is necessary as some browsers (i.e. Safari) have very limited call stack sizes which result in stack overflow exceptions in certain situations.
await undefined;
return opTry(src, i, c);
}
/** Parse output concat at i */
async function opOutputConcat(src, i, c) {
let n = i;
const pipes = [];
for (;;) {
let ops;
({
i: n,
ops
} = await opTry(src, n, c));
pipes.push(ops);
const m = (0, _util.matchWord)(src, n, c, {
phrase: ','
});
if (!m.is) break;
({
i: n
} = m);
}
if (pipes.length === 1) return {
i: n,
ops: pipes[0]
};
return {
i: n,
ops: [{
op: _library.OP_OUTPUT_CONCAT,
params: {
pipes
}
}]
};
}
/** Parse try at i */
async function opTry(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: 'try',
spaceAfter: true
});
if (!m.is) return opOr(src, n, c);
({
i: n
} = m);
let opsTry;
({
i: n,
ops: opsTry
} = await opOr(src, n, c));
let opsCatch;
m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'catch',
spaceAfter: true
});
if (m.is) {
({
i: n
} = m);
({
i: n,
ops: opsCatch
} = await opOr(src, n, c));
} else opsCatch = [{
op: _library.OP_VOID
}];
return {
i: n,
ops: [{
op: _library.OP_TRY,
params: {
try: opsTry,
catch: opsCatch
}
}]
};
}
/** Parse or at i */
async function opOr(src, i, c) {
let n = i;
const pipes = [];
for (;;) {
let ops;
({
i: n,
ops
} = await opAnd(src, n, c));
pipes.push(ops);
const m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'or',
spaceAfter: true
});
if (!m.is) break;
({
i: n
} = m);
}
if (pipes.length === 1) return {
i: n,
ops: pipes[0]
};
return {
i: n,
ops: [{
op: _library.OP_OR,
params: {
pipes
}
}]
};
}
/** Parse and at i */
async function opAnd(src, i, c) {
let n = i;
const pipes = [];
for (;;) {
let ops;
({
i: n,
ops
} = await opEquality(src, n, c));
pipes.push(ops);
const m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'and',
spaceAfter: true
});
if (!m.is) break;
({
i: n
} = m);
}
if (pipes.length === 1) return {
i: n,
ops: pipes[0]
};
return {
i: n,
ops: [{
op: _library.OP_AND,
params: {
pipes
}
}]
};
}
/** Parse equality at i */
async function opEquality(src, i, c) {
let n = i;
let ops;
({
i: n,
ops
} = await opComparison(src, n, c));
const comparisons = [];
for (;;) {
let m = (0, _util.matchWord)(src, n, c, {
phrase: '=='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opComparison(src, n, c));
comparisons.push({
op: _library.OPC_EQUAL,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '!='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opComparison(src, n, c));
comparisons.push({
op: _library.OPC_UNEQUAL,
params: {
by: opsBy
}
});
continue;
}
break;
}
if (comparisons.length === 0) return {
i: n,
ops
};
return {
i: n,
ops: [{
op: _library.OP_COMPARISON,
params: {
pipe: ops,
comparisons
}
}]
};
}
/** Parse comparison at i */
async function opComparison(src, i, c) {
let n = i;
let ops;
({
i: n,
ops
} = await opNot(src, n, c));
const comparisons = [];
for (;;) {
let m = (0, _util.matchWord)(src, n, c, {
phrase: '<='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNot(src, n, c));
comparisons.push({
op: _library.OPC_LESSEQUAL,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '<'
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNot(src, n, c));
comparisons.push({
op: _library.OPC_LESS,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '>='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNot(src, n, c));
comparisons.push({
op: _library.OPC_GREATEREQUAL,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '>'
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNot(src, n, c));
comparisons.push({
op: _library.OPC_GREATER,
params: {
by: opsBy
}
});
continue;
}
break;
}
if (comparisons.length === 0) return {
i: n,
ops
};
return {
i: n,
ops: [{
op: _library.OP_COMPARISON,
params: {
pipe: ops,
comparisons
}
}]
};
}
/** Parse not at i */
async function opNot(src, i, c) {
let n = i;
const m = (0, _util.matchWord)(src, n, c, {
phrase: 'not',
spaceAfter: true
});
if (!m.is) return opErrorSuppression(src, n, c);
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opErrorSuppression(src, n, c));
return {
i: n,
ops: [...ops, {
op: _library.OP_NOT
}]
};
}
/** Parse error suppression at i */
async function opErrorSuppression(src, i, c) {
let n = i;
const result = await opDifference(src, n, c);
({
i: n
} = result);
const m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (!m.is) return result;
({
i: n
} = m);
return {
i: n,
ops: [{
op: _library.OP_TRY,
params: {
try: result.ops,
catch: [{
op: _library.OP_VOID
}]
}
}]
};
}
/** Parse difference at i */
async function opDifference(src, i, c) {
let n = i;
let ops;
({
i: n,
ops
} = await opMultiplication(src, n, c));
const operations = [];
for (;;) {
let m = (0, _util.matchWord)(src, n, c, {
phrase: '+',
notBeforeSet: '='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opMultiplication(src, n, c));
operations.push({
op: _library.OPM_ADDITION,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '-',
notBeforeSet: '=>'
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opMultiplication(src, n, c));
operations.push({
op: _library.OPM_SUBTRACTION,
params: {
by: opsBy
}
});
continue;
}
break;
}
if (operations.length === 0) return {
i: n,
ops
};
return {
i: n,
ops: [{
op: _library.OP_CALCULATION,
params: {
pipe: ops,
operations
}
}]
};
}
/** Parse multiplication at i */
async function opMultiplication(src, i, c) {
let n = i;
let ops;
({
i: n,
ops
} = await opNullCoalescence(src, n, c));
const operations = [];
for (;;) {
let m = (0, _util.matchWord)(src, n, c, {
phrase: '*',
notBeforeSet: '='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNullCoalescence(src, n, c));
operations.push({
op: _library.OPM_MULTIPLICATION,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '/',
notBeforeSet: '='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNullCoalescence(src, n, c));
operations.push({
op: _library.OPM_DIVISION,
params: {
by: opsBy
}
});
continue;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: '%',
notBeforeSet: '='
});
if (m.is) {
({
i: n
} = m);
let opsBy;
({
i: n,
ops: opsBy
} = await opNullCoalescence(src, n, c));
operations.push({
op: _library.OPM_REMAINDER,
params: {
by: opsBy
}
});
continue;
}
break;
}
if (operations.length === 0) return {
i: n,
ops
};
return {
i: n,
ops: [{
op: _library.OP_CALCULATION,
params: {
pipe: ops,
operations
}
}]
};
}
/** Parse null coalescence at i */
async function opNullCoalescence(src, i, c) {
let n = i;
const pipes = [];
for (;;) {
let ops;
({
i: n,
ops
} = await opNegation(src, n, c));
pipes.push(ops);
const m = (0, _util.matchWord)(src, n, c, {
phrase: '??'
});
if (!m.is) break;
({
i: n
} = m);
}
if (pipes.length === 1) return {
i: n,
ops: pipes[0]
};
return {
i: n,
ops: [{
op: _library.OP_NULL_COALESCENCE,
params: {
pipes
}
}]
};
}
/** Parse negation at i */
async function opNegation(src, i, c) {
let n = i;
const m = (0, _util.matchWord)(src, n, c, {
phrase: '-',
notBeforeSet: '=>'
});
if (!m.is) return opIf(src, n, c);
({
i: n
} = m);
let ops;
({
i: n,
ops
} = await opIf(src, n, c));
return {
i: n,
ops: [...ops, {
op: _library.OP_NEGATION
}]
};
}
/** Parse if at i */
async function opIf(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: 'if',
spaceAfter: true
});
if (!m.is) return opConstant(src, n, c);
({
i: n
} = m);
const ifs = [];
for (;;) {
let opsIf;
({
i: n,
ops: opsIf
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'then',
spaceAfter: true
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'if statement',
message: "expected 'then'"
});
let opsThen;
({
i: n,
ops: opsThen
} = await opPipe(src, n, c));
ifs.push({
if: opsIf,
then: opsThen
});
m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'elif',
spaceAfter: true
});
if (!m.is) break;
({
i: n
} = m);
}
let opsElse;
m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'else',
spaceAfter: true
});
if (m.is) {
({
i: n
} = m);
({
i: n,
ops: opsElse
} = await opPipe(src, n, c));
} else opsElse = [];
m = (0, _util.matchWord)(src, n, c, {
spaceBefore: true,
phrase: 'end'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'if statement',
message: "expected 'end'"
});
return {
i: n,
ops: [{
op: _library.OP_IF,
params: {
ifs,
else: opsElse
}
}]
};
}
/** Parse constant at i */
function opConstant(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: 'true',
spaceAfter: true
});
if (m.is) {
({
i: n
} = m);
return {
i: n,
ops: [{
op: _library.OP_CONSTANT_TRUE
}]
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: 'false',
spaceAfter: true
});
if (m.is) {
({
i: n
} = m);
return {
i: n,
ops: [{
op: _library.OP_CONSTANT_FALSE
}]
};
}
m = (0, _util.matchWord)(src, n, c, {
phrase: 'null',
spaceAfter: true
});
if (m.is) {
({
i: n
} = m);
return {
i: n,
ops: [{
op: _library.OP_CONSTANT_NULL
}]
};
}
return opNumber(src, n, c);
}
/** Parse number at i */
async function opNumber(src, i, c) {
let n = i;
const result = await parseNumber(src, n, c);
if (!result.is) return opNamedFunctionDefinition(src, n, c);
({
i: n
} = result);
return {
i: n,
ops: result.ops
};
}
/** Parse named function definition at i */
async function opNamedFunctionDefinition(src, i, c) {
let n = i;
const m = (0, _util.matchWord)(src, n, c, {
phrase: 'func',
spaceAfter: true
});
if (!m.is) return opFunctionDefinition(src, n, c);
({
i: n
} = m);
const v = (0, _util.safeVariable)(src, n, c);
if (!v.is) return opFunctionDefinition(src, i, c);
let name;
({
i: n,
value: name
} = v);
let argNames;
({
i: n,
argNames
} = await parseFunctionHeader(src, n, c));
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
ops: [{
op: _library.OP_VARIABLE_DEFINITION,
params: {
name,
pipe: [{
op: _library.OP_FUNCTION_DEFINITION,
params: {
argNames,
pipe: ops
}
}]
}
}]
};
}
/** Parse function definition at i */
async function opFunctionDefinition(src, i, c) {
let n = i;
const m = (0, _util.matchWord)(src, n, c, {
phrase: 'func',
spaceAfter: true
});
if (!m.is) return opVariableAccess(src, n, c);
({
i: n
} = m);
let argNames;
({
i: n,
argNames
} = await parseFunctionHeader(src, n, c));
let ops;
({
i: n,
ops
} = await opSubRoute(src, n, c));
return {
i: n,
ops: [{
op: _library.OP_FUNCTION_DEFINITION,
params: {
argNames,
pipe: ops
}
}]
};
}
/** Parse variable definition at i */
async function opVariableAccess(src, i, c) {
let n = i;
const v = (0, _util.safeVariable)(src, n, c);
if (!v.is) return opValueAccess(src, n, c);
let name;
({
i: n,
value: name
} = v);
let selectors;
let canAssign;
const ac = await parseAccess(src, n, c);
if (ac.is) ({
i: n,
selectors,
canAssign
} = ac);else {
selectors = [];
canAssign = true;
}
if (!canAssign) {
const ops = [{
op: _library.OP_VARIABLE,
params: {
name
}
}];
if (selectors.length === 0) return {
i: n,
ops
};
return {
i: n,
ops: [{
op: _library.OP_ACCESS,
params: {
pipe: ops,
selectors
}
}]
};
}
const as = await parseAssignment(src, n, c);
if (!as.is) {
const ops = [{
op: _library.OP_VARIABLE,
params: {
name
}
}];
if (selectors.length === 0) return {
i: n,
ops
};
return {
i: n,
ops: [{
op: _library.OP_ACCESS,
params: {
pipe: ops,
selectors
}
}]
};
}
let opAssignment;
({
i: n,
assignment: opAssignment
} = as);
if (selectors.length === 0 && opAssignment.op === _library.OPU_SET) {
return {
i: n,
ops: [{
op: _library.OP_VARIABLE_DEFINITION,
params: {
name,
pipe: opAssignment.params.pipe
}
}]
};
}
return {
i: n,
ops: [{
op: _library.OP_VARIABLE_DEFINITION,
params: {
name,
pipe: [{
op: _library.OP_ASSIGNMENT,
params: {
pipe: [{
op: _library.OP_VARIABLE,
params: {
name
}
}],
selectors,
assignment: opAssignment
}
}]
}
}]
};
}
/** Parse variable access at i */
async function opValueAccess(src, i, c) {
let n = i;
const selectors = [];
let ops;
let m = (0, _util.matchWord)(src, n, c, {
phrase: '.'
});
if (!m.is) ({
i: n,
ops
} = await opObjectConstructor(src, n, c));else {
({
i: n
} = m);
ops = [];
const v = (0, _util.safeVariable)(src, n, c);
if (v.is) {
let name;
({
i: n,
value: name
} = v);
let optional;
m = (0, _util.matchWord)(src, n, c, {
phrase: '?',
notBeforeSet: '?='
});
if (m.is) ({
i: n,
is: optional
} = m);
selectors.push({
op: _library.OPA_FIELD,
params: {
pipe: [{
op: _library.OP_STRING,
params: {
string: name
}
}],
optional
}
});
}
}
const ac = await parseAccess(src, n, c, {
identity: ops.length === 0 && selectors.length === 0
});
let canAssign;
if (ac.is) {
({
i: n,
canAssign
} = ac);
selectors.push(...ac.selectors);
} else canAssign = selectors.length > 0;
if (selectors.length === 0) return {
i: n,
ops
};
if (!canAssign) return {
i: n,
ops: [{
op: _library.OP_ACCESS,
params: {
pipe: ops,
selectors
}
}]
};
const as = await parseAssignment(src, n, c);
if (!as.is) return {
i: n,
ops: [{
op: _library.OP_ACCESS,
params: {
pipe: ops,
selectors
}
}]
};
let opAssignment;
({
i: n,
assignment: opAssignment
} = as);
return {
i: n,
ops: [{
op: _library.OP_ASSIGNMENT,
params: {
pipe: ops,
selectors,
assignment: opAssignment
}
}]
};
}
/** Parse object constructor at i */
async function opObjectConstructor(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: '{'
});
if (!m.is) return opArrayConstructor(src, n, c);
({
i: n
} = m);
const fields = [];
m = (0, _util.matchWord)(src, n, c, {
phrase: '}'
});
if (m.is) ({
i: n
} = m);else for (;;) {
m = (0, _util.matchWord)(src, n, c, {
phrase: '('
});
if (m.is) {
({
i: n
} = m);
let opsKey;
({
i: n,
ops: opsKey
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
phrase: ')'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: "expected ')'"
});
let optional;
({
i: n,
is: optional
} = (0, _util.matchWord)(src, n, c, {
phrase: '?'
}));
m = (0, _util.matchWord)(src, n, c, {
phrase: ':'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: "expected ':'"
});
let opsValue;
({
i: n,
ops: opsValue
} = await opSubPipe(src, n, c));
fields.push({
key: opsKey,
value: opsValue,
optional
});
m = (0, _util.matchWord)(src, n, c, {
phrase: '}'
});
if (m.is) {
({
i: n
} = m);
break;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ','
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: "expected ',' or '}'"
});
continue;
}
const s = await parseString(src, n, c);
if (s.is) {
let opsKey;
({
i: n,
ops: opsKey
} = s);
m = (0, _util.matchWord)(src, n, c, {
phrase: ':'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: "expected ':'"
});
let opsValue;
({
i: n,
ops: opsValue
} = await opSubPipe(src, n, c));
fields.push({
key: opsKey,
value: opsValue,
optional: false
});
m = (0, _util.matchWord)(src, n, c, {
phrase: '}'
});
if (m.is) {
({
i: n
} = m);
break;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ','
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: "expected ',' or '}'"
});
continue;
}
const v = (0, _util.safeVariable)(src, n, c);
if (v.is) {
let name;
({
i: n,
value: name
} = v);
let opsValue;
m = (0, _util.matchWord)(src, n, c, {
phrase: ':'
});
if (m.is) {
({
i: n
} = m);
({
i: n,
ops: opsValue
} = await opSubPipe(src, n, c));
} else {
let optional;
({
i: n,
is: optional
} = (0, _util.matchWord)(src, n, c, {
phrase: '?'
}));
opsValue = optional ? [{
op: _library.OP_TRY,
params: {
try: [{
op: _library.OP_VARIABLE,
params: {
name
}
}],
catch: [{
op: _library.OP_VOID
}]
}
}] : [{
op: _library.OP_VARIABLE,
params: {
name
}
}];
}
fields.push({
key: [{
op: _library.OP_STRING,
params: {
string: name
}
}],
value: opsValue,
optional: false
});
m = (0, _util.matchWord)(src, n, c, {
phrase: '}'
});
if (m.is) {
({
i: n
} = m);
break;
}
m = (0, _util.matchWord)(src, n, c, {
phrase: ','
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: "expected ',' or '}'"
});
continue;
}
return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'object',
message: 'expected field declaration'
});
}
return {
i: n,
ops: [{
op: _library.OP_OBJECT_CONSTRUCTOR,
params: {
fields
}
}]
};
}
/** Parse array constructor at i */
async function opArrayConstructor(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: '['
});
({
i: n
} = m);
if (!m.is) return opStringLiteral(src, n, c);
let ops;
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
if (m.is) {
({
i: n
} = m);
ops = [{
op: _library.OP_VOID
}];
} else {
({
i: n,
ops
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
phrase: ']'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'array',
message: "expected ']'"
});
}
return {
i: n,
ops: [{
op: _library.OP_ARRAY_CONSTRUCTOR,
params: {
pipe: ops
}
}]
};
}
/** Parse string literal at i */
async function opStringLiteral(src, i, c) {
let n = i;
const s = await parseString(src, n, c);
if (!s.is) return opGroup(src, n, c);
({
i: n
} = s);
return {
i: n,
ops: s.ops
};
}
/** Parse group at i */
async function opGroup(src, i, c) {
let n = i;
let m = (0, _util.matchWord)(src, n, c, {
phrase: '('
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c);
let ops;
({
i: n,
ops
} = await opPipe(src, n, c));
m = (0, _util.matchWord)(src, n, c, {
phrase: ')'
});
({
i: n
} = m);
if (!m.is) return (0, _util.errorUnexpectedToken)(src, n, c, {
operator: 'group',
message: "expected ')'"
});
return {
i: n,
ops
};
}